85 lines
1.6 KiB
Python
85 lines
1.6 KiB
Python
|
import copy
|
||
|
from pprint import pprint
|
||
|
|
||
|
|
||
|
class PuzzleSolver:
|
||
|
def __init__(self, filename):
|
||
|
self.load(filename)
|
||
|
|
||
|
def load(self, filename):
|
||
|
with open(filename, "r", encoding="utf-8") as f:
|
||
|
self.data = [list(x.rstrip()) for x in f.readlines()]
|
||
|
self.width = len(self.data[0])
|
||
|
self.height = len(self.data)
|
||
|
|
||
|
def occupied_adjacent(self, x, y):
|
||
|
n = 0
|
||
|
for j in range(y-1, y+2):
|
||
|
for i in range(x-1, x+2):
|
||
|
if (i, j) == (x, y):
|
||
|
continue
|
||
|
if not (0 <= i < self.width):
|
||
|
continue
|
||
|
if not (0 <= j < self.height):
|
||
|
continue
|
||
|
|
||
|
s = self.get(i, j)
|
||
|
if s == "#":
|
||
|
n += 1
|
||
|
|
||
|
return n
|
||
|
|
||
|
def get(self, x, y):
|
||
|
return self.data[y][x]
|
||
|
|
||
|
def mutate(self):
|
||
|
ret = copy.deepcopy(self.data)
|
||
|
for y in range(self.height):
|
||
|
for x in range(self.width):
|
||
|
s = self.get(x, y)
|
||
|
if s == ".":
|
||
|
continue
|
||
|
|
||
|
n = self.occupied_adjacent(x, y)
|
||
|
if s == "L":
|
||
|
if n == 0:
|
||
|
ret[y][x] = "#"
|
||
|
elif s == "#":
|
||
|
if n >= 4:
|
||
|
ret[y][x] = "L"
|
||
|
|
||
|
return ret
|
||
|
|
||
|
def print(self):
|
||
|
for y in range(self.height):
|
||
|
print("".join(self.data[y]))
|
||
|
print()
|
||
|
|
||
|
def solve(self):
|
||
|
stable = False
|
||
|
rounds = 0
|
||
|
self.print()
|
||
|
while not stable:
|
||
|
x = self.mutate()
|
||
|
stable = x == self.data
|
||
|
self.data = x
|
||
|
rounds += 1
|
||
|
|
||
|
self.print()
|
||
|
|
||
|
return rounds
|
||
|
|
||
|
def count_occupied(self):
|
||
|
return sum([x.count("#") for x in self.data])
|
||
|
|
||
|
|
||
|
ps = PuzzleSolver("test.txt")
|
||
|
rounds = ps.solve()
|
||
|
cs = PuzzleSolver("test-1.txt")
|
||
|
assert ps.data == cs.data
|
||
|
|
||
|
ps = PuzzleSolver("data.txt")
|
||
|
rounds = ps.solve()
|
||
|
n = ps.count_occupied()
|
||
|
print(f"There are {n} occupied seats.")
|