108 lines
2.6 KiB
Python
108 lines
2.6 KiB
Python
from lib import get_data, Grid2D, add2
|
|
from collections import defaultdict
|
|
|
|
|
|
data = get_data(__file__)
|
|
|
|
g = Grid2D(data)
|
|
seen = set()
|
|
while True:
|
|
h = g.hash()
|
|
if h in seen:
|
|
break
|
|
else:
|
|
seen.add(h)
|
|
|
|
gn = g.clone_with_val(".")
|
|
for r in range(g.n_rows):
|
|
for c in range(g.n_cols):
|
|
p = (r, c)
|
|
nb_bugs = sum(1 for nb in g.neighbors_ort(p) if g[nb] == "#")
|
|
if g[p] == "#" and nb_bugs == 1:
|
|
gn[p] = "#"
|
|
if g[p] == "." and nb_bugs in [1, 2]:
|
|
gn[p] = "#"
|
|
g = gn
|
|
|
|
|
|
t = 0
|
|
p = 1
|
|
for r in range(g.n_rows):
|
|
for c in range(g.n_cols):
|
|
if g[(r, c)] == "#":
|
|
t += p
|
|
p *= 2
|
|
print(t)
|
|
|
|
N = (-1, 0)
|
|
E = (0, 1)
|
|
S = (1, 0)
|
|
W = (0, -1)
|
|
DIRS = [N, E, S, W]
|
|
ROW, COL = 0, 1
|
|
|
|
# data = get_data(__file__)
|
|
g = Grid2D(data)
|
|
bugs = [(0, r, c) for (r, c) in g.find("#")]
|
|
middle = (g.n_rows // 2, g.n_cols // 2)
|
|
rows, cols = g.n_rows, g.n_cols
|
|
|
|
|
|
def get_edge(side):
|
|
edges = {
|
|
S: [(0, c) for c in range(cols)],
|
|
N: [(rows - 1, c) for c in range(cols)],
|
|
W: [(r, cols - 1) for r in range(rows)],
|
|
E: [(r, 0) for r in range(rows)],
|
|
}
|
|
return edges[side]
|
|
|
|
|
|
def get_neighbors(pos):
|
|
level, row, col = pos
|
|
neighbors = []
|
|
|
|
for d in DIRS:
|
|
nb = add2((row, col), d)
|
|
if nb == middle:
|
|
for ir, ic in get_edge(d):
|
|
neighbors.append((level - 1, ir, ic))
|
|
elif nb[ROW] in {-1, rows} or nb[COL] in {-1, cols}:
|
|
nr, nc = nb
|
|
if nr == -1:
|
|
neighbors.append((level + 1, *add2(middle, N)))
|
|
if nr == rows:
|
|
neighbors.append((level + 1, *add2(middle, S)))
|
|
if nc == -1:
|
|
neighbors.append((level + 1, *add2(middle, W)))
|
|
if nc == cols:
|
|
neighbors.append((level + 1, *add2(middle, E)))
|
|
else:
|
|
nr, nc = nb
|
|
neighbors.append((level, nr, nc))
|
|
return neighbors
|
|
|
|
|
|
assert len(get_neighbors((0, 1, 1))) == 4
|
|
assert len(get_neighbors((0, 3, 3))) == 4
|
|
assert len(get_neighbors((0, 0, 3))) == 4
|
|
assert len(get_neighbors((0, 0, 4))) == 4
|
|
assert len(get_neighbors((0, 2, 3))) == 8
|
|
|
|
for _ in range(200):
|
|
neighbors = defaultdict(int)
|
|
current_bugs = set(bugs)
|
|
for pos in bugs:
|
|
for nb in get_neighbors(pos):
|
|
neighbors[nb] += 1
|
|
|
|
new_bugs = []
|
|
for pos, count in neighbors.items():
|
|
if pos in current_bugs and count == 1:
|
|
new_bugs.append(pos)
|
|
if pos not in current_bugs and count in [1, 2]:
|
|
new_bugs.append(pos)
|
|
bugs = new_bugs
|
|
|
|
print(len(bugs))
|