2023 day 22.
This commit is contained in:
parent
c496ea25c9
commit
af2fbf2da1
@ -1,13 +1,111 @@
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
|
||||
logging.basicConfig(level=logging.INFO if VERBOSE else logging.WARNING)
|
||||
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
|
||||
def _name(i: int) -> str:
|
||||
if len(lines) < 26:
|
||||
return string.ascii_uppercase[i]
|
||||
return f"B{i:04d}"
|
||||
|
||||
|
||||
def build_supports(
|
||||
bricks: list[tuple[tuple[int, int, int], tuple[int, int, int]]]
|
||||
) -> tuple[dict[int, set[int]], dict[int, set[int]]]:
|
||||
# 1. compute locations where a brick of sand will land after falling by processing
|
||||
# them in sorted order of bottom z location
|
||||
levels: dict[tuple[int, int, int], int] = defaultdict(lambda: -1)
|
||||
for i_brick, ((sx, sy, sz), (ex, ey, ez)) in enumerate(bricks):
|
||||
assert sx <= ex and sy <= ey and sz <= ez
|
||||
|
||||
xs, ys = range(sx, ex + 1), range(sy, ey + 1)
|
||||
|
||||
for z in range(sz - 1, 0, -1):
|
||||
if any(levels[x, y, z] >= 0 for x, y in itertools.product(xs, ys)):
|
||||
break
|
||||
sz, ez = sz - 1, ez - 1
|
||||
|
||||
bricks[i_brick] = ((sx, sy, sz), (ex, ey, ez))
|
||||
zs = range(sz, ez + 1)
|
||||
|
||||
for x, y, z in itertools.product(xs, ys, zs):
|
||||
levels[x, y, z] = i_brick
|
||||
|
||||
# 2. compute the bricks that supports any brick
|
||||
supported_by: dict[int, set[int]] = {}
|
||||
supports: dict[int, set[int]] = {i_brick: set() for i_brick in range(len(bricks))}
|
||||
for i_brick, ((sx, sy, sz), (ex, ey, ez)) in enumerate(bricks):
|
||||
name = _name(i_brick)
|
||||
|
||||
supported_by[i_brick] = {
|
||||
v
|
||||
for x, y in itertools.product(range(sx, ex + 1), range(sy, ey + 1))
|
||||
if (v := levels[x, y, sz - 1]) != -1
|
||||
}
|
||||
logging.info(
|
||||
f"{name} supported by {', '.join(map(_name, supported_by[i_brick]))}"
|
||||
)
|
||||
|
||||
for support in supported_by[i_brick]:
|
||||
supports[support].add(i_brick)
|
||||
|
||||
return supported_by, supports
|
||||
|
||||
|
||||
bricks: list[tuple[tuple[int, int, int], tuple[int, int, int]]] = []
|
||||
for line in lines:
|
||||
bricks.append(
|
||||
(
|
||||
tuple(int(c) for c in line.split("~")[0].split(",")), # type: ignore
|
||||
tuple(int(c) for c in line.split("~")[1].split(",")), # type: ignore
|
||||
)
|
||||
)
|
||||
|
||||
# sort bricks by bottom z position to compute supports
|
||||
bricks = sorted(bricks, key=lambda b: b[0][-1])
|
||||
supported_by, supports = build_supports(bricks)
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
answer_1 = len(bricks) - sum(
|
||||
any(len(supported_by[supported]) == 1 for supported in supports_to)
|
||||
for supports_to in supports.values()
|
||||
)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
falling_in_chain: dict[int, set[int]] = {}
|
||||
for i_brick in range(len(bricks)):
|
||||
to_disintegrate: set[int] = {
|
||||
supported
|
||||
for supported in supports[i_brick]
|
||||
if len(supported_by[supported]) == 1
|
||||
}
|
||||
|
||||
supported_by_copy = dict(supported_by)
|
||||
|
||||
falling_in_chain[i_brick] = set()
|
||||
while to_disintegrate:
|
||||
falling_in_chain[i_brick].update(to_disintegrate)
|
||||
|
||||
to_disintegrate_v: set[int] = set()
|
||||
|
||||
for d_brick in to_disintegrate:
|
||||
for supported in supports[d_brick]:
|
||||
supported_by_copy[supported] = supported_by_copy[supported] - {d_brick}
|
||||
|
||||
if not supported_by_copy[supported]:
|
||||
to_disintegrate_v.add(supported)
|
||||
|
||||
to_disintegrate = to_disintegrate_v
|
||||
|
||||
answer_2 = sum(len(falling) for falling in falling_in_chain.values())
|
||||
print(f"answer 2 is {answer_2}")
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
1,0,1~1,2,1
|
||||
0,0,2~2,0,2
|
||||
0,2,3~2,2,3
|
||||
0,0,4~0,2,4
|
||||
2,0,5~2,2,5
|
||||
0,1,6~2,1,6
|
||||
1,1,8~1,1,9
|
Loading…
Reference in New Issue
Block a user