Advent of Code 2017 - Day 1, in Kotlin
Kotlin solutions to parts 1 and 2 of Advent of Code 2017, Day 1: 'Inverse Captcha'
WOO HOO! Advent of Code 2017 is finally here and I’m so excited! I’ve been looking forward to this for months, and 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. To quote They Might Be Giants" “This could lead to excellence, or serious injury. Only one way to know, go, go go!"
The Advent of Code has two problems each day, the second unlocking after the first is solved. The second part typically relates to the first and changes an assumption. The reward for solving a problem is a star, and your ultimate goal is to collect 50 stars. There’s a funny story that goes along with each day, but I won’t recap those here. :)
⭐ Day 1, Part 1
The puzzle text can be found here.
This struck me as a textbook use for zipWithNext
, a new function in Kotlin 1.2
. Essentially, it creates pairs of elements from a stream. This is exactly what we need!
fun solvePart1(input: String): Int =
(input + input[0]) // Circular list, re-add [0] to the end so they pair up.
.zipWithNext()
.filter { it.first == it.second }
.map { it.first.asDigit() }
.sum()
The only tricky part here is adding input[0]
to the end of the input string. I do this because the requirements treat the input as a circular list, so rather than do a clunky comparison, I’ll just add it to the end and let zipWithNext
take care of it for me. Once zipWithNext
pairs everything up, it’s a simple matter of throwing out the pairs the don’t match and summing one of the digits in the pair.
I also defined an extension on Char
to convert it to an integer. I have a feeling this might exist, but I couldn’t find it after tens of seconds of Googling.
fun Char.asDigit(): Int = if(this.isDigit()) this-'0' else throw IllegalArgumentException()
⭐ Day 1, Part 2
The puzzle text can be found here.
Well, the good news is that we only have to evaluate half of the input. If a character at position A matches its pair half way around the list at position B, position B will match A as well. So let’s do less work.
fun solvePart2(input: String): Int {
val half = input.length / 2
return input
.subSequence(0, half)
.filterIndexed { i, c -> c == input[i + half] }
.map { it.asDigit() * 2 }
.sum()
}
}
Again, pretty straight forward. I feel kind of bad that I didn’t write this as a single expression (always my mental goal with Kotlin, if I can). I just felt that calculating half
and passing it into another function, or constantly recalculating it, or using apply
was overkill. At any rate, we get half of the input string, go through each character, comparing it to it’s pair half way around the circle. The trick here is to double our answer, because again, A == B == A.
And for all that work, we earn two stars, on our way to 50! Yay!
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 1
- Advent of Code - Come join in and do these challenges yourself!
- Go! Go! Go! - Some TMBG music to code by.