Skip to Content

Advent of Code 2017 - Day 2, in Kotlin

Kotlin solutions to parts 1 and 2 of Advent of Code 2017, Day 2: 'Corruption Checksum'

Posted on

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.

For each row, determine the difference between the largest value and the smallest value; the checksum is the sum of all of these differences.

For example, given the following spreadsheet:

 5 1 9 5
 7 5 3
 2 4 6 8
  • The first row’s largest and smallest values are 9 and 1, and their difference is 8.
  • The second row’s largest and smallest values are 7 and 3, and their difference is 4.
  • The third row’s difference is 6.
  • In this example, the spreadsheet’s checksum would be 8 + 4 + 6 = 18.

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

Onward!

It sounds like the goal is to find the only two numbers in each row where one evenly divides the other - that is, where the result of the division operation is a whole number. They would like you to find those numbers on each line, divide them, and add up each line’s result.

For example, given the following spreadsheet:

5 9 2 8
9 4 7 3
3 8 6 5
  • In the first row, the only two numbers that evenly divide are 8 and 2; the result of this division is 4.
  • In the second row, the two numbers are 9 and 3; the result is 3.
  • In the third row, the result is 2.
  • In this example, the sum of the results would be 4 + 3 + 2 = 9.

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

  1. Index of All Solutions - All solutions for 2017, in Kotlin.
  2. My Github repo - Solutions and tests for each day.
  3. Solution - Full code for day 2
  4. Advent of Code - Come join in and do these challenges yourself!
  5. Music to Code By - Two hours of The Blue Danube Waltz (I code to this often).