Skip to content

Commit b60d24d

Browse files
committed
Solution 2017-15 (Dueling Generators)
1 parent 2102015 commit b60d24d

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package de.ronny_h.aoc.year2017.day15
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
5+
fun main() = DuelingGenerators().run(594, 328)
6+
7+
class DuelingGenerators : AdventOfCode<Int>(2017, 15) {
8+
override fun part1(input: List<String>): Int = judge(
9+
Generator(seed(input, 'A', 0), 16807),
10+
Generator(seed(input, 'B', 1), 48271),
11+
)
12+
13+
override fun part2(input: List<String>): Int = judge(
14+
Generator(seed(input, 'A', 0), 16807, 4),
15+
Generator(seed(input, 'B', 1), 48271, 8),
16+
5_000_000,
17+
)
18+
19+
private fun seed(input: List<String>, generator: Char, index: Int): Long = input[index]
20+
.substringAfter("Generator $generator starts with ").toLong()
21+
22+
private fun judge(
23+
generatorA: Generator,
24+
generatorB: Generator,
25+
iterations: Int = 40_000_000,
26+
): Int {
27+
val bitmask = "00000000000000001111111111111111".toLong(2)
28+
29+
var equalLowestBitsCount = 0
30+
repeat(iterations) {
31+
val lowestABits = generatorA.next() and bitmask
32+
val lowestBBits = generatorB.next() and bitmask
33+
if (lowestABits == lowestBBits) {
34+
equalLowestBitsCount++
35+
}
36+
}
37+
return equalLowestBitsCount
38+
}
39+
}
40+
41+
class Generator(seed: Long, private val factor: Int, private val provideOnlyMultiplesOf: Int = 1) {
42+
private var value = seed
43+
private val divider = 2147483647
44+
45+
fun next(): Long {
46+
do {
47+
value = (value * factor) % divider
48+
} while (value % provideOnlyMultiplesOf != 0L)
49+
return value
50+
}
51+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package de.ronny_h.aoc.year2017.day15
2+
3+
import io.kotest.core.spec.style.StringSpec
4+
import io.kotest.data.forAll
5+
import io.kotest.data.row
6+
import io.kotest.matchers.shouldBe
7+
8+
class DuelingGeneratorsTest : StringSpec({
9+
10+
"generators A and B" {
11+
val generatorA = Generator(65, 16807)
12+
val generatorB = Generator(8921, 48271)
13+
forAll(
14+
row(1092455, 430625591),
15+
row(1181022009, 1233683848),
16+
row(245556042, 1431495498),
17+
row(1744312007, 137874439),
18+
row(1352636452, 285222916),
19+
) { a, b ->
20+
generatorA.next() shouldBe a
21+
generatorB.next() shouldBe b
22+
}
23+
}
24+
25+
"part 1: The number of equal lowest 16 bit values in a sample of 40 million pairs" {
26+
val input = listOf(
27+
"Generator A starts with 65",
28+
"Generator B starts with 8921",
29+
)
30+
DuelingGenerators().part1(input) shouldBe 588
31+
}
32+
33+
"generators A and B only providing multiples" {
34+
val generatorA = Generator(65, 16807, 4)
35+
val generatorB = Generator(8921, 48271, 8)
36+
forAll(
37+
row(1352636452, 1233683848),
38+
row(1992081072, 862516352),
39+
row(530830436, 1159784568),
40+
row(1980017072, 1616057672),
41+
row(740335192, 412269392),
42+
) { a, b ->
43+
generatorA.next() shouldBe a
44+
generatorB.next() shouldBe b
45+
}
46+
}
47+
48+
"part 2: The number of equal lowest 16 bit values generated by modified generators in a sample of 5 million pairs" {
49+
val input = listOf(
50+
"Generator A starts with 65",
51+
"Generator B starts with 8921",
52+
)
53+
DuelingGenerators().part2(input) shouldBe 309
54+
}
55+
})

0 commit comments

Comments
 (0)