129 lines
3.2 KiB
Python
Executable File
129 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from functools import reduce
|
|
import datetime
|
|
import os, re, sys
|
|
import math
|
|
import curses
|
|
import numpy as np
|
|
from time import sleep
|
|
|
|
choice = 'e ne nw w sw se'.split()
|
|
|
|
def tpl(l):
|
|
anyew = re.compile(r'[ns]?[ew]')
|
|
return anyew.findall(l)
|
|
|
|
def uniq(d):
|
|
north = d['ne'] + d['nw'] - d['se'] - d['sw']
|
|
east = 2 * (d['e'] - d['w']) + d['ne'] + d['se'] - d['nw'] - d['sw']
|
|
return '%d/%d' % (north, east)
|
|
|
|
def path2dic(l):
|
|
return {k: sum(k == p for p in l) for k in choice}
|
|
|
|
def flip(d, t):
|
|
if t in d:
|
|
d[t] = not d[t]
|
|
else:
|
|
d[t] = True
|
|
|
|
def dprint(*args):
|
|
sep = False
|
|
for arg in args:
|
|
if sep:
|
|
print('--------')
|
|
sep = True
|
|
for a, b in arg.items():
|
|
print('%10s: %s' % (a, b))
|
|
print()
|
|
|
|
def diccoord(x, y, w=80, h=24):
|
|
e = x - (w // 2)
|
|
n = (h // 2) - y
|
|
if n % 2 == 0:
|
|
e -= (e % 2)
|
|
else:
|
|
e -= ((e+1) % 2)
|
|
return '%d/%d' % (n, e)
|
|
|
|
def mprint(d, lin, col):
|
|
print(curses.tigetstr('clear').decode())
|
|
for y in range(lin):
|
|
for x in range(col):
|
|
c = '.'
|
|
try:
|
|
c = '#' if d[diccoord(x, y, w=col, h=lin)] else ' '
|
|
except: pass
|
|
sys.stdout.write(c)
|
|
print()
|
|
|
|
def surrounding(tile):
|
|
neigh = ((0, 2),
|
|
(1, 1),
|
|
(1, -1),
|
|
(0, -2),
|
|
(-1, -1),
|
|
(-1, 1))
|
|
n, e = (int(x) for x in tile.split('/'))
|
|
return ['%d/%d' % (n+u, e+v) for u, v in neigh]
|
|
|
|
def tick(d):
|
|
toflip = {}
|
|
are_black = list(filter(lambda x: d[x], d.keys()))
|
|
for t in are_black:
|
|
sur = surrounding(t)
|
|
"""
|
|
Any black tile with zero or more than 2 black tiles immediately
|
|
adjacent to it is flipped to white.
|
|
"""
|
|
tobe_white = sum(1 for s in sur if s in are_black) in (0, 3, 4, 5, 6)
|
|
if tobe_white:
|
|
toflip[t] = False # "white"
|
|
"""
|
|
Any white tile with exactly 2 black tiles immediately adjacent to it
|
|
is flipped to black.
|
|
"""
|
|
for s in sur: # must be one of these, ducy?
|
|
if s in are_black or s in toflip: # black, or already handled
|
|
continue
|
|
sursur = surrounding(s)
|
|
tobe_black = sum(1 for ss in sursur if ss in are_black) == 2 # >= 1
|
|
if tobe_black:
|
|
toflip[s] = True
|
|
# Add remaining black tiles
|
|
for t in are_black:
|
|
if t not in toflip:
|
|
toflip[t] = True
|
|
return toflip
|
|
|
|
curses.setupterm()
|
|
size = os.get_terminal_size()
|
|
w, h = size.columns, size.lines
|
|
w -= 2 # wtf?
|
|
h -= 2 # wtf?
|
|
|
|
print(w, h)
|
|
sleep(1)
|
|
|
|
fn = sys.argv[1] if len(sys.argv) > 1 else 'input%s' % 24
|
|
with open(fn) as f:
|
|
|
|
lines = [l.strip() for l in f.readlines()]
|
|
t = [tpl(l) for l in lines]
|
|
|
|
flipdic = {}
|
|
for p in t:
|
|
flip(flipdic, uniq(path2dic(p)))
|
|
#print(path2dic(p), uniq(path2dic(p)), '\n')
|
|
mprint(flipdic, h, w)
|
|
dprint(flipdic)
|
|
print(sum(flipdic.values())) # 24a
|
|
sleep(1)
|
|
|
|
for i in range(100):
|
|
flipdic = tick(flipdic)
|
|
mprint(flipdic, h, w)
|
|
print('Day %d:' % i, sum(flipdic.values()))
|
|
sleep(1)
|
|
print(sum(flipdic.values())) # 24b
|