Skip to Content

Advent of Code 2019 - Day 1, in Kotlin

Kotlin solutions to parts 1 and 2 of Advent of Code 2019, Day 1: 'The Tyranny of the Rocket Equation'

Posted on

It’s December 1st and that means another round of Advent of Code has started! Like the last two years , I’m going to be solving each of the problems in Kotlin and blogging about them. While some people try to solve the problems as quickly as possible after they are posted, or solve them in the most efficient way, I try to solve them with a clear solution. Sometimes, those three approaches all align, but in most cases they do not. So sometimes you might see a solution that is a bit more inefficient in order to be more clear. I’m fine with that. For problems like this (generally things I wouldn’t roll into production), I’m fine with that. Code should be written for people, not machines.

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

Problem Input

We are given a file with a module weight on each row. Since our solutions are run from a unit test, we’ll load our sample input file in the test and pass it to our solution class as a List<String>. From there, we’ll parse those into a List<Int>, which we can refer to for our solutions.

class Day01(input: List<String>) {

    private val modules: List<Int> = input.map { it.toInt() }

}

⭐ Day 1, Part 1

The puzzle text can be found here.

As we can see, there’s a module weight calculation that will be executed a few times. In order to make our code a bit cleaner looking, we’ll define a fuel extension function on Int. We’re fortunate that Kotlin will do exactly what we need (rounding down) when doing the division here.

private fun Int.fuel(): Int = (this / 3) - 2

Somebody might correctly point out that we don’t need the parenthesis there. However, I always put them in whenever I do any kind of arithmetic in code. This makes it more clear (to me), and I don’t want to assume that people who will read my code have memorized the operator precedence order.

This is a convenience for people only, the code that the computer runs will be the same either way.

If we look at the problem, we’re told to take each module, calculate the fuel it needs, and sum them together. We could do this with a map and a sum:

// We could try this...

fun solvePart1(): Int =
    modules.map { it.fuel() }.sum()

However, Kotlin’s standard library has a function that will let us do this a bit cleaner - sumBy . The sumBy function allows us to move the code we would have written in a map call to the sum function.

// Actually, let's make that simpler...

fun solvePart1(): Int =
    modules.sumBy { it.fuel() }

Running this will give us the correct answer to part 1 and our first star of 2019!

⭐ Day 1, Part 2

The puzzle text can be found here.

There’s always a twist to these Advent of Code problems in Part 2. In this case, we can keep our Int.fuel() calculation, because it still holds. What we need now is a way to keep calculating fuel costs until the number is low enough to stop. As usual, there are a few different approaches we could take. We could do this with a while loop, or a for loop I suppose but when I see problems described like this I think recursion.

A recursive function is a function that calls itself. It breaks down work into smaller and smaller versions of itself until it reaches a stop condition.

So let’s write a recursive function called fuelWithFuel that performs our fuel cost calculation recursively:

private fun Int.fuelWithFuel(): Int =
    if(this < 9)  {
        0
    } else {
        val fuel = this.fuel()
        fuel + fuel.fuelWithFuel()
    }
Update: Thanks to Karel Peeters in the #advent-of-code room in the Kotlin Slack for pointing out an optimization I missed in my haste! And thanks to Alexander Görtz for pointing out that we can avoid calculating fuel in more cases than I had realized (7 vs. 9 as a lower bound)!

Let’s go over that. First, we have our stop condition - return the 0 if we’re asked to calculate the fuel required for a value under 9. Why 9? Because anything less will yield a negative or zero fuel value.

Next, we get to the meat of our recursive function - breaking down the calculation into a smaller version of itself. In this case, we’re calculating the fuel cost given the weight (this), and add it to a recursive call to the cost for that fuel. As we recurse (calling fuelWithFuel from within fuelWithFuel), we will be dealing with smaller and smaller numbers until we hit the stop condition. At that point we’ll have our answer!

If we visualize this addition, it looks like the example in the problem description:

1969 is 654 + 216 + 70 + 21 + 5 = 966

Our solution to Part 2 ends up looking a lot like Part 1. The only difference is we’ll be calling our fuelWithFuel function:

fun solvePart2(): Int =
    modules.sumBy { it.fuelWithFuel() }

Running that earns us a star and closes out Day 1 of 2019!

Further Reading

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