aoc2023/day22.py
2023-12-22 08:31:55 +01:00

87 lines
2.3 KiB
Python

from collections import defaultdict
from tools.aoc import AOCDay
from typing import Any
def get_space_below(brick: tuple[tuple], max_y: dict[tuple, int]) -> int:
below_y = 0
for x in range(brick[0][0], brick[-1][0] + 1):
for z in range(brick[0][2], brick[-1][2] + 1):
below_y = max(below_y, max_y[(x, z)])
return brick[0][1] - below_y - 1
def drop(bricks: set[tuple]) -> (set[tuple], int):
dropped_bricks = set()
max_y = defaultdict(int)
count = 0
for brick in sorted(bricks, key=lambda b: b[0][1]):
space_below = get_space_below(brick, max_y)
new_brick = tuple()
for c in brick:
new_y = c[1] - space_below
max_y[(c[0], c[2])] = max(max_y[(c[0], c[2])], new_y)
new_brick += ((c[0], new_y, c[2]),)
dropped_bricks.add(new_brick)
if space_below:
count += 1
return dropped_bricks, count
def can_disintegrate(brick: tuple, bricks: set[tuple]) -> bool:
_, count = drop(bricks - {brick})
return count == 0
def would_fall(brick: tuple, bricks: set[tuple]) -> int:
_, count = drop(bricks - {brick})
return count
class Day(AOCDay):
inputs = [
[
(5, "input22_test"),
(527, "input22"),
],
[
(7, "input22_test"),
(100376, "input22"),
]
]
def parse_input(self) -> set[tuple]:
bricks = set()
for line in self.getInput():
a, b = line.split("~")
x1, z1, y1 = map(int, a.split(","))
x2, z2, y2 = map(int, b.split(","))
bricks.add(
tuple(
(x, y, z)
for x in range(x1, x2 + 1)
for y in range(y1, y2 + 1)
for z in range(z1, z2 + 1)
)
)
return bricks
def part1(self) -> Any:
bricks = self.parse_input()
dropped_bricks, _ = drop(bricks)
return sum(can_disintegrate(x, dropped_bricks) for x in dropped_bricks)
def part2(self) -> Any:
bricks = self.parse_input()
dropped_bricks, _ = drop(bricks)
return sum(would_fall(x, dropped_bricks) for x in dropped_bricks)
if __name__ == '__main__':
day = Day(2023, 22)
day.run(verbose=True)