···11+import fileinput
22+from copy import deepcopy
33+44+55+def reg_or_val(regs, x):
66+ try:
77+ return int(x)
88+ except ValueError:
99+ return regs[x]
1010+1111+1212+def emulate(program, a=0, b=0, c=0, d=0):
1313+ pc = 0
1414+ regs = {'a': a, 'b': b, 'c': c, 'd': d}
1515+1616+ # Toggling instructions modifes the program, so operate on a copy instead.
1717+ program = deepcopy(program)
1818+1919+ while True:
2020+ if pc >= len(program):
2121+ return regs
2222+2323+ cmd, x, y = program[pc]
2424+2525+ if cmd == 'cpy':
2626+ # Subroutines that look like this perform multiplication:
2727+ # cpy b c
2828+ # inc a
2929+ # dec c
3030+ # jnz c -2
3131+ # dec d
3232+ # jnz d -5
3333+ # Perform a lookahead and optimize it by doing the following:
3434+ # - Set a to b*d
3535+ # - Set c and d to 0.
3636+ # - Move forward 5 instructions.
3737+ next_cmds, next_regs = zip(*program[pc+1:pc+5])[0:2]
3838+3939+ if x.isalpha() and next_cmds == ('inc', 'dec', 'jnz', 'dec'):
4040+ a, _, c, d = next_regs
4141+4242+ regs[a] = regs[x] * regs[d]
4343+ regs[c] = 0
4444+ regs[d] = 0
4545+ pc += 5
4646+ continue
4747+4848+ # Ignore copy instructions that try to copy a value into an
4949+ # immediate value (occurs when toggling instructions).
5050+ if y.isalpha():
5151+ regs[y] = reg_or_val(regs, x)
5252+5353+ elif cmd == 'inc':
5454+ regs[x] += 1
5555+5656+ elif cmd == 'dec':
5757+ regs[x] -= 1
5858+5959+ elif cmd == 'jnz':
6060+ x = reg_or_val(regs, x)
6161+6262+ if x != 0:
6363+ pc += reg_or_val(regs, y)
6464+ continue
6565+6666+ elif cmd == 'tgl':
6767+ x = reg_or_val(regs, x)
6868+ to_toggle = pc + x
6969+ try:
7070+ cng, nx, ny = program[to_toggle]
7171+ except:
7272+ pc += 1
7373+ continue
7474+7575+ if ny == 'null':
7676+ if cng == 'inc':
7777+ program[to_toggle][0] = 'dec'
7878+ else:
7979+ program[to_toggle][0] = 'inc'
8080+ else:
8181+ if cng == 'jnz':
8282+ program[to_toggle][0] = 'cpy'
8383+ else:
8484+ program[to_toggle][0] = 'jnz'
8585+8686+ pc += 1
8787+8888+8989+PROGRAM = []
9090+9191+for line in fileinput.input():
9292+ # Add null argument to pad inc/dec instructions
9393+ instruction = line + ' null'
9494+ PROGRAM.append(instruction.split()[:3])
9595+9696+print "Value to send to safe:", emulate(PROGRAM, a=7)['a']
9797+print "Actual value for safe:", emulate(PROGRAM, a=12)['a']
+26
2016/inputs/23.txt
···11+cpy a b
22+dec b
33+cpy a d
44+cpy 0 a
55+cpy b c
66+inc a
77+dec c
88+jnz c -2
99+dec d
1010+jnz d -5
1111+dec b
1212+cpy b c
1313+cpy c d
1414+dec d
1515+inc c
1616+jnz d -2
1717+tgl c
1818+cpy -16 c
1919+jnz 1 c
2020+cpy 94 c
2121+jnz 82 d
2222+inc a
2323+inc d
2424+jnz d -2
2525+inc c
2626+jnz c -5