AdventOfCode/2018/day21.py

115 lines
4.0 KiB
Python
Raw Permalink Normal View History

2018-12-21 17:09:29 +10:30
with open('day21-input', 'r') as file:
data = [l.strip('\n') for l in file]
# This solution includes optimisations which only work for this input.
# To adapt it to other inputs, the exit condition must be identified and the other optimisations removed.
class oper_factory:
def __init__(self, operator, immediate_a, immediate_b):
self.operator = operator
self.immediate_a = immediate_a
self.immediate_b = immediate_b
def __call__(self, regs, opcodes):
op, a, b, c = opcodes
r = list(regs)
r[c] = self.operator((a if self.immediate_a else regs[a]), (b if self.immediate_b else regs[b]))
return r
bin_ops = (int.__add__, int.__mul__, int.__and__, int.__or__)
set_op = lambda a, b: a # Just discard second operand
comp_ops = (int.__gt__, int.__eq__)
comp_imms = ((True, False), (False, True), (False, False)) # ir, ri, rr
instructions = [oper_factory(op, False, imm) for op in bin_ops for imm in (False, True)] \
+ [oper_factory(set_op, imm, True) for imm in (False, True)] \
+ [oper_factory(op, *imm) for op in comp_ops for imm in comp_imms]
inst_names = ('addr', 'addi', 'mulr', 'muli', 'banr', 'bani', 'borr', 'bori', 'setr', 'seti', 'gtir', 'gtri', 'gtrr', 'eqir', 'eqri', 'eqrr')
insts = {name: func for name, func in zip(inst_names, instructions)}
ops = {}
ops['seti'] = 0
registers = [0,0,0,0,0,0]
ip_r = int(data[0].split()[-1])
tokens_ = []
for line in data[1:]:
tokens = line.split()
tokens_.append([insts[tokens[0]]] + [int(i) for i in tokens[1:]])
def run_program(initial_registers):
registers = initial_registers.copy()
past_comps = set()
past_comps_l = []
for j in range(100000000000):
# print(registers)
try:
i = registers[ip_r]
if i == 17:
registers[1] = (registers[3]//256)-1
registers[ip_r] += 1
continue
if i == 9:
registers[5] = (((registers[5]+registers[1])&0xFFFFFF) * 65899) & 0xFFFFFF
registers[ip_r] = 13
continue
if i == 28:
# print(registers)
if registers[5] in past_comps:
# print('Loop???')
return past_comps_l
past_comps.add(registers[5])
past_comps_l.append(registers[5])
opcodes = tokens_[i]
registers = opcodes[0](registers, opcodes)
except Exception:
print(f'Halted at cycle {j}!')
return j
registers[ip_r] += 1
print(f'Did not halt! {registers}')
return 1000000
past_comps_l = run_program([0,0,0,0,0,0])
print(past_comps_l[0]) # Part 1
print(past_comps_l[-1]) # Part 2
# #ip 2
# L00 - seti 123 0 5
# L01 - bani 5 456 5
# L02 - eqri 5 72 5 - r5 = (r5 == 72)
# L03 - addr 5 2 2 - r2 += r5
# L04 - seti 0 0 2 - r2 = 0 (goto L01)
# L05 - seti 0 9 5 - r5 = 0
# L06 - bori 5 65536 3 - r3 = r5 | 0x010000 <-- Insertion point after comparison
# L07 - seti 7586220 4 5 - r5 = 7586220
# [FUNCTION]
# L08 - bani 3 255 1 - r1 = r3 & 0xFF <-- insertion point
# L09 - addr 5 1 5 - r5 += r1
# L10 - bani 5 16777215 5 - r5 &= 0x00FFFFFF
# L11 - muli 5 65899 5 - r5 *= 65899
# L12 - bani 5 16777215 5 - r5 &= 0x00FFFFFF
# L13 - gtir 256 3 1 - r1 = 256 > r3 (not if executed sequentially)
# L14 - addr 1 2 2 - r2 += r1 (goto L16->L28 if 256>r3) !!!
# L15 - addi 2 1 2 - r2 += 1 (goto L17)
# L16 - seti 27 9 2 - r2 = 27 (goto L28 - comparison)
# L17 - seti 0 9 1 - r1 = 0
# [FUNCTION]
# L18 - addi 1 1 4 - r4 = r1 + 1 <-- insertion point
# L19 - muli 4 256 4 - r4 *= 256
# L20 - gtrr 4 3 4 - r4 = r4 > r3
# L21 - addr 4 2 2 - r2 += r4 (goto L23->L26 if (r1+1)*256 > r3. r3=r1 then goto L08)
# L22 - addi 2 1 2 - r2 += 1 (goto L24 increment r1 and goto L18)
# [FUNCTION]
# L28 - eqrr 5 0 1 - r1 = r5==r0 - Exit condition! - 11050031 is lowest
# L29 - addr 1 2 2 - r2 += r1
# L30 - seti 5 0 2 - r2 = 5 - Goto L06
# L23 - seti 25 4 2 - r2 = 25 (goto L26)
# L24 - addi 1 1 1 - r1 += 1
# L25 - seti 17 2 2 - r2 = 17 (goto L18)
# L26 - setr 1 6 3 - r3 = r1
# L27 - seti 7 8 2 - r2 = 7 (goto L08)