Day 11 (ugly)
This commit is contained in:
parent
cbedbccd57
commit
1b09653fcc
73
2020/day11.py
Normal file
73
2020/day11.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from grid import Grid, near8
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
lines = [line.rstrip() for line in sys.stdin]
|
||||||
|
|
||||||
|
# Part 1
|
||||||
|
g = Grid(value_factory=lambda: ".", lines=lines)
|
||||||
|
while update(g):
|
||||||
|
pass
|
||||||
|
print("Occupied:", sum(v == "#" for _, _, v in g.values_gen()))
|
||||||
|
|
||||||
|
# Part 2
|
||||||
|
g = Grid(value_factory=lambda: ".", lines=lines)
|
||||||
|
while update2(g):
|
||||||
|
pass
|
||||||
|
print("Occupied part 2:", sum(v == "#" for _, _, v in g.values_gen()))
|
||||||
|
|
||||||
|
|
||||||
|
def update(g):
|
||||||
|
changes = {}
|
||||||
|
for x, y, v in g.values_gen():
|
||||||
|
if v == ".":
|
||||||
|
continue
|
||||||
|
p = (x, y)
|
||||||
|
n = list(g.near_objects(p, near_f=near8).values())
|
||||||
|
if v == "L" and n.count("#") == 0:
|
||||||
|
changes[p] = "#"
|
||||||
|
elif v == "#" and n.count("#") >= 4:
|
||||||
|
changes[p] = "L"
|
||||||
|
for (x, y), v in changes.items():
|
||||||
|
g.setv(x, y, v)
|
||||||
|
return bool(changes)
|
||||||
|
|
||||||
|
|
||||||
|
RAYS_OFS = [
|
||||||
|
(-1, -1), ( 0, -1), ( 1, -1),
|
||||||
|
(-1, 0), ( 1, 0),
|
||||||
|
(-1, 1), ( 0, 1), ( 1, 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def update2(g):
|
||||||
|
changes = {}
|
||||||
|
for x, y, v in g.values_gen():
|
||||||
|
if v == ".":
|
||||||
|
continue
|
||||||
|
occ = 0
|
||||||
|
for ox, oy in RAYS_OFS:
|
||||||
|
n = 1
|
||||||
|
while True:
|
||||||
|
qx, qy = x + ox * n, y + oy * n
|
||||||
|
if not g.hasv(qx, qy):
|
||||||
|
break
|
||||||
|
if (rv := g.getv(qx, qy)) == "#":
|
||||||
|
occ += 1
|
||||||
|
break
|
||||||
|
elif rv == "L":
|
||||||
|
break
|
||||||
|
n += 1
|
||||||
|
if v == "L" and occ == 0:
|
||||||
|
changes[(x, y)] = "#"
|
||||||
|
elif v == "#" and occ >= 5:
|
||||||
|
changes[(x, y)] = "L"
|
||||||
|
for (x, y), v in changes.items():
|
||||||
|
g.setv(x, y, v)
|
||||||
|
return bool(changes)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
47
2020/grid.py
47
2020/grid.py
|
@ -3,6 +3,30 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
def near(p):
|
||||||
|
"""Return a tuple of neighbor positions (up, left, down, right)."""
|
||||||
|
return (
|
||||||
|
(p[0] , p[1] - 1),
|
||||||
|
(p[0] + 1, p[1] ),
|
||||||
|
(p[0] , p[1] + 1),
|
||||||
|
(p[0] - 1, p[1] ),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def near8(p):
|
||||||
|
"""Return a tuple of neighbor positions, including diagonals."""
|
||||||
|
return (
|
||||||
|
(p[0] - 1, p[1] - 1),
|
||||||
|
(p[0] , p[1] - 1),
|
||||||
|
(p[0] + 1, p[1] - 1),
|
||||||
|
(p[0] - 1, p[1] ),
|
||||||
|
(p[0] + 1, p[1] ),
|
||||||
|
(p[0] - 1, p[1] + 1),
|
||||||
|
(p[0] , p[1] + 1),
|
||||||
|
(p[0] + 1, p[1] + 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Grid:
|
class Grid:
|
||||||
|
|
||||||
def __init__(self, value_factory=int, lines=None):
|
def __init__(self, value_factory=int, lines=None):
|
||||||
|
@ -10,6 +34,9 @@ class Grid:
|
||||||
if lines:
|
if lines:
|
||||||
self.load(lines)
|
self.load(lines)
|
||||||
|
|
||||||
|
def hasv(self, x, y):
|
||||||
|
return y in self.g and x in self.g[y]
|
||||||
|
|
||||||
def getv(self, x, y):
|
def getv(self, x, y):
|
||||||
return self.g[y][x]
|
return self.g[y][x]
|
||||||
|
|
||||||
|
@ -26,9 +53,12 @@ class Grid:
|
||||||
for x, v in row.items():
|
for x, v in row.items():
|
||||||
yield (x, y, v)
|
yield (x, y, v)
|
||||||
|
|
||||||
def near_objects(self, p):
|
def near_objects(self, p, near_f=near):
|
||||||
"""Return a dict of neighbor positions to values (U, L, D, R)."""
|
return {
|
||||||
return {q: self.g[q[1]][q[0]] for q in Grid.near(p)}
|
q: self.getv(q[0], q[1])
|
||||||
|
for q in near_f(p)
|
||||||
|
if self.hasv(q[0], q[1]) # do not create entries.
|
||||||
|
}
|
||||||
|
|
||||||
def dumb_print(self, f=lambda v: v):
|
def dumb_print(self, f=lambda v: v):
|
||||||
for row in self.g.values():
|
for row in self.g.values():
|
||||||
|
@ -37,19 +67,8 @@ class Grid:
|
||||||
print()
|
print()
|
||||||
|
|
||||||
def print_near(self, p, view_size=2):
|
def print_near(self, p, view_size=2):
|
||||||
"""Print near values in an area of view_size. Works iff keys support addition."""
|
|
||||||
for dy in range(-view_size, view_size + 1):
|
for dy in range(-view_size, view_size + 1):
|
||||||
print("".join([
|
print("".join([
|
||||||
self.g[p[1] + dy][p[0] + dx]
|
self.g[p[1] + dy][p[0] + dx]
|
||||||
for dx in range(-view_size, view_size + 1)
|
for dx in range(-view_size, view_size + 1)
|
||||||
]))
|
]))
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def near(p):
|
|
||||||
"""Return a tuple of neighbor positions (up, left, down, right)."""
|
|
||||||
return (
|
|
||||||
(p[0] , p[1] - 1),
|
|
||||||
(p[0] + 1, p[1] ),
|
|
||||||
(p[0] , p[1] + 1),
|
|
||||||
(p[0] - 1, p[1] ),
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in a new issue