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
You are viewing a single thread.
View all comments 1 point
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.