summaryrefslogtreecommitdiffstats
path: root/day9/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'day9/__init__.py')
-rw-r--r--day9/__init__.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/day9/__init__.py b/day9/__init__.py
new file mode 100644
index 0000000..696a6dc
--- /dev/null
+++ b/day9/__init__.py
@@ -0,0 +1,79 @@
1from abc import ABC
2from collections import Counter
3from copy import copy
4from functools import reduce
5from operator import mul
6from typing import List, Tuple, Dict, FrozenSet, Iterator, Set, Callable
7
8from aoc import BaseAssignment
9
10Coordinate = Tuple[int, int]
11Field = List[List[int]]
12
13
14class 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 if ny == y:
25 continue
26 yield (x, ny)
27
28 for nx in list(range(max(0, x - 1), min(len(field[0]) - 1, x + 1) + 1)):
29 if nx == x:
30 continue
31 yield (nx, y)
32
33 @classmethod
34 def lowest_points(cls, field: Field) -> Iterator[Coordinate]:
35 for y, row in enumerate(field):
36 for x, item in enumerate(row):
37 if all(field[ny][nx] > item for nx, ny in cls.neighbours(field, x, y)):
38 yield x, y
39
40
41class AssignmentOne(Assignment):
42 example_result = 15
43
44 def run(self, input: Field) -> int:
45 lows = list(input[y][x] for x, y in self.lowest_points(input))
46 return sum(lows) + len(lows)
47
48
49def flatten(l: List[Set[Coordinate]]) -> List:
50 flat_list = []
51 for _ in l:
52 flat_list += _
53
54 return flat_list
55
56
57class AssignmentTwo(Assignment):
58 example_result = 1134
59
60 @classmethod
61 def find_basin_members(cls, field: Field, x: int, y: int) -> Set[Coordinate]:
62 return {
63 (x, y),
64 *flatten([
65 cls.find_basin_members(field, nx, ny)
66 for nx, ny in cls.neighbours(field, x, y)
67 if field[y][x] < field[ny][nx] < 9
68 ])
69 }
70
71 def run(self, input: Field) -> int:
72 return reduce(
73 mul,
74 sorted([
75 len(self.find_basin_members(input, x, y))
76 for x, y in self.lowest_points(input)
77 ], reverse=True)[:3],
78 1
79 )