By Eric Burden | December 9, 2023
It’s that time of year again! Just like last year, I’ll be posting my solutions to the Advent of Code puzzles. This year, I’ll be solving the puzzles in Kotlin. I’ll post my solutions and code to GitHub as well. If you haven’t given AoC a try, I encourage you to do so along with me!
Day 9 - Mirage Maintenance
Find the problem description HERE.
The Input - Read the Room
Today’s puzzle has us reading off lists of numbers from some fancy gadget we just happen to have in our pocket for checking environmental readings of oases. Sounds complicated, but it’s really lines of space-separated numbers. This, we can handle.
class Day09(input: List<String>) {
// List of space-separated strings to list of lists of numbers,
// coming up!
private val parsed = input.map { line -> line.split(" ").map { it.toInt() }}
}
That’s it? Yeah, that’s going to be today’s theme, didn’t you hear?
Part One - Getting to the Bottom of Things
Looks like we’ve finally had a chance to rest, relax, and prepare for the next exciting leg of this journey. Good. We needed a bit of a break. Speaking of getting a break, part one of today’s puzzle has us reading in a series of numbers, finding the next number in series, then adding up all the ’next numbers’. It’s some environmental stuff, so I hear. Thankfully, it’s a straightforward recursive solution.
/**
* Return the next number in the sequence.
*
* This is likely a very brittle approach (meaning the possibility of
* recursing too deeply for generic lists of numbers), but for these
* specially crafted sensor readings, it works just fine. This function
* recursively generates the list of differences and adds the next
* forecasted value from that list to the last value of the current list.
*
* @return The next forecasted value for this sequence of readings.
*/
fun List<Int>.nextSequenceValue(): Int {
// Base case. No need to go to all zeros, oncw the sequence contains
// all values the same, we know what the next value will be.
if (this.all { it == this[0] }) return this[0]
// Get the differences between each pair of values in `sequence`.
val derivedSequence = this.windowed(2) { (left, right) -> right - left }
return this.last() + derivedSequence.nextSequenceValue()
}
class Day09(input: List<String>) {
// private val parsed = ...
// In part one, we sum the next number in sequence for each list.
fun solvePart1(): Int = parsed.sumOf { it.nextSequenceValue() }
}
Why, yes, there is more comment than code here. How very astute of you to notice!
Part Two - Where Do You Come From, Where Do You Go?
Well, yes, I suppose it would be handy to know what the previous sensor value for each of these readings is. Granted, I dont’ know what each of these readings represents, so the value may be a bit limited, but more data is always better, right? I sure hope so!
// fun List<Int>.nextSequenceValue(): Int { ... }
class Day09(input: List<String>) {
// private val parsed = ...
// fun solvePart1(): Int = ...
// In part two, we extrapolate each list _backwards_ by one, then sum
// those results.
fun solvePart2(): Int = parsed.sumOf { it.reversed().nextSequenceValue() }
}
I think I’m going to go back to bed today!
Wrap Up
It feels like today’s puzzle was a bit of a break after yesterday’s, although truth be told yesterday’s puzzles wasn’t that bad if you recalled the fondness of Advent of Code for problems with cyclical values. None of that today, though. Just do what the puzzle text says, earn stars, and move on. I wonder if this day was here to remind us all that directions and puzzles are two different things, and that one of those things is more fun than the other… Either way, I think I’ll enjoy having the free time back today and spend it on something productive and festive. Happy Holidays!