112 lines
3.2 KiB
Python
112 lines
3.2 KiB
Python
|
|
from solutions import BaseSolution
|
||
|
|
|
||
|
|
|
||
|
|
class Solution(BaseSolution):
|
||
|
|
input_file = "11.txt"
|
||
|
|
|
||
|
|
directions = [
|
||
|
|
(-1, -1), # NW
|
||
|
|
(0, -1), # N
|
||
|
|
(1, -1), # NE
|
||
|
|
(-1, 0), # W
|
||
|
|
(1, 0), # E
|
||
|
|
(-1, 1), # SW
|
||
|
|
(0, 1), # S
|
||
|
|
(1, 1), # SE
|
||
|
|
]
|
||
|
|
|
||
|
|
def __str__(self):
|
||
|
|
return "Day 11: Seating System"
|
||
|
|
|
||
|
|
def parse_input(self, data):
|
||
|
|
return [[*l] for l in data.split()]
|
||
|
|
|
||
|
|
def solve(self, puzzle_input):
|
||
|
|
return self.update_seats(puzzle_input)
|
||
|
|
|
||
|
|
def solve_again(self, puzzle_input):
|
||
|
|
return self.update_seats(puzzle_input, tolerance=5, in_view=True)
|
||
|
|
|
||
|
|
def update_seats(self, seats, tolerance=4, in_view=False):
|
||
|
|
maxy = len(seats)
|
||
|
|
maxx = len(seats[0])
|
||
|
|
|
||
|
|
states = [seats]
|
||
|
|
|
||
|
|
keep_alive = True
|
||
|
|
rearranged = [s[:] for s in seats]
|
||
|
|
while keep_alive:
|
||
|
|
current = states[-1]
|
||
|
|
rearranged = self.tick(current, maxy, maxx, tolerance, in_view)
|
||
|
|
states.append([r[:] for r in rearranged])
|
||
|
|
if current == rearranged:
|
||
|
|
keep_alive = False
|
||
|
|
|
||
|
|
return len(
|
||
|
|
[*filter(lambda x: x == "#", "".join(["".join(r) for r in rearranged]))]
|
||
|
|
)
|
||
|
|
|
||
|
|
def tick(self, current, maxy, maxx, tolerance, in_view):
|
||
|
|
rearranged = [s[:] for s in current]
|
||
|
|
for y in range(maxy):
|
||
|
|
for x in range(maxx):
|
||
|
|
v = current[y][x]
|
||
|
|
if v == ".":
|
||
|
|
continue
|
||
|
|
if in_view:
|
||
|
|
adjacent = self.get_in_view(current, y, x)
|
||
|
|
else:
|
||
|
|
adjacent = self.get_adjacent(current, y, x)
|
||
|
|
adjval = [a for _, a in adjacent]
|
||
|
|
if v == "L":
|
||
|
|
v = self.occupy_if_empty(v, adjval)
|
||
|
|
else:
|
||
|
|
v = self.empty_if_occupied(v, adjval, tolerance)
|
||
|
|
rearranged[y][x] = v
|
||
|
|
return rearranged
|
||
|
|
|
||
|
|
def get_adjacent(self, seats, posy, posx, directions=None, factor=1):
|
||
|
|
adjacent = []
|
||
|
|
|
||
|
|
directions = directions or self.directions[:]
|
||
|
|
|
||
|
|
for x, y in directions:
|
||
|
|
r = y * factor + posy
|
||
|
|
c = x * factor + posx
|
||
|
|
if r < 0 or c < 0:
|
||
|
|
continue
|
||
|
|
try:
|
||
|
|
adjacent.append(((x, y), seats[r][c]))
|
||
|
|
except IndexError:
|
||
|
|
pass
|
||
|
|
return adjacent
|
||
|
|
|
||
|
|
def get_in_view(self, seats, posy, posx):
|
||
|
|
found = []
|
||
|
|
directions = True
|
||
|
|
distance = 1
|
||
|
|
directions = self.directions[:]
|
||
|
|
while directions:
|
||
|
|
adjacents = self.get_adjacent(
|
||
|
|
seats, posy, posx, directions, factor=distance
|
||
|
|
)
|
||
|
|
found += [a for a in adjacents if a[1] != "."]
|
||
|
|
directions = [a[0] for a in adjacents if a[1] == "."]
|
||
|
|
distance += 1
|
||
|
|
return found
|
||
|
|
|
||
|
|
def occupy_if_empty(self, seat, neighbours):
|
||
|
|
if seat == "L" and not any(n == "#" for n in neighbours):
|
||
|
|
return "#"
|
||
|
|
return seat
|
||
|
|
|
||
|
|
def empty_if_occupied(self, seat, neighbours, tolerance=4):
|
||
|
|
if seat == "#" and sum(map(lambda s: s == "#", neighbours)) >= tolerance:
|
||
|
|
return "L"
|
||
|
|
return seat
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
solution = Solution()
|
||
|
|
solution.show_results()
|