--- /dev/null
+#!/usr/bin/perl -w
+
+use v5.30;
+use strict;
+
+local $/ = "\n\n";
+
+my @is_op = (65535) x 16;
+
+my $total = 0;
+while(<>) {
+ chomp;
+ last if !length;
+
+ my @nums = /(\d+)/g;
+ my @before = @nums[0..3];
+ my ($op, $a, $b, $c) = @nums[4..7];
+ my @after = @nums[8..11];
+ my $match = 0;
+
+ print join(' ', @nums), "\n";
+ # addr
+ $is_op[$op] &= ~(1 << 0) unless ($before[$a] + $before[$b] == $after[$c]);
+ # addi
+ $is_op[$op] &= ~(1 << 1) unless ($before[$a] + $b == $after[$c]);
+ # mulr
+ $is_op[$op] &= ~(1 << 2) unless ($before[$a] * $before[$b] == $after[$c]);
+ # muli
+ $is_op[$op] &= ~(1 << 3) unless ($before[$a] * $b == $after[$c]);
+ # bandr
+ $is_op[$op] &= ~(1 << 4) unless (($before[$a] & $before[$b]) == $after[$c]);
+ # bandi
+ $is_op[$op] &= ~(1 << 5) unless (($before[$a] & $b) == $after[$c]);
+ # borr
+ $is_op[$op] &= ~(1 << 6) unless (($before[$a] | $before[$b]) == $after[$c]);
+ # bori
+ $is_op[$op] &= ~(1 << 7) unless (($before[$a] | $b) == $after[$c]);
+ # setr
+ $is_op[$op] &= ~(1 << 8) unless ($before[$a] == $after[$c]);
+ # seti
+ $is_op[$op] &= ~(1 << 9) unless ($a == $after[$c]);
+ # gtir
+ $is_op[$op] &= ~(1 << 10) unless (($a > $before[$b] ? 1 : 0) == $after[$c]);
+ # gtri
+ $is_op[$op] &= ~(1 << 11) unless (($before[$a] > $b ? 1 : 0) == $after[$c]);
+ # gtrr
+ $is_op[$op] &= ~(1 << 12) unless (($before[$a] > $before[$b] ? 1 : 0) == $after[$c]);
+ # eqir
+ $is_op[$op] &= ~(1 << 13) unless (($a == $before[$b] ? 1 : 0) == $after[$c]);
+ # eqri
+ $is_op[$op] &= ~(1 << 14) unless (($before[$a] == $b ? 1 : 0) == $after[$c]);
+ # eqrr
+ $is_op[$op] &= ~(1 << 15) unless (($before[$a] == $before[$b] ? 1 : 0) == $after[$c]);
+ print join(' ', map { sprintf("%04x", $_) } @is_op), "\n";
+}
+
+my %is_2n = map { (1 << $_) => 1 } 0 .. 15;
+
+my %done_2n;
+my $modified = 1;
+while ($modified) {
+ say join(" ", map { sprintf("%04x", $_) } @is_op);
+ $modified = 0;
+ for my $try (0 .. 15) {
+ next if $done_2n{$try};
+ next if !$is_2n{$is_op[$try]};
+ print "Unique: $try: $is_op[$try]\n";
+ $done_2n{$try} = 1;
+ $modified = 1;
+ for my $other (0 .. 15) {
+ next if $done_2n{$other};
+ $is_op[$other] &= ~$is_op[$try];
+ }
+ }
+}
+
+my @op_trans;
+for my $op (0 .. 15) {
+ for my $l (0 .. 15) {
+ next if (1 << $l) != $is_op[$op];
+ print "$op => $l\n";
+ $op_trans[$op] = $l;
+ }
+}
+
+local $/ = "\n";
+my @regs = (0) x 4;
+while (<>) {
+ my ($op, $a, $b, $c) = /(\d+)/g;
+ say "$op $a $b $c ", join(' ', @regs);
+
+ # addr
+ $regs[$c] = $regs[$a] + $regs[$b] if $op_trans[$op] == 0;
+ # addi
+ $regs[$c] = $regs[$a] + $b if $op_trans[$op] == 1;
+ # mulr
+ $regs[$c] = $regs[$a] * $regs[$b] if $op_trans[$op] == 2;
+ # muli
+ $regs[$c] = $regs[$a] * $b if $op_trans[$op] == 3;
+ # bandr
+ $regs[$c] = ($regs[$a] & $regs[$b]) if $op_trans[$op] == 4;
+ # bandi
+ $regs[$c] = ($regs[$a] & $b) if $op_trans[$op] == 5;
+ # borr
+ $regs[$c] = ($regs[$a] | $regs[$b]) if $op_trans[$op] == 6;
+ # bori
+ $regs[$c] = ($regs[$a] | $b) if $op_trans[$op] == 7;
+ # setr
+ $regs[$c] = $regs[$a] if $op_trans[$op] == 8;
+ # seti
+ $regs[$c] = $a if $op_trans[$op] == 9;
+ # gtir
+ $regs[$c] = ($a > $regs[$b] ? 1 : 0) if $op_trans[$op] == 10;
+ # gtri
+ $regs[$c] = ($regs[$a] > $b ? 1 : 0) if $op_trans[$op] == 11;
+ # gtrr
+ $regs[$c] = ($regs[$a] > $regs[$b] ? 1 : 0) if $op_trans[$op] == 12;
+ # eqir
+ $regs[$c] = ($a == $regs[$b] ? 1 : 0) if $op_trans[$op] == 13;
+ # eqri
+ $regs[$c] = ($regs[$a] == $b ? 1 : 0) if $op_trans[$op] == 14;
+ # eqrr
+ $regs[$c] = ($regs[$a] == $regs[$b] ? 1 : 0) if $op_trans[$op] == 15;
+}
+
+say $regs[0];
+