summaryrefslogtreecommitdiffstats
path: root/day5/__init__.py
blob: a9aaba5ceaba45776d91b92a19ec543c9966e05f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# -*- 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<amount>\d+) from (?P<start>\d+) to (?P<end>\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