advent2023/animate_ten.py

92 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
import cv2 as cv
from useful import *
bit = {(-1, 0): 8,
(1, 0): 4,
(0, -1): 2,
(0, 1): 1}
udlr = {'|': 12, # 1<<3 (u) + 1<<2 (d)
'J': 10,
'L': 9,
'7': 6,
'F': 5,
'-': 3,
'.': 0,
'S': 65535}
cs = [[udlr[c] for c in l] for l in lines(open(0))]
ca = np.pad(np.array(cs, dtype=int), 1)
visited = np.zeros(ca.shape, dtype=int)
pos = next(zip(*np.nonzero(ca == 65535)))
def sub(a, b):
return (a[0] - b[0], a[1] - b[1])
def neg(a):
return (-a[0], -a[1])
def cango(origin, step):
test = sub(origin, step) # note: subtraction to match udlr
return ca[test] & bit[step] and ca[origin] & bit[neg(step)] and not visited[test]
def draw(uptofour, linger=16): # different colors:
# blank, faded, pipe, special
palette = [(x & 255, x >> 8 & 255, x >> 16)
for x in [0x7f9aa5, 0x74878f, 0x433c34, 0xae8c67]]
colored = np.transpose(np.asarray(np.vectorize(
lambda x: palette[x])(
uptofour[3:-3,3:-3])), axes=(1, 2, 0)).astype('uint8')
zoom = 840 // max(colored.shape[:2])
cv.imshow('pipes', np.kron(colored, np.ones((zoom, zoom, 1), dtype='uint8')))
cv.waitKey(linger)
grill = ((np.kron(np.ones(ca.shape), np.asarray([[0, 8, 0],
[2, 15, 1],
[0, 4, 0]])).astype(int) &
np.kron(ca, np.ones((3, 3))).astype(int)) > 0).astype('uint8')
canvas = np.kron(1 + 2 * (ca == 65535), np.ones((3, 3))).astype('uint8') * grill # colorize animal
draw(canvas, linger=2000)
def drawvisit(y, x):
canvas[y*3:y*3+3,x*3:x*3+3] *= 2
canvas[y*3:y*3+3,x*3:x*3+3] %= 4
if not time % 69: # about 100 unique frames for us
draw(canvas)
time = 1
while True:
visited[pos] = time
drawvisit(*pos)
time += 1
goto = [s for s in bit.keys() if cango(pos, s)] # should give one result except in the beginning
if not goto:
break
pos = sub(pos, goto[0])
print(time // 2)
fillvas = np.kron(2 * (visited > 0), np.ones((3, 3))).astype('uint8') * grill # 2 if part of loop...
mask = np.pad(fillvas, (1,1))
for color in [4, 3, 2, 1]: # outside: 4, inside: 3
try:
empty = next(zip(*np.nonzero(fillvas == 0)))
except StopIteration: # all filled!
break
cv.floodFill(fillvas, mask, empty, color)
#assert color == 2
smallvas = fillvas[1::3,1::3]
print(len(np.where(smallvas == 3)[0]))
# also paint regardless if part of loop
fillvas *= (1 - grill)
fillvas |= (2 * grill)
fillvas %= 4
draw(canvas, linger=2000)
draw(fillvas, linger=0)