92 lines
2.6 KiB
Python
92 lines
2.6 KiB
Python
from typing import Iterable
|
|
|
|
STEP_LOOKUP = {
|
|
"e": ( 1, 0),
|
|
"w": (-1, 0),
|
|
"ne": ( 1, 1),
|
|
"sw": (-1, -1),
|
|
"nw": ( 0, 1),
|
|
"se": ( 0, -1),
|
|
}
|
|
|
|
def read_input(filename: str) -> list[list[str]]:
|
|
tiles = []
|
|
with open(filename, "r") as f:
|
|
for line in f.readlines():
|
|
line = line.strip()
|
|
steps = []
|
|
i = 0
|
|
while i < len(line):
|
|
if line[i] == "e" or line[i] == "w":
|
|
steps.append(line[i])
|
|
else:
|
|
steps.append(line[i:i+2])
|
|
i += 1
|
|
i += 1
|
|
tiles.append(steps)
|
|
return tiles
|
|
|
|
def get_black_tiles(tiles: list[list[str]]) -> set[tuple[int, int]]:
|
|
black_tiles = set()
|
|
|
|
for steps in tiles:
|
|
x = 0
|
|
y = 0
|
|
for step in steps:
|
|
dx, dy = STEP_LOOKUP[step]
|
|
x += dx
|
|
y += dy
|
|
if (x, y) in black_tiles:
|
|
black_tiles.remove((x, y))
|
|
else:
|
|
black_tiles.add((x, y))
|
|
|
|
return black_tiles
|
|
|
|
def part1(tiles: list[list[str]]) -> int:
|
|
return len(get_black_tiles(tiles))
|
|
|
|
def get_neighbors(tile: tuple[int, int]) -> Iterable[tuple[int, int]]:
|
|
for offset in STEP_LOOKUP.values():
|
|
neighbor = (tile[0]+offset[0], tile[1]+offset[1])
|
|
yield neighbor
|
|
|
|
def count_neighbors(tiles: set[tuple[int, int]], tile: tuple[int, int]) -> int:
|
|
count = 0
|
|
for neighbor in get_neighbors(tile):
|
|
if neighbor in tiles:
|
|
count += 1
|
|
return count
|
|
|
|
def simulate(black_tiles: set[tuple[int, int]]) -> set[tuple[int, int]]:
|
|
white_tiles = set()
|
|
for tile in black_tiles:
|
|
for neighbor in get_neighbors(tile):
|
|
if neighbor not in black_tiles:
|
|
white_tiles.add(neighbor)
|
|
|
|
new_black_tiles = set()
|
|
# Any black tile with zero or more than 2 black tiles immediately adjacent to it is flipped to white.
|
|
for black_tile in black_tiles:
|
|
black_count = count_neighbors(black_tiles, black_tile)
|
|
if black_count == 1 or black_count == 2:
|
|
new_black_tiles.add(black_tile)
|
|
|
|
# Any white tile with exactly 2 black tiles immediately adjacent to it is flipped to black.
|
|
for white_tile in white_tiles:
|
|
if count_neighbors(black_tiles, white_tile) == 2:
|
|
new_black_tiles.add(white_tile)
|
|
|
|
return new_black_tiles
|
|
|
|
def part2(tiles: list[list[str]]) -> int:
|
|
black_tiles = get_black_tiles(tiles)
|
|
for _ in range(100):
|
|
black_tiles = simulate(black_tiles)
|
|
return len(black_tiles)
|
|
|
|
if __name__ == "__main__":
|
|
tiles = read_input("input.txt")
|
|
print("part1: ", part1(tiles))
|
|
print("part2: ", part2(tiles))
|