diff --git a/src/P11.py b/src/P11.py index 7e731c6..15735e5 100644 --- a/src/P11.py +++ b/src/P11.py @@ -172,5 +172,196 @@ def part_1(seats: list[str]) -> None: print(f"There are {free_seats(seats)} seats occupied") +# --- Part Two --- + +# As soon as people start to arrive, you realize your mistake. People don't +# just care about adjacent seats - they care about the first seat they can see +# in each of those eight directions! + +# Now, instead of considering just the eight immediately adjacent seats, +# consider the first seat in each of those eight directions. For example, the +# empty seat below would see eight occupied seats: + +# .......#. +# ...#..... +# .#....... +# ......... +# ..#L....# +# ....#.... +# ......... +# #........ +# ...#..... + +# The leftmost empty seat below would only see one empty seat, but cannot see +# any of the occupied ones: + +# ............. +# .L.L.#.#.#.#. +# ............. + +# The empty seat below would see no occupied seats: + +# .##.##. +# #.#.#.# +# ##...## +# ...L... +# ##...## +# #.#.#.# +# .##.##. + +# Also, people seem to be more tolerant than you expected: it now takes five or +# more visible occupied seats for an occupied seat to become empty (rather than +# four or more from the previous rules). The other rules still apply: empty +# seats that see no occupied seats become occupied, seats matching no rule +# don't change, and floor never changes. + +# Given the same starting layout as above, these new rules cause the seating +# area to shift around as follows: + +# L.LL.LL.LL +# LLLLLLL.LL +# L.L.L..L.. +# LLLL.LL.LL +# L.LL.LL.LL +# L.LLLLL.LL +# ..L.L..... +# LLLLLLLLLL +# L.LLLLLL.L +# L.LLLLL.LL + +# #.##.##.## +# #######.## +# #.#.#..#.. +# ####.##.## +# #.##.##.## +# #.#####.## +# ..#.#..... +# ########## +# #.######.# +# #.#####.## + +# #.LL.LL.L# +# #LLLLLL.LL +# L.L.L..L.. +# LLLL.LL.LL +# L.LL.LL.LL +# L.LLLLL.LL +# ..L.L..... +# LLLLLLLLL# +# #.LLLLLL.L +# #.LLLLL.L# + +# #.L#.##.L# +# #L#####.LL +# L.#.#..#.. +# ##L#.##.## +# #.##.#L.## +# #.#####.#L +# ..#.#..... +# LLL####LL# +# #.L#####.L +# #.L####.L# + +# #.L#.L#.L# +# #LLLLLL.LL +# L.L.L..#.. +# ##LL.LL.L# +# L.LL.LL.L# +# #.LLLLL.LL +# ..L.L..... +# LLLLLLLLL# +# #.LLLLL#.L +# #.L#LL#.L# + +# #.L#.L#.L# +# #LLLLLL.LL +# L.L.L..#.. +# ##L#.#L.L# +# L.L#.#L.L# +# #.L####.LL +# ..#.#..... +# LLL###LLL# +# #.LLLLL#.L +# #.L#LL#.L# + +# #.L#.L#.L# +# #LLLLLL.LL +# L.L.L..#.. +# ##L#.#L.L# +# L.L#.LL.L# +# #.LLLL#.LL +# ..#.L..... +# LLL###LLL# +# #.LLLLL#.L +# #.L#LL#.L# + +# Again, at this point, people stop shifting around and the seating area +# reaches equilibrium. Once this occurs, you count 26 occupied seats. + +# Given the new visibility method and the rule change for occupied seats +# becoming empty, once equilibrium is reached, how many seats end up occupied? + + +def seats_around_mod(seats: list[str], r: int, c: int) -> int: + total = 0 + around_me = [ + (-1, -1), + (-1, 0), + (-1, 1), + (0, -1), + (0, 1), + (1, -1), + (1, 0), + (1, 1), + ] + for row, col in around_me: + _row = r + row + _col = c + col + while ( + _row >= 0 + and _row < len(seats) + and _col < len(seats[c]) + and seats[_row][_col] == "." + ): + _row += row + _col += col + if ( + _row >= 0 + and _row < len(seats) + and _col >= 0 + and _col < len(seats[c]) + ): + total += seats[_row][_col] == "#" + return total + + +def part_2(seats: list[str]) -> None: + R = len(seats) + C = len(seats[0]) + while True: + has_changed = False + next_iter = [] + for r in range(R): + new_row = "" + for c in range(C): + seat = seats[r][c] + if seat != ".": + occupants = seats_around_mod(seats, r, c) + if seat == "L" and occupants == 0: + seat = "#" + has_changed = True + elif seat == "#" and occupants >= 5: + seat = "L" + has_changed = True + new_row += seat + next_iter.append(new_row) + if not has_changed: + break + seats = next_iter + + print(f"There are {free_seats(seats)} seats occupied") + + if __name__ == "__main__": part_1(seats) + part_2(seats)