158 lines
4.8 KiB
Python
Executable File
158 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from functools import reduce
|
|
from itertools import cycle
|
|
import re, sys
|
|
import math
|
|
import numpy as np
|
|
|
|
def dprint(*args):
|
|
sep = False
|
|
for arg in args:
|
|
if sep:
|
|
print('--------')
|
|
sep = True
|
|
for a, b in arg.items():
|
|
print('%10s: %s' % (a, ','.join(b)))
|
|
print()
|
|
|
|
def cup(base, rest):
|
|
# find index of next cup to pick up
|
|
trial = chr(ord(base) - 1) if base > '1' else '9'
|
|
try:
|
|
return rest.index(trial)
|
|
except: # not there
|
|
return cup(trial, rest)
|
|
|
|
def getoff(circle, offset):
|
|
# undo our offset
|
|
return (circle + circle)[9 - offset:18 - offset]
|
|
|
|
def printoff(circle, offset):
|
|
print('%s (%d)' % (getoff(circle, offset), offset))
|
|
|
|
def printafterone(circle):
|
|
# lol we don't even need the offset
|
|
oneidx = circle.index('1')
|
|
print(circle[oneidx+1:] + circle[:oneidx])
|
|
|
|
def printnice(first, three, six, dest, i):
|
|
# ugh
|
|
print('-- move %d --' % i)
|
|
print('cups: (%s)%s' % (first, ''.join(' %s ' % c for c in three + six)))
|
|
print('pick up: %s' % ', '.join(three))
|
|
print('destination: %s' % dest)
|
|
print()
|
|
|
|
def move(circle, offset, i=1):
|
|
# don't keep track of the selected; just keep it at the left
|
|
# instead keep track of how far we've shifted the circle left
|
|
# (modulo 9, as if you care)
|
|
# ANYWAY, our selected cup is always in first position, so grab the three next
|
|
selected, pickup, remain = circle[0], circle[1:4], circle[4:]
|
|
dest = cup(selected, remain)
|
|
printnice(selected, pickup, remain, remain[dest], i) # jfc
|
|
# build the new circle
|
|
return (''.join(
|
|
[*remain[:dest],
|
|
remain[dest],
|
|
*pickup,
|
|
*remain[dest+1:],
|
|
selected,
|
|
]),
|
|
(offset + 1 + dest) % 9)
|
|
|
|
def subone(sel, three, size):
|
|
ret = sel - 1
|
|
if ret == 0:
|
|
ret = size
|
|
if ret in three:
|
|
return subone(ret, three, size)
|
|
else:
|
|
return ret
|
|
|
|
def messwith(l, r, sel, size=1000000):
|
|
#print('selected:', sel)
|
|
three = r[sel], r[r[sel]], r[r[r[sel]]]
|
|
#print('pick up:', three)
|
|
# DANGLING: r[sel], l[r[sel]] (change in opposite order of course),
|
|
# ... r[three[-1]], l[ibid],
|
|
# ALSO MODIFY: r[dest], l[r[dest]] (again change in opposite order)
|
|
dest = subone(sel, three, size)
|
|
#print('destination:', dest)
|
|
# i do not like python
|
|
#print('r[%s] = %s' % (sel, r[three[-1]]))
|
|
#print('l[%s] = %s' % (r[sel], dest))
|
|
#print('r[%s] = %s' % (three[-1], r[dest]))
|
|
#print('l[%s] = %s' % (r[three[-1]], sel))
|
|
#print('r[%s] = %s' % (dest, three[0]))
|
|
#print('l[%s] = %s' % (r[dest], three[-1]))
|
|
#print('set this to 1, please:', l[r[dest]], 'btw', r[dest])
|
|
src_r_idx = sel
|
|
src_l_idx = r[three[-1]]
|
|
dst_r_idx = dest
|
|
dst_l_idx = r[dest]
|
|
three_r_idx = three[-1]
|
|
three_l_idx = three[0] # which indeed is r[sel], yes
|
|
r[src_r_idx] = src_l_idx
|
|
l[src_l_idx] = src_r_idx
|
|
r[dst_r_idx] = three_l_idx
|
|
l[dst_l_idx] = three_r_idx
|
|
r[three_r_idx] = dst_l_idx
|
|
l[three_l_idx] = dst_r_idx
|
|
#print()
|
|
#print('left:', l)
|
|
return r[sel]
|
|
|
|
def rightof(r, i, rem):
|
|
if rem == 0:
|
|
return []
|
|
return [r[i], ] + rightof(r, r[i], rem - 1)
|
|
|
|
def printall(r, sel, size):
|
|
print('cups:', ''.join('%s%s%s' % (
|
|
'(' if x == sel else ' ',
|
|
str(x),
|
|
')' if x == sel else ' ')
|
|
for x in rightof(r, 1, size)))
|
|
|
|
fn = sys.argv[1] if len(sys.argv) > 1 else 'input%s' % 23
|
|
with open(fn) as f:
|
|
|
|
offset, circle = 0, f.read().strip()
|
|
finito = reduce(lambda a, b: move(a[0], a[1], i=b+1), range(100), (circle, offset)) # lol
|
|
printoff(*finito)
|
|
printafterone(finito[0])
|
|
|
|
# well, we'll have to be more creative here
|
|
size = int(sys.argv[2] if len(sys.argv) > 2 else 1e6)
|
|
# first, redo part 1
|
|
orbit = np.linspace(1, size, size, dtype=int)
|
|
for i, c in enumerate(circle):
|
|
orbit[i] = int(c)
|
|
print(orbit)
|
|
left = np.zeros(size + 1, dtype=int) # 1-indexed, so "pad"
|
|
right = np.zeros(size + 1, dtype=int)
|
|
for i, c in enumerate(orbit):
|
|
left[c] = orbit[(i+size-1)%size]
|
|
right[c] = orbit[(i+1)%size]
|
|
print(left[1:11], '<>', right[1:11])
|
|
print()
|
|
|
|
selidx = orbit[0]
|
|
rounds = int(sys.argv[3] if len(sys.argv) > 2 else 1e7)
|
|
for i in range(rounds):
|
|
#print('-- round %d --' % (i + 1))
|
|
#printall(right, selidx, size)
|
|
selidx = messwith(left, right, selidx, size=size)
|
|
if not (i % math.ceil(rounds / 10)):
|
|
print(left[1:], '<>', right[1:])
|
|
print('%d to go' % (rounds - i))
|
|
print('-- final --')
|
|
print(left[1:], '<>', right[1:])
|
|
#printall(right, selidx, size)
|
|
|
|
# ok, now find cups on SIDE.
|
|
bill = right[1]
|
|
bob = right[bill]
|
|
print('%d * %d =\n%d' % (bill, bob, (bill * bob)))
|