143 lines
4.6 KiB
Python
Executable File
143 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import cv2 as cv
|
|
|
|
from useful import *
|
|
|
|
sin = {0:0,90:-1,180:0,270:1}
|
|
cos = {0:1,90:0,180:-1,270:0}
|
|
|
|
mirrors = np.array([[{'/':45,'\\':135,'-':0,'|':90,'.':69}[c] for c in l] for l in lines(open(0))])
|
|
size = mirrors.shape[0] # w = h anyway, don't bother genericizing
|
|
done = np.zeros((size * 4, 4, size, size), dtype=bool)
|
|
|
|
verbose = len(sys.argv) > 1 and '-v' in sys.argv[1]
|
|
draw_every = 1 if verbose and '-vv' in sys.argv[1] else 666
|
|
|
|
if verbose:
|
|
"""
|
|
why aren't there single characters identifiers for top left or northwest?
|
|
let's use initials of countries: canada, soviet, brazil, australia
|
|
in addition to udlr and also "middle"
|
|
"""
|
|
initials = {letter: np.asarray(coords) / 2 for coords, letter in
|
|
np.ndenumerate(np.array(list('cuslmrbda')).reshape((3, 3)))}
|
|
mirror_rections = {45:'bs',135:'ca',0:'lr',90:'ud'}
|
|
frame = 0
|
|
cv.namedWindow('lasers', flags=cv.WINDOW_GUI_NORMAL | cv.WINDOW_AUTOSIZE)
|
|
|
|
def draw(linger=16):
|
|
global canvas, frame
|
|
for (y, x), angle in np.ndenumerate(mirrors): # just put them on top
|
|
if angle == 69:
|
|
continue
|
|
line(y, x, mirror_rections[angle], (0x7f, 0x9a, 0xa5)[::-1])
|
|
zewm = 840 // canvas.shape[0]
|
|
cv.imshow('lasers', np.kron(canvas, np.ones((zewm, zewm, 1), dtype='uint8')))
|
|
#cv.imwrite('lasers%04d.png' % frame, np.kron(canvas, np.ones((zewm, zewm, 1), dtype='uint8')))
|
|
frame += 1
|
|
cv.waitKey(linger)
|
|
|
|
def line(y, x, rection, color):
|
|
global canvas, scale
|
|
off1 = initials[rection[0]]
|
|
off2 = initials[rection[1]]
|
|
cv.line(canvas,
|
|
(x * scale + int(off1[1] * (scale - 1)),
|
|
y * scale + int(off1[0] * (scale - 1))),
|
|
(x * scale + int(off2[1] * (scale - 1)),
|
|
y * scale + int(off2[0] * (scale - 1))),
|
|
color,
|
|
1)
|
|
|
|
scale = 7
|
|
canvas = np.kron(np.ones((size * scale, size * scale, 1)),
|
|
np.asarray((0x43, 0x3c, 0x34))[::-1].reshape((1, 1, 3))).astype('uint8')
|
|
|
|
draw(1000)
|
|
|
|
def nextvel(y, x, vel):
|
|
here = mirrors[y,x]
|
|
if here == 69:
|
|
return [vel, ]
|
|
elif here == 45: # 0->90 avv, 180->270 avv: (init % 180)
|
|
return [(vel // 180) * 180 + (90 - vel % 180), ]
|
|
elif here == 135: # 0->270 avv, 180->90 avv
|
|
return [270 - vel, ]
|
|
elif here == 0:
|
|
if vel % 180 == 90:
|
|
return [0, 180]
|
|
else:
|
|
return [vel, ]
|
|
elif here == 90:
|
|
if vel % 180 == 0:
|
|
return [90, 270]
|
|
else:
|
|
return [vel, ]
|
|
else:
|
|
raise ValueError('omg')
|
|
|
|
def nexts(y, x, vel, beam):
|
|
return [(y + sin[n], x + cos[n], n, beam) for n in nextvel(y, x, vel)]
|
|
|
|
def is_done(y, x, vel, beam):
|
|
return (not all(n >= 0 and n < size for d, n in enumerate((y, x))) or
|
|
done[beam,vel // 90,y,x])
|
|
|
|
def set_done(y, x, vel, beam):
|
|
done[beam,vel // 90,y,x] = True
|
|
|
|
def test(y, x, vel, beam):
|
|
global totest
|
|
if is_done(y, x, vel, beam):
|
|
return
|
|
set_done(y, x, vel, beam)
|
|
totest += nexts(y, x, vel, beam)
|
|
if verbose and beam % draw_every == 0: # meh
|
|
here = mirrors[y,x]
|
|
if here == 69:
|
|
line(y, x, {0:'lr',90:'ud'}[vel%180], (0, 0, 255))
|
|
elif here == 45: # 0->90 avv, 180->270 avv: (init % 180)
|
|
if vel in (0, 270):
|
|
line(y, x, 'lm', (0, 0, 255))
|
|
line(y, x, 'mu', (0, 0, 255))
|
|
else:
|
|
line(y, x, 'rm', (0, 0, 255))
|
|
line(y, x, 'md', (0, 0, 255))
|
|
elif here == 135:
|
|
if vel in (0, 90):
|
|
line(y, x, 'lm', (0, 0, 255))
|
|
line(y, x, 'md', (0, 0, 255))
|
|
else:
|
|
line(y, x, 'rm', (0, 0, 255))
|
|
line(y, x, 'mu', (0, 0, 255))
|
|
elif here == 0:
|
|
if vel == 90:
|
|
line(y, x, 'dm', (0, 0, 255))
|
|
elif vel == 270:
|
|
line(y, x, 'um', (0, 0, 255))
|
|
elif here == 90:
|
|
if vel == 0:
|
|
line(y, x, 'lm', (0, 0, 255))
|
|
elif vel == 180:
|
|
line(y, x, 'rm', (0, 0, 255))
|
|
|
|
totest=deque()
|
|
for step in range(size):
|
|
totest += [(step, 0, 0, step), ]
|
|
totest += [(step, size - 1, 180, step + size), ]
|
|
totest += [(0, step, 270, step + size * 2), ]
|
|
totest += [(size - 1, step, 90, step + size * 3), ]
|
|
|
|
while totest:
|
|
if verbose:
|
|
draw()
|
|
for _ in range(len(totest)):
|
|
test(*totest.popleft())
|
|
|
|
print(np.count_nonzero(done[0].sum(axis=0).astype(bool)))
|
|
print(max(np.count_nonzero(done.sum(axis=1).astype(bool), axis=(1, 2))))
|
|
|
|
if verbose:
|
|
draw(0)
|