day 16
chronal classification
approach
the sixteen opcodes are lambdas over a register tuple, built from three helpers (register/register, register/immediate, immediate/register) plus setr and seti. each one returns a new tuple instead of mutating. part 1 counts the samples that at least three opcodes explain.
part 2 starts every opcode number with all sixteen candidates and intersects them with the opcodes that fit each sample. then a queue of numbers with a single candidate left removes that candidate from every other number, repeating until each number maps to one opcode. the test program runs with the decoded table and register 0 is printed.
the trick
repeatedly take an opcode number that has only one candidate left and remove that candidate from all the others.
python
q = deque([i for i in range(len(poss)) if len(poss[i]) == 1])
done = {i for i in q}
while q:
for _ in range(len(q)):
n = q.popleft()
for i in range(len(poss)):
if i != n:
poss[i] = poss[i] - poss[n]
if i not in done and len(poss[i]) == 1:
q.append(i)
done.add(i)
return [p.pop() for p in poss]