import sys from typing import Tuple E = { (y,x) for y,l in enumerate(sys.stdin.read().splitlines()) for x,c in enumerate(l) if c == '#' } def dim(): minx = min(x for (_,x) in E) maxx = max(x for (_,x) in E) miny = min(y for (y,_) in E) maxy = max(y for (y,_) in E) return (maxx-minx+1,maxy-miny+1) # W,H MARK = (-9999,-9999) for r in range(int(sys.argv[1])): # rounds P = dict() # { new_pos: old_pos } for (y,x) in E: # for each elve can1 = (y-1,x-1) not in E can2 = (y-1,x) not in E can3 = (y-1,x+1) not in E can4 = (y,x+1) not in E can5 = (y+1,x+1) not in E can6 = (y+1,x) not in E can7 = (y+1,x-1) not in E can8 = (y,x-1) not in E canN = (y-1,x) if can1 and can2 and can3 else None canS = (y+1,x) if can5 and can6 and can7 else None canW = (y,x-1) if can7 and can8 and can1 else None canE = (y,x+1) if can3 and can4 and can5 else None moves = [canN, canS, canW, canE] moves = [moves[(r+0)%4], moves[(r+1)%4], moves[(r+2)%4], moves[(r+3)%4]] if all(m is not None for m in moves): # far away continue if all(m is None for m in moves): # all packed continue #moves = [moves[(r+0)%4], moves[(r+1)%4], moves[(r+2)%4], moves[(r+3)%4]] p:Tuple[int,int] = next(filter(lambda m: m is not None ,moves)) #p:Tuple[int,int] = next(filter(lambda m: m is not None, (moves[(r+i)%4] for i in (0,1,2,3)) )) if p not in P: # can move P[p] = (y,x) else: # occupied, invalidate move for all P[p] = MARK moved = { v for k,v in P.items() if v != MARK } newpos = { k for k,v in P.items() if v != MARK } if r+1 == 10: (W,H) = dim() print(W, H, W * H - len(E)) if len(newpos) == 0: (W,H) = dim() print(f"no move after {r+1}, {W}, {H}") break E = (E - moved) | newpos