Advent of Code 2022 day 5
I’m jumping around a little bit, but here’s my Python solution for Advent of Code 2022 day 5. I had quite a few false starts trying to parse the input for this one - I knew I wanted to transpose the stacks, but trying to extract the stack IDs from their delimiters while managing potential white-space caused some head scratching. Some list popping and pushing from there.
import re
import unittest
import utils
def extract_stacks_from_raw_input(raw_input):
return [line.rstrip() for line in raw_input if "[" in line]
def extract_steps_from_raw_input(raw_input):
return [line.rstrip() for line in raw_input if "move" in line]
def parse_raw_stacks(raw_stacks: list[str]):
# Some of this is simply to work around the fact that I've set my text editor
# to strip trailing whitespace from all lines in a file on save
stacks_width = max([len(line) for line in raw_stacks])
transposed_raw_stacks = [
[row.ljust(stacks_width)[i] for row in raw_stacks] for i in range(stacks_width)
]
dirty_stacks = [
stack
for stack in transposed_raw_stacks
if any([char.isupper() for char in stack])
]
return [list(reversed([c for c in stack if c.isupper()])) for stack in dirty_stacks]
def extract_data_from_step(step):
return [
int(g)
for g in re.match(r"^move (\d+) from (\d+) to (\d+)$", step).group(1, 2, 3)
]
def parse_raw_steps(raw_steps):
return [extract_data_from_step(step) for step in raw_steps]
def part_one(raw_input):
stacks = parse_raw_stacks(extract_stacks_from_raw_input(raw_input))
steps = parse_raw_steps(extract_steps_from_raw_input(raw_input))
for step in steps:
for _ in range(step[0]):
stacks[step[2] - 1] += stacks[step[1] - 1].pop()
return "".join([stack[-1] for stack in stacks])
def part_two(raw_input):
stacks = parse_raw_stacks(extract_stacks_from_raw_input(raw_input))
steps = parse_raw_steps(extract_steps_from_raw_input(raw_input))
for step in steps:
stacks[step[2] - 1] += stacks[step[1] - 1][-step[0] :]
del stacks[step[1] - 1][-step[0] :]
return "".join([stack[-1] for stack in stacks])
class TestExamples(unittest.TestCase):
def setUp(self):
self.raw_input = [
" [D] ",
"[N] [C] ",
"[Z] [M] [P]",
" 1 2 3 ",
"",
"move 1 from 2 to 1",
"move 3 from 1 to 3",
"move 2 from 2 to 1",
"move 1 from 1 to 2",
]
def test_part_one(self):
self.assertEqual(part_one(self.raw_input), "CMZ")
def test_part_two(self):
self.assertEqual(part_two(self.raw_input), "MCD")
if __name__ == "__main__":
raw_input = utils.get_raw_input("day_05_input.txt", strip=False)
print(f"Part one: {part_one(raw_input)}")
print(f"Part two: {part_two(raw_input)}")