from typing import * from aocpy import BaseChallenge from queue import LifoQueue as Stack from dataclasses import dataclass import re @dataclass class MoveInstruction: n: int source: int destination: int instruction_regexp = re.compile(r"move (\d+) from (\d+) to (\d+)") def parse(instr: str) -> Tuple[List[Stack], List[MoveInstruction]]: raw_initial_state, raw_instructions = instr.rstrip().split("\n\n") state_lines = raw_initial_state.splitlines() state_lines = state_lines[:-1] # the last line only contains digits that # we don't need to look at state_lines = [ [line[i : i + 3] for i in range(0, len(line), 4)] for line in state_lines ] state: List[Stack] = [] for _ in range(len(state_lines[0])): state.append(Stack()) for line in state_lines[::-1]: for i, item in enumerate(line): if item != " ": state[i].put_nowait(item[1]) instructions: List[MoveInstruction] = [] for line in raw_instructions.strip().splitlines(): instructions.append( MoveInstruction(*map(int, instruction_regexp.match(line).groups())) ) return state, instructions class Challenge(BaseChallenge): @staticmethod def one(instr: str) -> str: state, instructions = parse(instr) for instruction in instructions: for _ in range(instruction.n): x = state[instruction.source - 1].get_nowait() state[instruction.destination - 1].put_nowait(x) return "".join(crate.get_nowait() for crate in state) @staticmethod def two(instr: str) -> str: state, instructions = parse(instr) for instruction in instructions: items = [] for _ in range(instruction.n): items.append(state[instruction.source - 1].get_nowait()) for item in items[::-1]: state[instruction.destination - 1].put_nowait(item) return "".join(crate.get_nowait() for crate in state)