Skip to Content

Advent of Code 2020 - Day 25, in Kotlin - Combo Breaker

Kotlin solutions to parts 1 and 2 of Advent of Code 2020, Day 25: 'Combo Breaker'

Posted on

Today is the final puzzle for Advent of Code 2020! Just for fun, we’ll use sequences for everything. I love the name of this puzzle - after 24 days of alliterative puzzle names (“Report Repair”, “Rain Risk”, “Crab Combat”, etc) today we get COMBO BUSTER!

I want to say thank you to Eric Wastl, the creator of Advent of Code. I get so much joy and learn so much every year, and I can’t even begin to imagine how much work he must put into creating 25 puzzles and matching sets of inputs. Thanks, Eric!

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

Problem Input

We have two numbers to take in, so we’ll do that as a List<String> and convert them each to Longs.

class Day25(input: List<String>) {

    private val cardPk = input.first().toLong()
    private val doorPk = input.last().toLong()

}

⭐ Day 25, Part 1

The puzzle text can be found here.

I’ll confess it took me a while to understand what was being asked of us today, but the examples helped as usual. We’re going to be performing the same equation a few times, so let’s abstract that into a function.

private fun Long.mathPart(subject: Long = 7): Long =
    this * subject % 20201227

This could have taken two arguments and not been an extension function, but I think this just looks cleaner. Also, we default the subject to 7, which is the number we’re going to use half the time.

Next, we need to be able to calculate the loop size. The work here is to keep increasing the loop size until the mathPart generates our target number. We could do this with a while loop, and in fact it would be faster if we did. But I like this version because it shows off the use of indexOf on a Sequence. That’s a nice trick to remember so we don’t have to return Pair<Int,Long> or keep track of the proposed loop values ourselves.

private fun findLoopSize(target: Long): Int =
    generateSequence(1L) { it.mathPart() }.indexOf(target)

Once we have a loop size figured out, we want to use that to transform one of the card numbers. We’ll use another sequence here just for fun, but it would be faster with a while loop. In this case, we generate successive values and drop them until we’ve hit our loopSize, and then take the first value we find.

private fun transform(loopSize: Int, subject: Long): Long =
    generateSequence(1L) { it.mathPart(subject) }.drop(loopSize).first()

And we can use those to succinctly solve part 1!

fun solvePart1(): Long =
    transform(findLoopSize(cardPk), doorPk)

Star earned! Two, in fact!

⭐ Day 25, Part 2

There is no part 2! This was my 100th blog post on Advent of Code and I hope you’ve had as much fun solving these puzzles as I have over the years. Hopefully we’ll get to do this again next year!

Further Reading

  1. Index of All Solutions - All posts and solutions for 2020, in Kotlin.
  2. My Github repo - Solutions and tests for each day.
  3. Solution - Full code for day 25
  4. Advent of Code - Come join in and do these challenges yourself!