From d13666f520159067a4badb4521502fa24a14a957 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Fri, 21 Dec 2018 17:09:29 +1030 Subject: [PATCH] Added specialised 2018 Day 21 solution --- 2018/day21-input | 32 +++++++++++++ 2018/day21.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 2018/day21-input create mode 100644 2018/day21.py diff --git a/2018/day21-input b/2018/day21-input new file mode 100644 index 0000000..621f0ba --- /dev/null +++ b/2018/day21-input @@ -0,0 +1,32 @@ +#ip 2 +seti 123 0 5 +bani 5 456 5 +eqri 5 72 5 +addr 5 2 2 +seti 0 0 2 +seti 0 9 5 +bori 5 65536 3 +seti 7586220 4 5 +bani 3 255 1 +addr 5 1 5 +bani 5 16777215 5 +muli 5 65899 5 +bani 5 16777215 5 +gtir 256 3 1 +addr 1 2 2 +addi 2 1 2 +seti 27 9 2 +seti 0 9 1 +addi 1 1 4 +muli 4 256 4 +gtrr 4 3 4 +addr 4 2 2 +addi 2 1 2 +seti 25 4 2 +addi 1 1 1 +seti 17 2 2 +setr 1 6 3 +seti 7 8 2 +eqrr 5 0 1 +addr 1 2 2 +seti 5 0 2 diff --git a/2018/day21.py b/2018/day21.py new file mode 100644 index 0000000..43d4a68 --- /dev/null +++ b/2018/day21.py @@ -0,0 +1,115 @@ +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) \ No newline at end of file