# -*- coding: utf-8 -*- import re from abc import ABC from typing import Iterator, Any, TypedDict, Tuple, List from queue import LifoQueue from aoc import BaseAssignment move_regex = re.compile("^move (?P\d+) from (?P\d+) to (?P\d+)$") class Move(TypedDict): amount: int start: int end: int class Assignment(BaseAssignment, ABC): def parse_move(self, move: str) -> Move: match = move_regex.match(move) if match: move = match.groupdict() return Move( amount=int(move["amount"]), start=int(move["start"]), end=int(move["end"]), ) def parse_stacks(self, string_stacks: List[str]) -> List[LifoQueue]: stacks = [] columns = string_stacks.pop().replace(" ", "") for i in range(len(columns)): stacks.append(LifoQueue()) for line in reversed(string_stacks): for index, stack in enumerate(stacks): item_index = (index * 4) + 1 try: item = line[item_index] if item != " ": stack.put(item) except IndexError: pass return stacks def parse_input(self, input: Iterator) -> Tuple[List[LifoQueue], List[Move]]: parsing_stacks = True tmp_stacks = [] stacks = [] moves = [] for line in input: if line == "": parsing_stacks = False stacks = self.parse_stacks(tmp_stacks) continue if parsing_stacks: tmp_stacks.append(line) else: moves.append(self.parse_move(line)) return stacks, moves def execute_moves(self, stacks: List[LifoQueue], moves: List[Move]): raise NotImplementedError() def run(self, input: Iterator) -> Any: stacks, moves = self.parse_input(input) self.execute_moves(stacks, moves) return "".join([stack.get() for stack in stacks]) class AssignmentOne(Assignment): example_result = "CMZ" def execute_moves(self, stacks: List[LifoQueue], moves: List[Move]): for move in moves: start = stacks[move["start"] - 1] end = stacks[move["end"] - 1] for _ in range(move["amount"]): end.put(start.get()) return stacks class AssignmentTwo(Assignment): example_result = "MCD" def execute_moves(self, stacks: List[LifoQueue], moves: List[Move]): for move in moves: start = stacks[move["start"] - 1] end = stacks[move["end"] - 1] tmp_stack = LifoQueue() for _ in range(move["amount"]): tmp_stack.put(start.get()) while not tmp_stack.empty(): end.put(tmp_stack.get()) return stacks