diff --git a/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22.kt b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22.kt new file mode 100644 index 00000000..432f5ca4 --- /dev/null +++ b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22.kt @@ -0,0 +1,70 @@ +package me.peckb.aoc._2024.calendar.day22 + +import arrow.core.Tuple4 +import javax.inject.Inject +import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory + +class Day22 @Inject constructor( + private val generatorFactory: InputGeneratorFactory, +) { + fun partOne(filename: String) = generatorFactory.forFile(filename).readAs(::secretNumber) { input -> + input.sumOf { number -> + (0 until 2000).fold(number) { n, _ -> nextNumber(n) } + } + } + + fun partTwo(filename: String) = generatorFactory.forFile(filename).readAs(::secretNumber) { input -> + val data = input.toList() + + val solutions = mutableMapOf, Long>() + + data.forEach { number-> + val buyerNumbers = sequence { + var n = number + while (true) { + yield(n) + n = nextNumber(n) + } + } + + val mySequences = mutableSetOf>() + + buyerNumbers + .map { it % 10 } + .windowed(5) + .take(2000) + .forEach { (a, b, c, d, e) -> + val k = Tuple4(b - a, c - b, d - c, e - d) + if (k !in mySequences) { + solutions.merge(k, e, Long::plus) + mySequences.add(k) + } + } + } + + solutions.values.max() + } + + private fun nextNumber(number: Long): Long { + var n = number + + // step one + val a = n * 64 // Calculate the result of multiplying the secret number by 64. + n = n xor a // Then, mix this result into the secret number. + n %= 16_777_216 // Finally, prune the secret number. + + // step two + val b = n / 32 // Calculate the result of dividing the secret number by 32. + n = n xor b // Then, mix this result into the secret number. + n %= 16_777_216 // Finally, prune the secret number. + + // step three + val c = n * 2048 // Calculate the result of multiplying the secret number by 2048. + n = n xor c // Then, mix this result into the secret number. + n %= 16_777_216 // Finally, prune the secret number. + + return n + } + + private fun secretNumber(line: String) = line.toLong() +} diff --git a/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/README.md b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/README.md new file mode 100644 index 00000000..f7223294 --- /dev/null +++ b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day22/README.md @@ -0,0 +1 @@ +## [Day 22: Monkey Market](https://adventofcode.com/2024/day/22) \ No newline at end of file diff --git a/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt b/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt index e9a907ea..e3e16447 100644 --- a/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt +++ b/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt @@ -21,6 +21,7 @@ import me.peckb.aoc._2024.calendar.day18.Day18Test import me.peckb.aoc._2024.calendar.day19.Day19Test import me.peckb.aoc._2024.calendar.day20.Day20Test import me.peckb.aoc._2024.calendar.day21.Day21Test +import me.peckb.aoc._2024.calendar.day22.Day22Test import javax.inject.Singleton import me.peckb.aoc.DayComponent import me.peckb.aoc.InputModule @@ -50,4 +51,5 @@ internal interface TestDayComponent : DayComponent { fun inject(day19Test: Day19Test) fun inject(day20Test: Day20Test) fun inject(day21Test: Day21Test) + fun inject(day22Test: Day22Test) } diff --git a/src/test/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22Test.kt b/src/test/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22Test.kt new file mode 100644 index 00000000..58df32ef --- /dev/null +++ b/src/test/kotlin/me/peckb/aoc/_2024/calendar/day22/Day22Test.kt @@ -0,0 +1,32 @@ +package me.peckb.aoc._2024.calendar.day22 + +import javax.inject.Inject + +import me.peckb.aoc._2024.DaggerTestDayComponent +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class Day22Test { + @Inject + lateinit var day22: Day22 + + @BeforeEach + fun setup() { + DaggerTestDayComponent.create().inject(this) + } + + @Test + fun testDay22PartOne() { + assertEquals(16039090236, day22.partOne(DAY_22)) + } + + @Test + fun testDay22PartTwo() { + assertEquals(1808, day22.partTwo(DAY_22)) + } + + companion object { + private const val DAY_22: String = "advent-of-code-input/2024/day22.input" + } +}