1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- #!/usr/bin/python3
-
- """Solution for day 23 of Advent of Code 2016.
-
- This is loosely based on day 12's solution. As instructions can now be modified (by the TGL opcode), they're kept
- in a 'register' as well.
-
- For part two to work in a reasonable amount of time, try_multiply implements a look-ahead optimisation for
- basic multiplication. Instructions of the form
-
- cpy b c
- inc a
- dec c
- jnz c -2
- dec d
- jnz d -5
-
- Are actually incrementing a by b*d, and setting both c and d to 0. The optimisation supports any registers, as long
- as they're distinct. It also only applies if the whole block of six instructions is reached naturally (i.e., execution
- doesn't jump into the middle of it).
- """
-
-
- def value(registers, x):
- try:
- return int(x)
- except ValueError:
- return registers[x]
-
-
- def cpy(registers, src, dst):
- registers[dst] = value(registers, src)
-
-
- def inc(registers, reg):
- registers[reg] += 1
-
-
- def dec(registers, reg):
- registers[reg] -= 1
-
-
- def jnz(registers, val, tar):
- registers['pc'] += 0 if value(registers, val) == 0 else value(registers, tar) - 1
-
-
- def tgl(registers, ins):
- mappings = {inc: dec, dec: inc, tgl: inc, jnz: cpy, cpy: jnz}
- target = registers['pc'] + value(registers, ins)
- registers['in'][target] = (mappings[registers['in'][target][0]], registers['in'][target][1])
-
-
- def try_multiply(registers):
- try:
- pc = registers['pc']
- chunk = registers['in'][pc:pc+6]
- instr, args = map(list, zip(*chunk))
- if instr == [cpy, inc, dec, jnz, dec, jnz] \
- and args[0][1] == args[2][0] == args[3][0] \
- and args[4][0] == args[5][0] \
- and args[1][0] != args[0][1] != args[4][0] != args[0][0] \
- and args[3][1] == '-2' and args[5][1] == '-5':
- registers[args[1][0]] += value(registers, args[0][0]) * value(registers, args[4][0])
- registers[args[2][0]] = 0
- registers[args[4][0]] = 0
- registers['pc'] += 5
- return True
- except:
- pass
- return False
-
-
- def step(registers):
- if not try_multiply(registers):
- try:
- registers['in'][registers['pc']][0](registers, *registers['in'][registers['pc']][1])
- except:
- pass
-
-
- def run(values):
- registers = values
- registers['pc'] = 0
- registers['in'] = instr.copy()
-
- while registers['pc'] < len(instr):
- step(registers)
- registers['pc'] += 1
-
- return registers['a']
-
-
- with open('data/23.txt', 'r') as file:
- instr = map(str.split, map(str.strip, file.readlines()))
- instr = [(globals()[i[0]], i[1:]) for i in instr]
-
- print("Stage 1: %s" % run({'a': 7, 'b': 0, 'c': 0, 'd': 0}))
- print("Stage 2: %s" % run({'a': 12, 'b': 0, 'c': 0, 'd': 0}))
|