My Advent of Code solutions in Python. kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update 2017/23 solution

Use peephole optimizations to solve Part 2 via emulation.

+63 -40
+63 -40
2017/day23.py
··· 2 2 import fileinput 3 3 from collections import defaultdict 4 4 5 - from utils import parse_line, mul, all_unique, factors, memoize, primes # NOQA 5 + 6 + def emulate(instrs, **reg_init): 7 + regs = defaultdict(int) 8 + 9 + for k, v in reg_init.items(): 10 + regs[k] = v 6 11 7 - INSTRS = [] 8 - B = None 12 + pc = 0 13 + 14 + while 0 <= pc < len(instrs): 15 + op, x, y = instrs[pc] 16 + y = regs[y] if y.isalpha() else int(y) 17 + 18 + if op == 'set': 19 + regs[x] = y 20 + elif op == 'sub': 21 + regs[x] -= y 22 + elif op == 'mul': 23 + regs[x] *= y 24 + regs['_muls'] += 1 25 + elif op == 'mod': 26 + regs[x] %= y 27 + elif op == 'sqrt': 28 + regs[x] = int(math.sqrt(y)) + 1 29 + elif op == 'jnz': 30 + if (regs[x] if x.isalpha() else int(x)) != 0: 31 + pc += y 32 + continue 33 + 34 + pc += 1 35 + 36 + return regs 37 + 9 38 10 39 # Read puzzle input 40 + INSTRS = [] 41 + 11 42 for line in fileinput.input(): 12 43 instr = line.strip() + ' foo' 13 44 op, x, y = instr.split()[:3] 14 45 INSTRS.append((op, x, y)) 15 46 16 - if fileinput.isfirstline(): 17 - B = int(y) 18 - 19 47 # Part 1 20 - REGS = defaultdict(int) 21 - pc = 0 22 - muls = 0 48 + print "`mul` instruction invocations:", emulate(INSTRS)['_muls'] 23 49 24 - while 0 <= pc < len(INSTRS): 25 - op, x, y = INSTRS[pc] 26 - y = REGS[y] if y.isalpha() else int(y) 50 + # Part 2 51 + # 52 + # Perform peephole optimizations to speed up execution of Part 2 53 + # (inspired by https://www.reddit.com/r/adventofcode/comments/7lrjei) 54 + # 55 + # Speed up composite check using modulo 56 + # set e 2 -> set g b 57 + # set g d -> mod g d 58 + # mul g e -> jnz g 8 59 + # sub g b -> set f 0 60 + # jnz g 2 -> jnz 1 11 61 + # set f 0 -> nop 62 + # sub e -1 -> nop 63 + # set g e -> nop 64 + # sub g b -> nop 65 + # jnz g -8 -> nop 66 + # 67 + # Only check integers up to sqrt(n) 68 + # set g d -> sqrt g b 69 + # sub g b -> sub g d 27 70 28 - if op == 'set': 29 - REGS[x] = y 30 - elif op == 'sub': 31 - REGS[x] -= y 32 - elif op == 'mul': 33 - REGS[x] *= y 34 - muls += 1 35 - elif op == 'mod': 36 - REGS[x] %= y 37 - elif op == 'jnz': 38 - if (REGS[x] if x.isalpha() else int(x)) != 0: 39 - pc += y 40 - continue 71 + INSTRS[10] = ['set', 'g', 'b'] 72 + INSTRS[11] = ['mod', 'g', 'd'] 73 + INSTRS[12] = ['jnz', 'g', '8'] 74 + INSTRS[13] = ['set', 'f', '0'] 75 + INSTRS[14] = ['jnz', '1', '11'] 41 76 42 - pc += 1 43 - 44 - print "`mul` instruction invocations:", muls 77 + INSTRS[21] = ['sqrt', 'g', 'b'] 78 + INSTRS[22] = ['sub', 'g', 'd'] 45 79 46 - # Part 2 47 - b = (B * 100) + 100000 48 - c = b + 17000 49 - h = 0 50 - 51 - for n in range(b, c + 1, 17): 52 - for i in range(2, int(math.sqrt(n))): 53 - if n % i == 0: 54 - h += 1 55 - break 56 - 57 - print "Value in register h, ie. primes in [{}, {}]: {}".format(b, c, h) 80 + print "Value in register h:", emulate(INSTRS, a=1)['h']