Advent of Code 2017 - Day 2, in Kotlin
Kotlin solutions to parts 1 and 2 of Advent of Code 2017, Day 2: 'Corruption Checksum'
Here we are on day two of Advent of Code 2017 . I’ve challenged myself to post each day’s solution to Github and blog about it. Like last year, I’m going to be solving these problems in Kotlin. I might go back and revise solutions, but I’ll be sure to annotate that fact in these posts.
Problem Input
We are given a set of input
for this problem consisting of 16 rows of 16 numbers. I’ll spare you the code to parse it, but I’ve reduced this down to a List<List<Int>>
called input
that each of my solutions will depend on.
⭐ Day 2, Part 1
For our first problem, we are given several rows consisting of integers, and we’re asked to perform a checksum on them.
The puzzle text can be found here.
Well this seems fun, and more importantly, doesn’t look like it has any crazy hidden edge cases. If I could guarantee the order of the rows, it would be a simple matter of taking the first and last elements. Since there isn’t that much input, I’ll just sort the rows.
fun solvePart1(): Int =
input
.map { it.sorted() }
.sumBy { it.last() - it.first() }
This shows off a function in Kotlin that I almost always forget about: sumBy
. It takes a function and returns the sum of function outputs given your elements as inputs. In our case, the input is just a sorted List<Int>
and by taking the last element (the largest) and subtracting the first element (the smallest), we meet the requirements and pass the tests. Yay! We’ve earned ourselves a star.
⭐ Day 2, Part 2
The puzzle text can be found here.
Hmmmm. OK. This is one of those situations where I’m going to take advantage of the fact that this is not production code and my inputs are small. I’m also taking advantage of the fact that each row (at least in my input), has unique numbers. This means if I make a Pair
of each element in a row with every other element, filter out the elements that are paired with themselves, and filter out the ones that aren’t evenly divisible, I should have what I’m looking for.
More work than is strictly necessary? Sure. But again, this is a toy problem and I’m optimizing for clarity over speed.
fun solvePart2(): Int =
input
.map { findDivisiblePairForRow(it) }
.sumBy { it.first / it.second }
private fun findDivisiblePairForRow(row: List<Int>): Pair<Int, Int> =
row
.flatMap { x -> row.map { Pair(x, it) } }
.filter { it.first != it.second }
.first { it.first % it.second == 0 }
I feel that’s straight forward. For each row, find the one and only one pair of numbers that are divisible, and then using our friend sumBy
(we’re on a first name basis now), divide the first
and second
elements in the Pair
. The best part, our tests pass and we’ve earned another star.
Originally I had a different solution to part 2 that was recursive. It probably did less work than the solution above, but it was far messier and I didn’t feel good about it. Normally, I enjoy a nice recursive solution because they are so clear and can be efficient. But not this time.
At the end of day 2, we’ve earned 4 stars with 46 left to go! Huzzah!
Further Reading
- Index of All Solutions - All solutions for 2017, in Kotlin.
- My Github repo - Solutions and tests for each day.
- Solution - Full code for day 2
- Advent of Code - Come join in and do these challenges yourself!
- Music to Code By - Two hours of The Blue Danube Waltz (I code to this often).