Day 11: Plutonian Pebbles
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Kotlin
Gone mathematical.
Also overflowing indices screwed with me a bit.
Here's the code:
import kotlin.math.floor import kotlin.math.log import kotlin.math.pow import kotlin.time.DurationUnit fun main() { fun part1(input: List<String>): Long = Day11Solver(input).solve(25) fun part2(input: List<String>): Long = Day11Solver(input).solve(75) val testInput = readInput("Day11_test") check(part1(testInput) == 55312L) //check(part2(testInput) == 0L) No test output available. val input = readInput("Day11") part1(input).println() part2(input).println() timeTrials("Part 1", unit = DurationUnit.MICROSECONDS) { part1(input) } timeTrials("Part 2", repetitions = 1000) { part2(input) } } class Day11Solver(input: List<String>) { private val parsedInput = input[0].split(' ').map { it.toLong() } /* * i ∈ ℕ₀ ∪ {-1}, φᵢ: ℕ₀ → ℕ shall be the function mapping the amount of stones generated to the amount of steps * taken with a stone of starting number i. * * Furthermore, ѱ: ℕ₀ → ℕ₀ ⨯ (ℕ₀ ∪ {-1}) shall be the function mapping an index to two new indices after a step. * * ⎧ (1, -1) if i = 0 * ѱ(i) := ⎨ (a, b) if ⌊lg(i)⌋ + 1 ∈ 2 ℕ with a := i/(10^((⌊lg(i)⌋ + 1) / 2)), b := i - 10^((⌊lg(i)⌋ + 1) / 2) * a * ⎩ (2024 i, -1) otherwise * * ⎧ 0 if i = -1 * φᵢ(n) := ⎨ 1 if n = 0 * ⎩ φₖ(n - 1) + φₗ(n - 1) otherwise with (k, l) := ѱ(i) * * With that φᵢ(n) is a sum with n up to 2ⁿ summands, that are either 0 or 1. */ private val cacheIndices = mutableMapOf<Long, Pair<Long, Long>>() // Cache the next indices for going from φᵢ(n) to φₖ(n - 1) + φₗ(n - 1). private val cacheValues = mutableMapOf<Pair<Long, Int>, Long>() // Also cache already calculated φᵢ(n) fun calculatePsi(i: Long): Pair<Long, Long> = cacheIndices.getOrPut(i) { if(i == -1L) throw IllegalArgumentException("Advancement made: How did we get here?") else if (i == 0L) 1L to -1L else { val amountOfDigits = (floor(log(i.toDouble(), 10.0)) + 1) if (amountOfDigits.toLong() % 2 == 0L) { // Split digits at the midpoint. val a = floor(i / 10.0.pow(amountOfDigits / 2)) val b = i - a * 10.0.pow(amountOfDigits / 2) a.toLong() to b.toLong() } else { 2024 * i to -1L } } } fun calculatePhi(i: Long, n: Int): Long = cacheValues.getOrPut(i to n) { if (i == -1L) 0L else if (n == 0) 1L else { val (k, l) = calculatePsi(i) calculatePhi(k, n - 1) + calculatePhi(l, n - 1) } } fun solve(steps: Int): Long = parsedInput.sumOf { val debug = calculatePhi(it, steps) debug } }
Try it out here.
And this is the full repo.