mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2024-11-17 10:30:29 +01:00
100 lines
2.7 KiB
Python
100 lines
2.7 KiB
Python
from os.path import join, dirname
|
|
from typing import List, Optional
|
|
from itertools import product
|
|
from copy import deepcopy
|
|
|
|
TSeats = List[List[Optional[bool]]]
|
|
|
|
mapping = {
|
|
'.': None,
|
|
'#': True,
|
|
'L': False
|
|
}
|
|
inv = {v: k for k, v in mapping.items()}
|
|
|
|
|
|
class Seats:
|
|
p = [-1, 0, 1]
|
|
|
|
def __init__(self, plan: str, alt: bool = False) -> None:
|
|
self.seats: TSeats = [
|
|
[
|
|
mapping[seat]
|
|
for seat in row
|
|
]
|
|
for row in plan.strip().split('\n')
|
|
]
|
|
self.max_x = len(self.seats[0])
|
|
self.max_y = len(self.seats)
|
|
self.alt = alt
|
|
|
|
def __str__(self) -> str:
|
|
return '\n'.join([
|
|
''.join([inv[seat] for seat in row])
|
|
for row in self.seats
|
|
])
|
|
|
|
def find_next_in_direction(self, y: int, x: int, dy: int, dx: int) -> Optional[bool]:
|
|
y += dy
|
|
x += dx
|
|
while 0 <= x < self.max_x and 0 <= y < self.max_y:
|
|
cur = self.seats[y][x]
|
|
if cur is not None:
|
|
return cur
|
|
y += dy
|
|
x += dx
|
|
return None
|
|
|
|
def get_occupied(self, y: int, x: int,) -> int:
|
|
occupied = 0
|
|
for dx, dy in product(self.p, self.p):
|
|
if dx == 0 and dy == 0:
|
|
continue
|
|
if self.alt and self.find_next_in_direction(y, x, dy, dx) == True:
|
|
occupied += 1
|
|
else:
|
|
dx += x
|
|
dy += y
|
|
if 0 <= dx < self.max_x and 0 <= dy < self.max_y and self.seats[dy][dx]:
|
|
occupied += 1
|
|
return occupied
|
|
|
|
def iteration(self) -> int:
|
|
changed = 0
|
|
future: TSeats = deepcopy(self.seats)
|
|
required_to_leave = 4 if self.alt else 3
|
|
for y, x in product(range(self.max_y), range(self.max_x)):
|
|
current = self.seats[y][x]
|
|
if current == None:
|
|
continue
|
|
occupied = self.get_occupied(y, x)
|
|
if (current == True and occupied > required_to_leave) or (current == False and occupied == 0):
|
|
future[y][x] = not current
|
|
changed += 1
|
|
self.seats = future
|
|
return changed
|
|
|
|
def count_occupied(self) -> int:
|
|
return sum([
|
|
sum([
|
|
1 if seat == True else 0
|
|
for seat in row
|
|
])
|
|
for row in self.seats
|
|
])
|
|
|
|
def find_equilibrium(self) -> int:
|
|
while self.iteration() > 0:
|
|
pass
|
|
return self.count_occupied()
|
|
|
|
|
|
data = join(dirname(__file__), '../data.txt')
|
|
with open(data) as f:
|
|
txt = f.read()
|
|
seats = Seats(txt)
|
|
print(seats.find_equilibrium())
|
|
|
|
seats = Seats(txt, True)
|
|
print(seats.find_equilibrium())
|