|
|
@@ -0,0 +1,39 @@
|
|
|
+#!/usr/bin/env python3
|
|
|
+import sys
|
|
|
+from functools import reduce
|
|
|
+
|
|
|
+def parse(line):
|
|
|
+ left, right = line.rstrip().split('~')
|
|
|
+ xs, ys, zs = map(int, left.split(','))
|
|
|
+ xe, ye, ze = map(int, right.split(','))
|
|
|
+ return [(x, y, z) for x in range(xs, xe + 1)
|
|
|
+ for y in range(ys, ye + 1)
|
|
|
+ for z in range(zs, ze + 1)]
|
|
|
+
|
|
|
+def drop(i, brick, stack):
|
|
|
+ air = 0
|
|
|
+ while not any(z - air == 1 or (x, y, z - air - 1) in stack
|
|
|
+ for x, y, z in brick):
|
|
|
+ air += 1
|
|
|
+ for x, y, z in brick:
|
|
|
+ stack[(x, y, z - air)] = i
|
|
|
+ base = stack.get((x, y, z - air - 1), i)
|
|
|
+ if base != i:
|
|
|
+ yield base
|
|
|
+
|
|
|
+def disintegrate(bricks):
|
|
|
+ bricks = sorted(bricks, key=lambda brick: min(z for x, y, z in brick))
|
|
|
+ stack = {}
|
|
|
+ supports = [set(drop(i, brick, stack)) for i, brick in enumerate(bricks)]
|
|
|
+ dom = [set(range(len(bricks))) for _ in bricks]
|
|
|
+ lens = [0] * len(dom)
|
|
|
+ while any(len(d) != l for d, l in zip(dom, lens)):
|
|
|
+ lens = list(map(len, dom))
|
|
|
+ dom = [{i} | reduce(set.intersection, map(dom.__getitem__, supp))
|
|
|
+ if supp else {i} for i, supp in enumerate(supports)]
|
|
|
+ for i in range(len(dom)):
|
|
|
+ yield sum(i in d for j, d in enumerate(dom) if j != i)
|
|
|
+
|
|
|
+would_fall = list(disintegrate(map(parse, sys.stdin)))
|
|
|
+print(would_fall.count(0))
|
|
|
+print(sum(would_fall))
|