It’s the 14th and I’m just writing about day 2, which is pretty much what I expected to happen. If the trajectory is linear it’s not too bad, I’ll at least be done in time for AOC 2022.

Day 2’s problem has us read commands and update our position with the following rules:

• `forward X` increases the horizontal position by X units.
• `down X` increases the depth by X units.
• `up X` decreases the depth by X units.

and then returning the product of `horizontal` and `depth`.

Given the following commands, we’d end up with a horizontal value of `15` and depth of `10`, and the product will be `150`

``````forward 5
down 5
forward 8
up 3
down 8
forward 2
``````

The command looks like a nice opportunity for me to have a go at algebraic data types (ADTs) in Kotlin. The way I’ve read that people do this is to create an interface or sealed class and then create a class for each field. I’m not sure if there’s a reason to use interfaces over sealed classes, or vice versa. I tried both and they both worked.

``````interface Command
data class Forward(val distance: Int) : Command
data class Down(val distance: Int): Command
data class Up(val distance: Int): Command
``````

Let’s parse the input:

``````fun parse(commands: List<String>): List<Command> {
return commands.map { c ->
val (command, distance) =
c.split(" ")
.let { (c, d) -> Pair(c, d.toInt())}

when (command) {
"forward" -> Forward(distance)
"down" -> Down(distance)
"up" -> Up(distance)
else -> throw Exception("Invalid command")
}
}
}
``````

I’m going to return a `Position` instead of the product, as that’s what I’d do in real life, let the caller decide what to do with the calculation.

``````data class Position(val horizontal: Int, val depth: Int)

fun getPosition(commands: List<Command>): Position {
var horizontal = 0
var depth = 0

for (c in commands) {
when (c) {
is Forward -> horizontal += c.distance
is Down -> depth += c.distance
is Up -> depth -= c.distance
}
}

return Position(horizontal, depth)
}
``````

Putting it all together:

``````fun run(commandData: List<String>): Int {
return parse(commandData)
.let { getPosition(it) }
.let { p -> p.horizontal * p.depth }
}
``````

In part 2 we learn that we read the manual incorrectly and that we not only need to keep track of `horizontal` and `depth`, but also `aim`. The rules are:

• down X increases your aim by X units.
• up X decreases your aim by X units.
• forward X does two things:
• It increases your horizontal position by X units.

We only need to change the `getPosition` function to satisfy these rules, the rest stays as it is.

``````fun getPosition(commands: List<Command>): Position {
var horizontal = 0
var depth = 0
var aim = 0

for (c in commands) {
when (c) {
is Forward -> {
horizontal += c.distance
depth += aim * c.distance
}
is Down -> aim += c.distance
is Up -> aim -= c.distance
}
}

return Position(horizontal, depth)
}
``````