Advent of Code 2021 - Day 2
The advent of code is an annual coding challenge in the month of December. This article covers the second day's puzzle with a solution written in Go.
Still with me? Great! Let's head on to solving day 2.
The story tells us, that we're still in the submarine and are trying to learn how to navigate it. The submarine can take a bunch of simple commands in the form of direction unit
.
forward 5
down 5
forward 8
up 3
down 8
forward 2
Someone has already programmed a course for us and it's our task to figure out where we're going. We're to compute the final horizontal position and our final depth. An important note here is that down
increases the depth while up
decreases the depth of the submarine.
Part 1
Since I'm trying to learn some concepts of Go I decided to represent the commands as a struct:
type command struct {
direction string
steps int
}
This is easy enough. We have a direction and a number of steps in the defined direction.
We can now write go on to read our puzzle input.
func getInputs() []command {
bytes, _ := ioutil.ReadFile(filename)
lines := strings.Split(string(bytes), "\n")
cmds := []command{}
for _, line := range lines {
if len(line) == 0 {
continue
}
instr := strings.Split(line, " ")
val, _ := strconv.Atoi(instr[1])
cmds = append(cmds, command{instr[0], val})
}
return cmds
}
Once again, there's not too much magic going on here. We read the file, split it into lines, and then further split the lines into the two components representing our direction and a number. A more experienced Go programmer would probably use bufio.ReadLine
to read the file line-by-line, but for now, I'm content that this will do the job just fine.
Computing our horizontal position and depth is now as easy as looping over all commands and tallying up the steps based on the direction:
var pos, depth int
for _, cmd := range cmds {
switch cmd.direction {
case "forward":
pos += cmd.steps
case "down":
depth += cmd.steps
case "up":
depth -= cmd.steps
}
}
Part 2
The second part of the story suggests that the final position we calculated doesn't make any sense, and so an alternative algorithm is proposed. The down
and up
commands don't directly affect our position but represent changes to the submarine's aim.
Assume for a moment our instructions were:
forward 5
down 1
forward 2
In Part 1 this would have resulted in a horizontal position of 7 and a depth of 1. In Part 2 the interpretation changes to:
- Move 5 steps forward
- Adjust aim to 1 (aim down!)
- Move 2 more steps forward and 2 steps down in depth (since our aim is at 1 and we're stepping two times)
In other words, every movement forward by X steps will change our depth by X * aim
.
We need to modify our code ever so slightly to keep track of our sub's aim:
var aim int
pos = 0
depth = 0
for _, cmd := range cmds {
switch cmd.direction {
case "forward":
pos += cmd.steps
depth += aim * cmd.steps
case "down":
aim += cmd.steps
case "up":
aim -= cmd.steps
}
}
That's it. We're done with part 2.
Summary
Day 2 built really well on the previous day. It's good enough to practice I/O and processing text input. The task should be easy to solve even if the programming language you're using is relatively new to you.
You can also follow me on Twitter.