import fileinput import itertools from pprint import pprint from typing import Any, Dict, List, Optional, Tuple, Generator def parse() -> Generator[List[str], None, None]: for line in fileinput.input(): line = line.strip() directions = [] while line: for direction in ("e", "se", "sw", "w", "nw", "ne"): if line.startswith(direction): line = line[len(direction) :] directions.append(direction) break yield directions def main() -> None: directions = list(parse()) N = 1000 OFFSET = N // 2 grid = [[False] * N for _ in range(N)] for tile in directions: column, row = 0, 0 for direction in tile: if direction == "e": column += 1 elif direction == "se": column += row % 2 row += 1 elif direction == "sw": column -= (row + 1) % 2 row += 1 elif direction == "w": column -= 1 elif direction == "nw": column -= (row + 1) % 2 row -= 1 elif direction == "ne": column += row % 2 row -= 1 grid[row + OFFSET][column + OFFSET] = not grid[row + OFFSET][column + OFFSET] print("Part 1:", sum(sum(row) for row in grid)) changes = [] for _ in range(100): for row in range(N): for column in range(N): neighbors = 0 for dc, dr in ( (1, 0), (row % 2, 1), (-((row + 1) % 2), 1), (-1, 0), (-((row + 1) % 2), -1), (row % 2, -1), ): c, r = column + dc, row + dr if 0 <= c < N and 0 <= r < N: neighbors += grid[r][c] # print(neighbors) if grid[row][column]: if neighbors != 1 and neighbors != 2: changes.append((row, column, False)) else: if neighbors == 2: changes.append((row, column, True)) for (row, column, value) in changes: grid[row][column] = value changes.clear() print("Part 2:", sum(sum(row) for row in grid)) if __name__ == "__main__": main()