#!/usr/bin/env ruby input = $stdin.readlines.map(&:strip).reject(&:empty?) class Machine def initialize(rs) @rs = rs end def addr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] + @rs[b] nrs end def addi(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] + b nrs end def mulr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] * @rs[b] nrs end def muli(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] * b nrs end def banr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] & @rs[b] nrs end def bani(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] & b nrs end def borr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] | @rs[b] nrs end def bori(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] | b nrs end def setr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] nrs end def seti(a, b, c) nrs = @rs.dup nrs[c] = a nrs end def gtir(a, b, c) nrs = @rs.dup nrs[c] = a > @rs[b] ? 1 : 0 nrs end def gtri(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] > b ? 1 : 0 nrs end def gtrr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] > @rs[b] ? 1 : 0 nrs end def eqir(a, b, c) nrs = @rs.dup nrs[c] = a == @rs[b] ? 1 : 0 nrs end def eqri(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] == @rs[b] ? 1 : 0 nrs end def eqrr(a, b, c) nrs = @rs.dup nrs[c] = @rs[a] == @rs[b] ? 1 : 0 nrs end def oprs(a, b, c) [ addr(a, b, c), addi(a, b, c), mulr(a, b, c), muli(a, b, c), banr(a, b, c), bani(a, b, c), borr(a, b, c), bori(a, b, c), setr(a, b, c), seti(a, b, c), gtir(a, b, c), gtri(a, b, c), gtrr(a, b, c), eqir(a, b, c), eqri(a, b, c), eqrr(a, b, c) ] end end oprsorder = { 1<<15 => "addr", 1<<14 => "addi", 1<<13 => "mulr", 1<<12 => "muli", 1<<11 => "banr", 1<<10 => "bani", 1<<9 => "borr", 1<<8 => "bori", 1<<7 => "setr", 1<<6 => "seti", 1<<5 => "gtir", 1<<4 => "grri", 1<<3 => "gtrr", 1<<2 => "eqir", 1<<1 => "eqri", 1<<0 => "eqrr" } opsorder = %w( addr addi mulr muli banr bani borr bori setr seti gtir gtri gtrr eqir eqri eqrr ) ops = [ 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111, 0b1111111111111111 ] input.each_slice(3) do |sample| sample[0] =~ /Before: \[(\d+), (\d+), (\d+), (\d+)\]/ break if $1.nil? m = Machine.new([$1.to_i, $2.to_i, $3.to_i, $4.to_i]) sample[1] =~ /(\d+) (\d+) (\d+) (\d+)/ opc = $1.to_i oprs = m.oprs($2.to_i, $3.to_i, $4.to_i) sample[2] =~ /After: \[(\d+), (\d+), (\d+), (\d+)\]/ a = [$1.to_i, $2.to_i, $3.to_i, $4.to_i] ops[opc] &= oprs.map{|opr|opr == a ? 1 : 0}.join.to_i(2) end iopts = { "addr" => [], "addi" => [], "mulr" => [], "muli" => [], "banr" => [], "bani" => [], "borr" => [], "bori" => [], "setr" => [], "seti" => [], "gtir" => [], "gtri" => [], "gtrr" => [], "eqir" => [], "eqri" => [], "eqrr" => [] } ops.each_with_index do |op, opc| ("%016b" % op).chars.each_with_index do |bit, istr| if bit == "1" then iopts[opsorder[istr]] << opc end end end res = [] until iopts.values.map(&:empty?).all? do iopts.each do |istr, opcs| puts "#{istr}: #{opcs}" end puts istr = iopts.select{|k, v| v.length == 1}.keys[0] opc = iopts[istr][0] res[opc] = istr iopts.each do |k, v| v.delete(opc) end end res.each_with_index do |istr, opc| puts "#{opc}: #{istr}" end