68 lines
2.1 KiB
Python
Raw Normal View History

2020-12-17 16:16:30 +01:00
# SPDX-License-Identifier: MIT
# Copyright (c) 2020 Akumatic
#
# https://adventofcode.com/2020/day/17
from itertools import product
def read_file() -> list:
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
return [list(line.strip()) for line in f.readlines()]
def parse_input(input: list) -> set:
active_cubes = set()
for y in range(len(input)):
for x in range(len(input[0])):
if input[y][x] == "#":
active_cubes.add((x, y, 0, 0))
return active_cubes
def simulate(active_cubes: set, size: int = 3, iterations: int = 6) -> int:
assert 3 <= size <= 4
# neighbor positions
positions = product(range(-1, 2), repeat=size)
if size == 4:
npos = tuple(pos for pos in positions if pos != (0, 0, 0, 0))
else: # size == 4
npos = tuple((pos[0], pos[1], pos[2], 0) for pos in positions if pos != (0, 0, 0))
# iterations
for _ in range(iterations):
next_active = set()
neighbors = set()
# check if active cubes stay active
for cube in active_cubes:
count = 0
for n in npos:
pos = tuple(cube[i] + n[i] for i in range(4))
if pos in active_cubes:
count += 1
else:
neighbors.add(pos)
if 2 <= count <= 3:
next_active.add(cube)
# check neighbors of active cubes if they become active
for cube in neighbors:
count = 0
for n in npos:
pos = tuple(cube[i] + n[i] for i in range(4))
if pos in active_cubes:
count += 1
if count == 3:
next_active.add(cube)
active_cubes = next_active
return len(active_cubes)
def part1(active_cubes: set) -> int:
return simulate(active_cubes, 3)
def part2(active_cubes: set) -> int:
return simulate(active_cubes, 4)
if __name__ == "__main__":
input = read_file()
data = parse_input(input)
print(f"Part 1: {part1(data)}")
print(f"Part 2: {part2(data)}")