Solution in Python for the day 2 puzzle of the 2021 edition of the Advent of Code annual programming challenge.
It seems like the submarine can take a series of commands like forward 1, down 2, or up 3:
- 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.
After following these instructions, you would have a horizontal position of 15 and a depth of 10. (Multiplying these together produces 150.)
Calculate the horizontal position and depth you would have after following the planned course. What do you get if you multiply your final horizontal position by your final depth?
According to this statement, this first part is quite straightforward.
Opening the input contents file, we notice that each line starts with command followed by a quantity.
First, let's confirm this assumption:
for line in open('./advent-of-code/2021/day-2/input.txt').readlines():
assert len(line.split()) == 2 \
and line.split()[0] in ['forward', 'up', 'down'] \
and line.split()[1].isdigit()
Which is does great! We can move and create a proper method this time. Before creating said method, we must agree on a return type.
Looking at the input contents files, we have a number of lines with no relationship between them. An iterator is a good fit for such scenarios promoting sequential processing. This means that the method uses a yield
statement instead of return
.
The structure of each line is a string followed by an integer. Thus, the return object is Iterator[tuple]
def load_contents(filename: Path) -> Iterator[tuple]:
"""Load and convert contents from file
:param filename: input filename
:return: iterator
"""
for line in open(filename).readlines():
items = line.split()
yield items[0], int(items[1])
log.debug(f'Reached end of {filename=}')
def solve_part_one(commands: Iterator[tuple]) -> int:
"""Solve the first part of the challenge
:param commands: list of commands
:return: expected challenge answer
"""
forward_pos = 0
depth = 0
for command in commands:
if command[0] == 'forward':
forward_pos += command[1]
elif command[0] == 'down':
depth += command[1]
elif command[0] == 'up':
depth -= command[1]
answer = forward_pos * depth
return answer
Contents | Command | Answer | Time |
---|---|---|---|
input.txt |
./day_2.py input.txt -p 1 |
1480518 |
11.2 ms |
In addition to horizontal position and depth, you'll also need to track a third value, aim, which also starts at 0. The commands also mean something entirely different from you first thought:
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. It increases your depth by your aim multiplied by X.
Suspiciously easy for a part two!
Again note that since you're on a submarine, down and up do the opposite of what you might expect: "down" means aiming in the positive direction.
Using this new interpretation of the commands, calculate the horizontal position and depth you would have after following the planned course. What do you get if you multiply your final horizontal position by your final depth?
Same method for computing the answer as in part one.
def solve_part_two(commands: Iterator[tuple]) -> int:
"""Solve the second part of the challenge
:param commands: list of commands
:return: expected challenge answer
"""
forward_pos = 0
depth = 0
aim = 0
for command in commands:
if command[0] == 'forward':
forward_pos += command[1]
depth += aim * command[1]
elif command[0] == 'down':
aim += command[1]
elif command[0] == 'up':
aim -= command[1]
answer = forward_pos * depth
return answer
Contents | Command | Answer | Time |
---|---|---|---|
input.txt |
./day_2.py input.txt -p 2 |
1282809906 |
22.5 ms |