summaryrefslogtreecommitdiffstats
path: root/day11/__init__.py
blob: 60f2037351af37c1fa8f5e41e74bdef5c390fe7d (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
from abc import ABC
from collections import Counter
from copy import copy
from functools import reduce
from operator import mul
from typing import List, Tuple, Dict, FrozenSet, Iterator, Set, Callable, Any

from aoc import BaseAssignment

Coordinate = Tuple[int, int]
Field = List[List[int]]


class Assignment(BaseAssignment, ABC):
    def parse_item(self, item: str) -> List[int]:
        return [int(i) for i in item]

    def read_input(self, example = False) -> Field:
        return list(super().read_input(example))

    @classmethod
    def neighbours(cls, field: Field, x: int, y: int) -> Iterator[Coordinate]:
        for ny in list(range(max(0, y - 1), min(len(field) - 1, y + 1) + 1)):
            for nx in list(range(max(0, x - 1), min(len(field[0]) - 1, x + 1) + 1)):
                if ny == y and nx == x:
                    continue
                yield (nx, ny)

    @classmethod
    def flatten(cls, l: List[List[Any]]) -> List:
        flat_list = []
        for _ in l:
            flat_list += _

        return flat_list

    @classmethod
    def flash(cls, field, x, y):
        for nx, ny in cls.neighbours(field, x, y):
            if field[ny][nx] > 0:
                field[ny][nx] = (field[ny][nx] + 1) % 10

                if field[ny][nx] == 0:
                    cls.flash(field, nx, ny)

    @classmethod
    def step(cls, field: Field):
        flashing = []

        for y, row in enumerate(field):
            for x, item in enumerate(row):
                field[y][x] = (item + 1) % 10
                if field[y][x] == 0:
                    flashing.append((x, y))

        for x, y in flashing:
            cls.flash(field, x, y)


class AssignmentOne(Assignment):
    example_result = 1656

    def run(self, input: Field) -> int:
        count = 0
        for _ in range(100):
            self.step(input)
            count += Counter(self.flatten(input))[0]

        return count


class AssignmentTwo(Assignment):
    example_result = 195

    def run(self, input: Field) -> int:
        step_nr = 0
        while True:
            step_nr += 1

            self.step(input)

            flat_input = self.flatten(input)

            if len(flat_input) == Counter(flat_input)[0]:
                break

        return step_nr