1
0
aoc-2020/24/main.py
2022-05-22 18:39:45 +00:00

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))