#!/usr/bin/env python3 import sys, re, math out = [] def output(i): out.append(i) def instr(opc, op, ra, rb, rc, p): cop = op if op in [4,5,6]: cop = [ra,rb,rc][op-4] if op == 7: cop = 'ERROR' if opc == 0: # 'adv' instruction ra = math.trunc(ra / 2**cop) p += 2 elif opc == 1: # 'bxl' instruction rb = rb ^ op p += 2 elif opc == 2: # 'bst' instruction rb = cop % 8 p += 2 elif opc == 3: # 'jnz' instruction if ra != 0: p = op else: p += 2 elif opc == 4: # 'bxc' instruction rb = rb ^ rc p += 2 elif opc == 5: # 'out' instruction output(cop % 8) p += 2 elif opc == 6: # 'bdv' instruction rb = math.trunc(ra / 2**cop) p += 2 elif opc == 7: # 'cdv' instruction rc = math.trunc(ra / 2**cop) p += 2 return ra, rb, rc, p def step(lb, ub, i, exp): for ra in range(lb, ub): if (((ra//8**i)%8) ^ 1 ^ int((ra//8**i) / 2**((ra//8** i%8)^2)) % 8) == exp: yield ra if __name__ == '__main__': ins = open(sys.argv[1]).read() g = re.search(r'Register A: (?P\d+)\nRegister B: (?P\d+)\nRegister C: (?P\d+)\n\nProgram: (?P(\d+,?)*)', ins) ra, rb, rc = int(g['ra']), int(g['rb']), int(g['rc']) prog = [int(p) for p in g['prog'].split(',')] pointer = 0 while True: if pointer >= len(prog): break ra, rb, rc, pointer = instr(prog[pointer], prog[pointer+1], ra, rb, rc, pointer) possible_bounds = [(0,8)] for i in range(15,-1,-1): exp = prog[i] possible_x = [] for lb, ub in possible_bounds: possible_x += [i for i in step(lb, ub, 0, exp)] possible_bounds = [(x*8,(x+1)*8) for x in possible_x] ra = min(possible_x) # challenge 1 res1 = ','.join([str(o) for o in out]) print(f"challenge 1:\n{res1}\n") # challenge 2 res2 = ra print(f"challenge 2 (only works for my input):\n{res2}")