#!/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)