Reasonably clean 2018 Day 16
This commit is contained in:
parent
225fe62540
commit
107933cb99
|
@ -6,46 +6,40 @@ import re
|
||||||
numbers_pt1 = [[int(s) for s in re.findall(r'-?\d+', d)] for d in data if d]
|
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]
|
numbers_pt2 = [[int(s) for s in re.findall(r'-?\d+', d)] for d in data2 if d]
|
||||||
|
|
||||||
def oper_prototype(operator, immediate_a, immediate_b, regs, opcodes):
|
|
||||||
|
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
|
op, a, b, c = opcodes
|
||||||
r = list(regs)
|
r = list(regs)
|
||||||
r[c] = operator((a if immediate_a else regs[a]), (b if immediate_b else regs[b]))
|
r[c] = self.operator((a if self.immediate_a else regs[a]), (b if self.immediate_b else regs[b]))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
addr = lambda regs, opcodes: oper_prototype(int.__add__, False, False, regs, opcodes)
|
bin_ops = (int.__add__, int.__mul__, int.__and__, int.__or__)
|
||||||
addi = lambda regs, opcodes: oper_prototype(int.__add__, False, True, regs, opcodes)
|
set_op = lambda a, b: a # Just discard second operand
|
||||||
mulr = lambda regs, opcodes: oper_prototype(int.__mul__, False, False, regs, opcodes)
|
comp_ops = (int.__gt__, int.__eq__)
|
||||||
muli = lambda regs, opcodes: oper_prototype(int.__mul__, False, True, regs, opcodes)
|
comp_imms = ((True, False), (False, True), (False, False)) # ir, ri, rr
|
||||||
andr = lambda regs, opcodes: oper_prototype(int.__and__, False, False, regs, opcodes)
|
|
||||||
andi = lambda regs, opcodes: oper_prototype(int.__and__, False, True, regs, opcodes)
|
instructions = [oper_factory(op, False, imm) for op in bin_ops for imm in (False, True)] \
|
||||||
orr = lambda regs, opcodes: oper_prototype(int.__or__, False, False, regs, opcodes)
|
+ [oper_factory(set_op, imm, True) for imm in (False, True)] \
|
||||||
ori = lambda regs, opcodes: oper_prototype(int.__or__, False, True, regs, opcodes)
|
+ [oper_factory(op, *imm) for op in comp_ops for imm in comp_imms]
|
||||||
setr = lambda regs, opcodes: oper_prototype(lambda a, b: a, True, True, regs, opcodes)
|
|
||||||
seti = lambda regs, opcodes: oper_prototype(lambda a, b: a, False, True, regs, opcodes)
|
|
||||||
gtir = lambda regs, opcodes: oper_prototype(int.__gt__, True, False, regs, opcodes)
|
|
||||||
gtri = lambda regs, opcodes: oper_prototype(int.__gt__, False, True, regs, opcodes)
|
|
||||||
gtrr = lambda regs, opcodes: oper_prototype(int.__gt__, False, False, regs, opcodes)
|
|
||||||
eqir = lambda regs, opcodes: oper_prototype(int.__eq__, True, False, regs, opcodes)
|
|
||||||
eqri = lambda regs, opcodes: oper_prototype(int.__eq__, False, True, regs, opcodes)
|
|
||||||
eqrr = lambda regs, opcodes: oper_prototype(int.__eq__, False, False, regs, opcodes)
|
|
||||||
|
|
||||||
instructions = [addr, addi, mulr, muli, andr, andi, orr, ori, setr, seti, gtir, gtri, gtrr, eqir, eqri, eqrr]
|
|
||||||
|
|
||||||
num_3_or_more = 0
|
num_3_or_more = 0
|
||||||
instruction_codes = {}
|
instruction_codes = {}
|
||||||
instruction_impossibilities = {}
|
|
||||||
for before, opcodes, after in zip(numbers_pt1[::3], numbers_pt1[1::3], numbers_pt1[2::3]):
|
for before, opcodes, after in zip(numbers_pt1[::3], numbers_pt1[1::3], numbers_pt1[2::3]):
|
||||||
possibilities = set()
|
possibilities = set()
|
||||||
impossibilities = set()
|
|
||||||
for op in instructions:
|
for op in instructions:
|
||||||
try:
|
try:
|
||||||
r2 = op(before, opcodes)
|
r2 = op(before, opcodes)
|
||||||
if r2 == after:
|
if r2 == after:
|
||||||
possibilities.add(op)
|
possibilities.add(op)
|
||||||
else:
|
except Exception:
|
||||||
impossibilities.add(op)
|
pass
|
||||||
except:
|
|
||||||
impossibilities.add(op)
|
|
||||||
if len(possibilities) >= 3:
|
if len(possibilities) >= 3:
|
||||||
num_3_or_more += 1
|
num_3_or_more += 1
|
||||||
|
|
||||||
|
@ -54,28 +48,20 @@ for before, opcodes, after in zip(numbers_pt1[::3], numbers_pt1[1::3], numbers_p
|
||||||
else:
|
else:
|
||||||
instruction_codes[opcodes[0]] = set(possibilities)
|
instruction_codes[opcodes[0]] = set(possibilities)
|
||||||
|
|
||||||
if opcodes[0] in instruction_impossibilities:
|
|
||||||
instruction_impossibilities[opcodes[0]] |= impossibilities
|
|
||||||
else:
|
|
||||||
instruction_impossibilities[opcodes[0]] = set(impossibilities)
|
|
||||||
|
|
||||||
print(num_3_or_more) # Part 1
|
print(num_3_or_more) # Part 1
|
||||||
|
|
||||||
for k in instruction_codes:
|
|
||||||
instruction_codes[k] -= instruction_impossibilities[k]
|
|
||||||
while sum([len(i) for i in instruction_codes.values()]) > len(instructions):
|
while sum([len(i) for i in instruction_codes.values()]) > len(instructions):
|
||||||
for code, cands in instruction_codes.items():
|
for code, candidates in instruction_codes.items():
|
||||||
if len(cands) == 1:
|
if len(candidates) == 1:
|
||||||
for code2 in [c for c in instruction_codes if c != code]:
|
for code2 in [c for c in instruction_codes if c != code]:
|
||||||
instruction_codes[code2] -= cands
|
instruction_codes[code2] -= candidates
|
||||||
|
instruction_codes = {k: tuple(s)[0] for k, s in instruction_codes.items()}
|
||||||
opcode_convert = {code: list(s)[0] for code, s in instruction_codes.items()}
|
|
||||||
|
|
||||||
regs = [0, 0, 0, 0]
|
regs = [0, 0, 0, 0]
|
||||||
for i, opcodes in enumerate(numbers_pt2):
|
for i, opcodes in enumerate(numbers_pt2):
|
||||||
try:
|
try:
|
||||||
regs = opcode_convert[opcodes[0]](regs, opcodes)
|
regs = instruction_codes[opcodes[0]](regs, opcodes)
|
||||||
except:
|
except Exception:
|
||||||
print(f'Line {i}: {regs} {opcodes}')
|
print(f'Line {i}: {regs} {opcodes}')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue