def overlaps(brick1, brick2): """reports whether two bricks overlap with each other""" # the bricks as a whole overlap if there is any overlap # on all three axes for (a,b),(x,y) in zip(brick1, brick2): if (b < x or a > y): # ranges don't overlap return False return True assert overlaps([(0,0), (1,2), (2,2)], [(0,0),(1,1),(2,3)]) assert not overlaps([(0,0), (1,1), (2,2)], [(1,1),(1,1),(2,2)]) def read_input(f): data = [] for line in f: start, end = line.split("~") start = [int(x) for x in start.split(',')] end = [int(x) for x in end .split(',')] brick = [tuple(sorted([a,b])) for a,b in zip(start,end)] data.append(brick) return data def check(data): print(data) for x in data: for y in data: if x == y: assert overlaps(x,y) else: assert not overlaps(x,y) print("ok") def solve(f): data = read_input(f) check(data) settle(data) check(data) disintegrate(data) def settle(data): def zindex(b): return b[2] data.sort(key=zindex) top = 1 for i in range(len(data)): # first, lower all blocks >i so that at least one block is at z=top minz = min(z[0] for x,y,z in data[i:]) if minz > top: print("lowering all blocks by", minz-top) for b in data[i:]: b[:] = lower(b, minz-top) # lower blocks one at a time b = data[i] n = 0 while canlower(b, data[:i]): b = lower(b) n += 1 print("lowering block %d by %d" % (i,n)) data[i] = b top = max(z[1] for x,y,z in data[:i+1]) + 1 def canlower(block, under): if block[2][0] <= 1: return False x = lower(block) for u in under: if overlaps(u, x): return False return True def disintegrate(data): print(*data, sep="\n") t = 0 #for i,x in enumerate(data): # assert not canlower(x,data[:i]) for i,x in enumerate(data): # disintegrate x # find other blocks on the same z #others = [y for y in data if x != y and not (y[2][1] < x[2][0] or y[2][0] > x[2][1])] # see if any block can be lowered # if yes, then x cannot be disintegrated candisintegrate = True for j in range(i+1, len(data)): if canlower(data[j], data[:i] + data[i+1:j]): candisintegrate = False break #ly = lower(y) #if y == ly: # continue #supports = [z for z in others if z != x and z != y and overlaps(z,ly)] #if supports: # # theer is a block that supports y # #candisintegrate = True # print('y = %s would be blocked by %d blocks' % (y, len(supports))) # pass #else: # # no block would stop y from falling # print("no blockk stops y=%s" % (y)) # candisintegrate = False # break print(i, x, candisintegrate) if candisintegrate: t += 1 print(t) return (t) def lower(brick, n=1): """lower a brick n spaces in the z direction""" x, y, z = brick if z[0] > 1: z = z[0]-1, z[1]-1 return [x, y, z] import sys solve(sys.stdin)