aoc2022/d23/run.co.py

53 lines
1.6 KiB
Python

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 = can1 and can2 and can3
canS = can5 and can6 and can7
canW = can7 and can8 and can1
canE = can3 and can4 and can5
if all((canN, canS, canW, canE)): # far away
continue
if not any((canN, canS, canW, canE)): # all packed
continue
moves = (((y-1,x),canN), ((y+1,x),canS), ((y,x-1),canW), ((y,x+1),canE))
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[1], moves))[0]
#p:Tuple[int,int] = next(filter(lambda m: m[1], (moves[(r+i)%4] for i in (0,1,2,3)) ))[0] # using generator is slower than a tuple in codon ^^
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