| 123456789101112131415161718192021222324252627282930313233343536373839 |
- #!/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))
|