AdventOfCode/2018/day16.py

69 lines
2.3 KiB
Python
Raw Permalink Normal View History

2018-12-16 16:29:33 +10:30
with open('day16-input1', 'r') as file:
data = [l.strip('\n') for l in file]
with open('day16-input2', 'r') as file:
data2 = [l.strip('\n') for l in file]
import re
2018-12-16 16:58:30 +10:30
numbers_pt1 = [[int(s) for s in re.findall(r'-?\d+', d)] for d in data if d]
numbers_pt2 = [[int(s) for s in re.findall(r'-?\d+', d)] for d in data2 if d]
2018-12-16 16:29:33 +10:30
2018-12-16 17:24:17 +10:30
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]
2018-12-16 16:29:33 +10:30
2018-12-17 11:34:44 +10:30
samples_3_or_more = 0
instruction_candidates = {}
2018-12-16 16:58:30 +10:30
for before, opcodes, after in zip(numbers_pt1[::3], numbers_pt1[1::3], numbers_pt1[2::3]):
2018-12-16 16:29:33 +10:30
possibilities = set()
for op in instructions:
try:
r2 = op(before, opcodes)
if r2 == after:
possibilities.add(op)
2018-12-16 17:24:17 +10:30
except Exception:
pass
2018-12-16 16:29:33 +10:30
if len(possibilities) >= 3:
2018-12-17 11:34:44 +10:30
samples_3_or_more += 1
2018-12-16 16:29:33 +10:30
2018-12-17 11:34:44 +10:30
if opcodes[0] in instruction_candidates:
instruction_candidates[opcodes[0]] &= possibilities
2018-12-16 16:29:33 +10:30
else:
2018-12-17 11:34:44 +10:30
instruction_candidates[opcodes[0]] = set(possibilities)
2018-12-16 16:29:33 +10:30
2018-12-17 11:34:44 +10:30
print(samples_3_or_more) # Part 1
2018-12-16 16:29:33 +10:30
2018-12-17 11:34:44 +10:30
instruction_codes = {}
while instruction_candidates:
for code, candidates in instruction_candidates.items():
2018-12-16 17:24:17 +10:30
if len(candidates) == 1:
2018-12-17 11:34:44 +10:30
instruction_codes[code] = tuple(candidates)[0]
for code2 in [c for c in instruction_candidates if c != code]:
instruction_candidates[code2].discard(instruction_codes[code])
instruction_candidates.pop(code)
break # Can't continue iterating on mutated sequence, also want to recheck start anyway
2018-12-16 16:29:33 +10:30
regs = [0, 0, 0, 0]
2018-12-16 16:58:30 +10:30
for i, opcodes in enumerate(numbers_pt2):
2018-12-17 11:34:44 +10:30
regs = instruction_codes[opcodes[0]](regs, opcodes)
2018-12-16 16:29:33 +10:30
print(regs) # Part 2 is first number