diff options
Diffstat (limited to 'day11/__init__.py')
| -rw-r--r-- | day11/__init__.py | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/day11/__init__.py b/day11/__init__.py new file mode 100644 index 0000000..60f2037 --- /dev/null +++ b/day11/__init__.py | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | from abc import ABC | ||
| 2 | from collections import Counter | ||
| 3 | from copy import copy | ||
| 4 | from functools import reduce | ||
| 5 | from operator import mul | ||
| 6 | from typing import List, Tuple, Dict, FrozenSet, Iterator, Set, Callable, Any | ||
| 7 | |||
| 8 | from aoc import BaseAssignment | ||
| 9 | |||
| 10 | Coordinate = Tuple[int, int] | ||
| 11 | Field = List[List[int]] | ||
| 12 | |||
| 13 | |||
| 14 | class Assignment(BaseAssignment, ABC): | ||
| 15 | def parse_item(self, item: str) -> List[int]: | ||
| 16 | return [int(i) for i in item] | ||
| 17 | |||
| 18 | def read_input(self, example = False) -> Field: | ||
| 19 | return list(super().read_input(example)) | ||
| 20 | |||
| 21 | @classmethod | ||
| 22 | def neighbours(cls, field: Field, x: int, y: int) -> Iterator[Coordinate]: | ||
| 23 | for ny in list(range(max(0, y - 1), min(len(field) - 1, y + 1) + 1)): | ||
| 24 | for nx in list(range(max(0, x - 1), min(len(field[0]) - 1, x + 1) + 1)): | ||
| 25 | if ny == y and nx == x: | ||
| 26 | continue | ||
| 27 | yield (nx, ny) | ||
| 28 | |||
| 29 | @classmethod | ||
| 30 | def flatten(cls, l: List[List[Any]]) -> List: | ||
| 31 | flat_list = [] | ||
| 32 | for _ in l: | ||
| 33 | flat_list += _ | ||
| 34 | |||
| 35 | return flat_list | ||
| 36 | |||
| 37 | @classmethod | ||
| 38 | def flash(cls, field, x, y): | ||
| 39 | for nx, ny in cls.neighbours(field, x, y): | ||
| 40 | if field[ny][nx] > 0: | ||
| 41 | field[ny][nx] = (field[ny][nx] + 1) % 10 | ||
| 42 | |||
| 43 | if field[ny][nx] == 0: | ||
| 44 | cls.flash(field, nx, ny) | ||
| 45 | |||
| 46 | @classmethod | ||
| 47 | def step(cls, field: Field): | ||
| 48 | flashing = [] | ||
| 49 | |||
| 50 | for y, row in enumerate(field): | ||
| 51 | for x, item in enumerate(row): | ||
| 52 | field[y][x] = (item + 1) % 10 | ||
| 53 | if field[y][x] == 0: | ||
| 54 | flashing.append((x, y)) | ||
| 55 | |||
| 56 | for x, y in flashing: | ||
| 57 | cls.flash(field, x, y) | ||
| 58 | |||
| 59 | |||
| 60 | class AssignmentOne(Assignment): | ||
| 61 | example_result = 1656 | ||
| 62 | |||
| 63 | def run(self, input: Field) -> int: | ||
| 64 | count = 0 | ||
| 65 | for _ in range(100): | ||
| 66 | self.step(input) | ||
| 67 | count += Counter(self.flatten(input))[0] | ||
| 68 | |||
| 69 | return count | ||
| 70 | |||
| 71 | |||
| 72 | class AssignmentTwo(Assignment): | ||
| 73 | example_result = 195 | ||
| 74 | |||
| 75 | def run(self, input: Field) -> int: | ||
| 76 | step_nr = 0 | ||
| 77 | while True: | ||
| 78 | step_nr += 1 | ||
| 79 | |||
| 80 | self.step(input) | ||
| 81 | |||
| 82 | flat_input = self.flatten(input) | ||
| 83 | |||
| 84 | if len(flat_input) == Counter(flat_input)[0]: | ||
| 85 | break | ||
| 86 | |||
| 87 | return step_nr | ||
