···22import fileinput
33from collections import defaultdict
4455-from utils import parse_line, mul, all_unique, factors, memoize, primes # NOQA
55+66+def emulate(instrs, **reg_init):
77+ regs = defaultdict(int)
88+99+ for k, v in reg_init.items():
1010+ regs[k] = v
61177-INSTRS = []
88-B = None
1212+ pc = 0
1313+1414+ while 0 <= pc < len(instrs):
1515+ op, x, y = instrs[pc]
1616+ y = regs[y] if y.isalpha() else int(y)
1717+1818+ if op == 'set':
1919+ regs[x] = y
2020+ elif op == 'sub':
2121+ regs[x] -= y
2222+ elif op == 'mul':
2323+ regs[x] *= y
2424+ regs['_muls'] += 1
2525+ elif op == 'mod':
2626+ regs[x] %= y
2727+ elif op == 'sqrt':
2828+ regs[x] = int(math.sqrt(y)) + 1
2929+ elif op == 'jnz':
3030+ if (regs[x] if x.isalpha() else int(x)) != 0:
3131+ pc += y
3232+ continue
3333+3434+ pc += 1
3535+3636+ return regs
3737+9381039# Read puzzle input
4040+INSTRS = []
4141+1142for line in fileinput.input():
1243 instr = line.strip() + ' foo'
1344 op, x, y = instr.split()[:3]
1445 INSTRS.append((op, x, y))
15461616- if fileinput.isfirstline():
1717- B = int(y)
1818-1947# Part 1
2020-REGS = defaultdict(int)
2121-pc = 0
2222-muls = 0
4848+print "`mul` instruction invocations:", emulate(INSTRS)['_muls']
23492424-while 0 <= pc < len(INSTRS):
2525- op, x, y = INSTRS[pc]
2626- y = REGS[y] if y.isalpha() else int(y)
5050+# Part 2
5151+#
5252+# Perform peephole optimizations to speed up execution of Part 2
5353+# (inspired by https://www.reddit.com/r/adventofcode/comments/7lrjei)
5454+#
5555+# Speed up composite check using modulo
5656+# set e 2 -> set g b
5757+# set g d -> mod g d
5858+# mul g e -> jnz g 8
5959+# sub g b -> set f 0
6060+# jnz g 2 -> jnz 1 11
6161+# set f 0 -> nop
6262+# sub e -1 -> nop
6363+# set g e -> nop
6464+# sub g b -> nop
6565+# jnz g -8 -> nop
6666+#
6767+# Only check integers up to sqrt(n)
6868+# set g d -> sqrt g b
6969+# sub g b -> sub g d
27702828- if op == 'set':
2929- REGS[x] = y
3030- elif op == 'sub':
3131- REGS[x] -= y
3232- elif op == 'mul':
3333- REGS[x] *= y
3434- muls += 1
3535- elif op == 'mod':
3636- REGS[x] %= y
3737- elif op == 'jnz':
3838- if (REGS[x] if x.isalpha() else int(x)) != 0:
3939- pc += y
4040- continue
7171+INSTRS[10] = ['set', 'g', 'b']
7272+INSTRS[11] = ['mod', 'g', 'd']
7373+INSTRS[12] = ['jnz', 'g', '8']
7474+INSTRS[13] = ['set', 'f', '0']
7575+INSTRS[14] = ['jnz', '1', '11']
41764242- pc += 1
4343-4444-print "`mul` instruction invocations:", muls
7777+INSTRS[21] = ['sqrt', 'g', 'b']
7878+INSTRS[22] = ['sub', 'g', 'd']
45794646-# Part 2
4747-b = (B * 100) + 100000
4848-c = b + 17000
4949-h = 0
5050-5151-for n in range(b, c + 1, 17):
5252- for i in range(2, int(math.sqrt(n))):
5353- if n % i == 0:
5454- h += 1
5555- break
5656-5757-print "Value in register h, ie. primes in [{}, {}]: {}".format(b, c, h)
8080+print "Value in register h:", emulate(INSTRS, a=1)['h']