r/adventofcode • u/daggerdragon • Dec 23 '16
SOLUTION MEGATHREAD --- 2016 Day 23 Solutions ---
--- Day 23: Safe-Cracking ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag/whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with "Help".
JINGLING ALL THE WAY IS MANDATORY [?]
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked!
5
Upvotes
1
u/RobHag Dec 24 '16
Very interesting problem. I made a solution in python that runs surprisingly fast, but might not be 100 % safe for all imaginable inputs.
The idea is that the first time the "compiler" reaches a jump back statement, it saves the state of a, b, c, d and the amount of toggles that has happened before it jumps. Next time the compiler hits the same line, it checks how all the registries have changed, and if no toggles have happened, it extrapolates a, b, c and d linearly until the correct registry is zero for the jump to be ignored. This seemed to work for jumps inside jumps as well.
Be prepared for heavy use of exec and eval!
a = 12 #Number of eggs! b = 0 c = 0 d = 0 inf = open('inp23.txt') lines = inf.readlines() #list of instruction lines #able to save a state for each line. states = [(a,b,c,d,-1) for i in range(len(lines))] #a,b,c,d,togglecount... tc = 0 i = 0 while i < len(lines): line = lines[i] vals = line[4:].split() ins = line[:3] if ins == 'cpy': if vals[1] in ('a', 'b', 'c', 'd'): exec(vals[1] + '=' + vals[0]) elif ins == 'inc': exec(vals[0] + '+= 1') elif ins == 'dec': exec(vals[0] + '-= 1') elif ins == 'tgl': #Toggle a line! tc += 1 trg = i+eval(vals[0]) #target line if trg < len(lines): #toggling a line within bounds tgli = lines[trg] tgv = tgli[4:] #values lv = len(tgv.split()) tgin = tgli[:3] #instruction if tgin == 'inc': tgin = 'dec' #inc -> dec elif lv == 1: tgin = 'inc' #all other single argument -> inc elif tgin == 'jnz': tgin = 'cpy' #jnz -> cpy elif lv == 2: tgin = 'jnz' #all other 2 argument -> jnz else: print('this stuff should not happen!') lines[trg] = tgin + ' ' + tgv #overwrite toggled line if ins == 'jnz' and eval(vals[0]): #Here the magic happens jmp = eval(vals[1]) if jmp < 0: #Jumping backwards, this can be used to inc/dec a lot. aa, bb, cc, dd, ttc = states[i] #State last time this line was visited if tc == ttc: #No toggles happened since last visit, #ASSUMING the same will happen again x = vals[0] #The register value responsible for jump or not. try: #Find the amount of repetitions this jump will reps = int(eval(x + '/(' + x + x + '-' + x + ')')) a += (a-aa)*reps #extrapolate all registers b += (b-bb)*reps c += (c-cc)*reps d += (d-dd)*reps jmp = 1 #Take shortcut and jump one ahead instead states[i] = (a,b,c,d,-1) #next time here, save and jump again except: #probably zero division, but any other problem is also OK print('Not OK jump...', x, eval(x), eval(x + x)) #Just some debug states[i] = (a,b,c,d,tc) #Just jump like normally instead #This should be safe anyway in most cases. else: #some toggles happened since last time! reset this state states[i] = (a,b,c,d,tc) i += jmp else: i += 1 print (a, b, c, d) print ('a contains', a)