-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproblem11.py
116 lines (92 loc) · 3.3 KB
/
problem11.py
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
109
110
111
112
113
114
115
116
"""
ADVENT OF CODE 2021
Contestant: Kevin Wood
Problem: 11
"""
import argparse
from typing import List, Set, Tuple
def solve_part1(lines: List[str], steps: int = 100) -> int:
board = OctopusMatrix.from_string(lines)
for _ in range(steps):
board.step()
return board.total_flashes
def solve_part2(lines: List[str]) -> int:
board = OctopusMatrix.from_string(lines)
steps = 0
while not board.is_synced():
board.step()
steps += 1
return steps
class OctopusMatrix:
def __init__(self, matrix: List[List[int]]) -> None:
self.matrix = matrix
self.total_flashes = 0
self.flashed_coordinates = set() # type: Set[Tuple[int, int]]
@classmethod
def from_string(cls, lines: List[str]) -> "OctopusMatrix":
return cls([[int(val) for val in line] for line in lines])
def step(self) -> None:
for y in range(self.height):
for x in range(self.width):
self.inc(x, y)
self.flashed_coordinates = set()
for y in range(self.height):
for x in range(self.width):
if self.matrix[y][x] > 9:
self.matrix[y][x] = 0
def inc(self, x: int, y: int) -> None:
self.matrix[y][x] += 1
if self.matrix[y][x] > 9 and (x, y) not in self.flashed_coordinates:
self.flashed_coordinates.add((x, y))
self.total_flashes += 1
for nx, ny in self.get_neighbors_at(x, y):
self.inc(nx, ny)
def get_neighbors_at(self, x: int, y: int) -> List[Tuple[int, int]]:
neighbors = [] # type: List[Tuple[int, int]]
if x > 0:
neighbors.append((x - 1, y))
if x < self.width - 1:
neighbors.append((x + 1, y))
if y > 0:
neighbors.append((x, y - 1))
if y < self.height - 1:
neighbors.append((x, y + 1))
if x > 0 and y > 0:
neighbors.append((x - 1, y - 1))
if x < self.width - 1 and y > 0:
neighbors.append((x + 1, y - 1))
if x > 0 and y < self.height - 1:
neighbors.append((x - 1, y + 1))
if x < self.width - 1 and y < self.height - 1:
neighbors.append((x + 1, y + 1))
return neighbors
def is_synced(self) -> int:
v = self.matrix[0][0]
for y in range(self.height):
for x in range(self.width):
if self.matrix[y][x] != v:
return False
return True
@property
def width(self) -> int:
return len(self.matrix[0])
@property
def height(self) -> int:
return len(self.matrix)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Advent of Code 2021, problem 11")
parser.add_argument(
"-i", "--input_file", help="path to input file", default="input/problem11.txt"
)
parser.add_argument("part", help="part (1|2)", type=int)
args = parser.parse_args()
with open(args.input_file, "r") as file:
lines = [line.strip() for line in file.readlines()]
filtered_lines = list(filter(lambda line: bool(line), lines))
if args.part == 1:
output = solve_part1(filtered_lines)
elif args.part == 2:
output = solve_part2(filtered_lines)
else:
raise ValueError("Unknown part")
print(output)