Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
build-docker:
docker build -f distribution/docker/Dockerfile --build-arg JAR_FILE=build/libs/\*.jar -t lindar/bingoticketgenerator-apalfi:0.0.1-SNAPSHOT .

build-gradle:
./gradlew clean build

build: build-gradle build-docker

run-docker:
docker run -p 8080:8080 lindar/bingoticketgenerator-apalfi:0.0.1-SNAPSHOT

boot-run:
./gradlew bootRun

run-tests:
./gradlew test --tests "com.attilapalfi.lindar.bingoticketgenerator.ticketgenerator*"

run-perf-tests:
./gradlew test --tests 'com.attilapalfi.lindar.bingoticketgenerator.performancetest*'
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,56 @@

## System Requirements
- Java 17, gradle
- Docker

## Build & Run
Use the Makefile to execute build & run commands.

To build with gradle and docker:
```shell
make build
```

To run the docker container:
```shell
make run-docker
```
If the container started, the ticket generator endpoint is available at:

### [http://localhost:8080/bingo/newStrips](http://localhost:8080/bingo/newStrips)

To run tests or performance tests:
```shell
make run-tests
make run-perf-tests
```

## Implementation Details
- `-1` means `Blank` space in the ticket
- the core part of the algorithm is in `AbstractTicketGenerator`
- it iterates through the spaces of the tickets row by row and based on a set of rules it places the blanks and numbers
- time complexity of the algorithm is `O(n)` with some amortized time, where `n` is the total number of spaces in the 6 tickets
- the algorithm is hard to scale though. it was specifically implemented to generate 3x9 tickets in batches of 6
- array lists are initialized in the `ArrayBasedTicketGenerator` to keep track of the state of the ticket generator
- these array lists are maybe not optimal: removing an element has `O(n)` time complexity
- it is possible to create another subclass for `AbstractTicketGenerator` which uses another approach
- e.g. instead of array lists, shuffled linked lists. removing from LL: `O(1)`, shuffling during init: `O(nlogn)`
- altough these are very small array lists: `n` is usually smaller than 20
- an error checking is part of the algorithm, because in very rare cases an invalid ticket is generated.
As soon as it's detected, the algorithm drops it and starts creating a new one.
- luckily this does not have a performance impact because it's so rare

## Performance
On my machine the performance test executed with these results:

`Generated 10.000 strips in 487 ms.`

And with 16 threads:

`Generated 100.000 strips in parallel in 1602 ms.`

------
Original content:
# Ticket Generator Challenge

A small challenge that involves building a [Bingo 90](https://en.wikipedia.org/wiki/Bingo_(United_Kingdom)) ticket generator.
Expand All @@ -19,3 +72,4 @@ A small challenge that involves building a [Bingo 90](https://en.wikipedia.org/w

Try to also think about the performance aspects of your solution. How long does it take to generate 10k strips?
The recommended time is less than 1s (with a lightweight random implementation)

35 changes: 35 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("org.springframework.boot") version "2.7.1"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.6.21"
kotlin("plugin.spring") version "1.6.21"
}

group = "com.attilapalfi.lindar"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

repositories {
mavenCentral()
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}

tasks.withType<Test> {
useJUnitPlatform()
}
4 changes: 4 additions & 0 deletions distribution/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading