105 lines
2.6 KiB
Python
105 lines
2.6 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
import sys
|
||
|
|
from typing import Sequence, Tuple, Set
|
||
|
|
from copy import deepcopy
|
||
|
|
|
||
|
|
|
||
|
|
Point = Tuple[int, int]
|
||
|
|
|
||
|
|
|
||
|
|
class Grid:
|
||
|
|
def __init__(self, grid: Sequence[Sequence[int]]):
|
||
|
|
self.grid = grid
|
||
|
|
self.rows = len(grid)
|
||
|
|
self.cols = len(grid[0]) if self.rows else 0
|
||
|
|
|
||
|
|
def neighbors(self, point: Point) -> Set[Point]:
|
||
|
|
i, j = point
|
||
|
|
return {
|
||
|
|
(r, c)
|
||
|
|
for r, c in [
|
||
|
|
(i - 1, j - 1),
|
||
|
|
(i - 1, j + 1),
|
||
|
|
(i + 1, j - 1),
|
||
|
|
(i + 1, j + 1),
|
||
|
|
(i, j - 1),
|
||
|
|
(i, j + 1),
|
||
|
|
(i - 1, j),
|
||
|
|
(i + 1, j),
|
||
|
|
]
|
||
|
|
if 0 <= r < self.rows and 0 <= c < self.cols
|
||
|
|
}
|
||
|
|
|
||
|
|
def step(self):
|
||
|
|
# Add 1 to everything
|
||
|
|
for i in range(self.rows):
|
||
|
|
for j in range(self.cols):
|
||
|
|
self.grid[i][j] += 1
|
||
|
|
|
||
|
|
# "Apply" grid - increments to add to each grid item
|
||
|
|
apply = [[0 for _ in row] for row in self.grid]
|
||
|
|
flashed = [[False for _ in row] for row in self.grid]
|
||
|
|
|
||
|
|
while True:
|
||
|
|
changed = False
|
||
|
|
|
||
|
|
for i in range(self.rows):
|
||
|
|
for j in range(self.cols):
|
||
|
|
if self.grid[i][j] > 9 and not flashed[i][j]:
|
||
|
|
flashed[i][j] = True
|
||
|
|
changed = True
|
||
|
|
for ni, nj in self.neighbors((i, j)):
|
||
|
|
self.grid[ni][nj] += 1
|
||
|
|
|
||
|
|
if not changed:
|
||
|
|
break
|
||
|
|
# Now, reset anything greater than 9 to 0
|
||
|
|
for i in range(self.rows):
|
||
|
|
for j in range(self.cols):
|
||
|
|
if self.grid[i][j] > 9:
|
||
|
|
self.grid[i][j] = 0
|
||
|
|
|
||
|
|
def __getitem__(self, key: Point) -> int:
|
||
|
|
r, c = key
|
||
|
|
return self.grid[r][c]
|
||
|
|
|
||
|
|
def __str__(self) -> str:
|
||
|
|
lines = []
|
||
|
|
for row in self.grid:
|
||
|
|
line = ""
|
||
|
|
for col in row:
|
||
|
|
if col == 0:
|
||
|
|
line += "\u001b[34;1m0\u001b[0m"
|
||
|
|
else:
|
||
|
|
line += str(col)
|
||
|
|
lines += [line]
|
||
|
|
return "\n".join(lines)
|
||
|
|
|
||
|
|
|
||
|
|
grid = Grid([[int(c) for c in line.strip()] for line in sys.stdin])
|
||
|
|
|
||
|
|
|
||
|
|
def part1(grid: Grid):
|
||
|
|
flashes = 0
|
||
|
|
for step in range(100):
|
||
|
|
grid.step()
|
||
|
|
for row in grid.grid:
|
||
|
|
for col in row:
|
||
|
|
if col == 0:
|
||
|
|
flashes += 1
|
||
|
|
print(flashes)
|
||
|
|
|
||
|
|
|
||
|
|
def part2(grid: Grid):
|
||
|
|
steps = 0
|
||
|
|
while any(any(col != 0 for col in row) for row in grid.grid):
|
||
|
|
grid.step()
|
||
|
|
steps += 1
|
||
|
|
print(steps)
|
||
|
|
|
||
|
|
|
||
|
|
print("Part 1")
|
||
|
|
part1(deepcopy(grid))
|
||
|
|
print("Part 2")
|
||
|
|
part2(grid)
|