115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
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) |