# Advent of Code 2018 - Day 14, in Kotlin

Kotlin solutions to parts 1 and 2 of Advent of Code 2018, Day 14: 'Chocolate Charts'

Posted on

I’m a bit late posting this because I’ve been moving and have been extra busy.

If you’d rather just view code, the GitHub Repository is here.

Problem Input

We are given a number, and we need it as a `String`, an `Int`, and a `List<Int>` eventually. Let’s do that here, and we can refer to them in parts 1 and 2.

``````class Day14(stoppingPoint: String) {

private val stopInt = stoppingPoint.toInt()
private val stopList = stoppingPoint.map { it.toString().toInt() }.toList()

}``````

Turning a `String` into a `List<Int>` where the `Int` is a digit looks complicated, but `String.toInt()` and `Char.toInt()` mean different things. If you skip one of the `toString()` calls, you’ll get character values, not the digit it represents! Also, we can’t just turn our `Int` into a `List<Int>` with our `asDigits()` function below, because inputs might start with zero, and we would mis-calculate them.

#### Day 14, Part 1

The puzzle text can be found here.

The problem is pretty limiting in terms of approaches we can take. We could write this as a sequence, but it would be easier for part 2 if we pass in a function to tell us when to stop. Essentially, we will keep generating recipes and ask the `stopCondition` function if we should stop. When it tells us to stop, we return the entire history we’ve generated so far.

``````private fun recipes(stopCondition: (List<Int>) -> Boolean): List<Int> {
val history = mutableListOf(3, 7)
var elf1 = 0
var elf2 = 1
var stop = false

while (!stop) {
val nextValue = history[elf1] + history[elf2]
nextValue.asDigits().forEach {
if (!stop) {
stop = stopCondition(history)
}
}
elf1 = (elf1 + history[elf1] + 1) % history.size
elf2 = (elf2 + history[elf2] + 1) % history.size
}
return history
}``````

The part that got me for a while is that we have to check `stopCondition` twice! Why? If the elves create a great recipe, they produce two digits and not just one. So we have to check the stop condition for each history item added, not just the first one.

We also define this extension function to bust up an `Int` into a `List<Int>`

``````private fun Int.asDigits(): List<Int> =
this.toString().map { it.toString().toInt() }``````

And with part 1, our stop condition is just based on the length:

``````fun solvePart1(): String =
recipes { it.size == stopInt + 10 }.takeLast(10).joinToString("")``````

We generate recipes until we have 10 more than the stopping point we have is, and then we just stringify the last 10 elements.

Star earned! Onward!

#### Day 14, Part 2

The puzzle text can be found here.

See? I told you the higher-order function was the way to go. Defining a new function for part two solves the problem without altering our logic any more:

``````fun solvePart2(): Int =
recipes { it.endsWith(stopList) }.size - stopList.size``````

We’ve got this handy extension function to quickly test that one `List` ends with another `List`. I found this to be fast enough to make part 2 not take too long.

``````private fun List<Int>.endsWith(other: List<Int>): Boolean =
if (this.size < other.size) false
else this.slice(this.size - other.size until this.size) == other``````

Star earned!