Solution to problem 17 in Python

This commit is contained in:
David Doblas Jiménez 2022-01-07 16:07:57 +01:00
parent 9b11007a2f
commit 606c111e32

221
src/2020/P17.py Normal file
View File

@ -0,0 +1,221 @@
# --- Day 17: Conway Cubes ---
# As your flight slowly drifts through the sky, the Elves at the Mythical
# Information Bureau at the North Pole contact you. They'd like some help
# debugging a malfunctioning experimental energy source aboard one of their
# super-secret imaging satellites.
# The experimental energy source is based on cutting-edge technology: a set of
# Conway Cubes contained in a pocket dimension! When you hear it's having
# problems, you can't help but agree to take a look.
# The pocket dimension contains an infinite 3-dimensional grid. At every
# integer 3-dimensional coordinate (x,y,z), there exists a single cube which is
# either active or inactive.
# In the initial state of the pocket dimension, almost all cubes start
# inactive. The only exception to this is a small flat region of cubes (your
# puzzle input); the cubes in this region start in the specified active (#) or
# inactive (.) state.
# The energy source then proceeds to boot up by executing six cycles.
# Each cube only ever considers its neighbors: any of the 26 other cubes where
# any of their coordinates differ by at most 1. For example, given the cube at
# x=1,y=2,z=3, its neighbors include the cube at x=2,y=2,z=2, the cube at
# x=0,y=2,z=3, and so on.
# During a cycle, all cubes simultaneously change their state according to the
# following rules:
# If a cube is active and exactly 2 or 3 of its neighbors are also active,
# the cube remains active. Otherwise, the cube becomes inactive.
# If a cube is inactive but exactly 3 of its neighbors are active, the cube
# becomes active. Otherwise, the cube remains inactive.
# The engineers responsible for this experimental energy source would like you
# to simulate the pocket dimension and determine what the configuration of
# cubes should be at the end of the six-cycle boot process.
# For example, consider the following initial state:
# .#.
# ..#
# ###
# Even though the pocket dimension is 3-dimensional, this initial state
# represents a small 2-dimensional slice of it. (In particular, this initial
# state defines a 3x3x1 region of the 3-dimensional space.)
# Simulating a few cycles from this initial state produces the following
# configurations, where the result of each cycle is shown layer-by-layer at
# each given z coordinate (and the frame of view follows the active cells in
# each cycle):
# Before any cycles:
# z=0
# .#.
# ..#
# ###
# After 1 cycle:
# z=-1
# #..
# ..#
# .#.
# z=0
# #.#
# .##
# .#.
# z=1
# #..
# ..#
# .#.
# After 2 cycles:
# z=-2
# .....
# .....
# ..#..
# .....
# .....
# z=-1
# ..#..
# .#..#
# ....#
# .#...
# .....
# z=0
# ##...
# ##...
# #....
# ....#
# .###.
# z=1
# ..#..
# .#..#
# ....#
# .#...
# .....
# z=2
# .....
# .....
# ..#..
# .....
# .....
# After 3 cycles:
# z=-2
# .......
# .......
# ..##...
# ..###..
# .......
# .......
# .......
# z=-1
# ..#....
# ...#...
# #......
# .....##
# .#...#.
# ..#.#..
# ...#...
# z=0
# ...#...
# .......
# #......
# .......
# .....##
# .##.#..
# ...#...
# z=1
# ..#....
# ...#...
# #......
# .....##
# .#...#.
# ..#.#..
# ...#...
# z=2
# .......
# .......
# ..##...
# ..###..
# .......
# .......
# .......
# After the full six-cycle boot process completes, 112 cubes are left in the
# active state.
# Starting with your given initial configuration, simulate six cycles. How many
# cubes are left in the active state after the sixth cycle?
import itertools as iter
with open("files/P17.txt", "r") as f:
init_state = [line for line in f.read().strip().split("\n")]
def get_active_points(dim: int):
ap = set()
for y, z in enumerate(init_state):
for x, c in enumerate(z):
if c == "#":
ap.add(tuple([x, y] + [0] * (dim - 2)))
return ap
def part_1() -> None:
active_points = get_active_points(dim=3)
for it in range(6):
new_active_points = set()
# check x,y,z point
for x in range(-10 - it, it + 10):
for y in range(-10 - it, it + 10):
for z in range(-2 - it, it + 2):
point = (x, y, z)
# for the current point, check the neighbors
num_actives = 0
for delta in iter.product(range(-1, 2), repeat=3):
if delta != (0,) * 3:
if (
tuple([a + b for a, b in zip(point, delta)])
in active_points
):
num_actives += 1
# apply rules
if point in active_points and (
num_actives == 2 or num_actives == 3
):
new_active_points.add(point)
if point not in active_points and num_actives == 3:
new_active_points.add(point)
# next iteration
active_points = new_active_points
print(f"After 6 cycles in 3D, we have {len(active_points)} active cubes")
if __name__ == "__main__":
part_1()