advent2020/twentyfour.py

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