#!/usr/bin/env ruby input = (ARGV.first.nil? ? DATA : ARGF) .readlines(chomp: true) split = input.index("") registers = input[...split] .map { _1.split(": ").last.to_i } .zip(%i[A B C]).map(&:reverse) .to_h program = input[split+1].split(" ").last.split(",").map(&:to_i) def execute(registers, program) stdout, ic = Array.new, 0 combo = ->(operand) { operand < 4 ? operand : registers.values[operand - 4] } while ic < program.size opcode, operand = program[ic], program[ic + 1] ic += 2 case opcode when 0 then registers[:A] = registers[:A] / 2 ** combo.(operand) when 1 then registers[:B] = registers[:B] ^ operand when 2 then registers[:B] = combo.(operand) % 8 when 3 then registers[:A] == 0 || ic = operand when 4 then registers[:B] = registers[:B] ^ registers[:C] when 5 then stdout << combo.(operand) % 8 when 6 then registers[:B] = registers[:A] / 2 ** combo.(operand) when 7 then registers[:C] = registers[:A] / 2 ** combo.(operand) end end stdout end part_1 = execute(registers.dup, program).join(",") p part_1 def reverse_engineer(program, slot, candidate) return candidate if slot < 0 candidate <<= 3 unless slot == program.size - 1 (0..7) .map { [candidate + _1, execute({A: candidate + _1, B: 0, C: 0}, program)] } .select { _1.last == program[slot..] } .flat_map { reverse_engineer(program, slot - 1, _1.first) } end p reverse_engineer(program, program.size - 1, 0).sort.first # part_2 = 0 # (program.size - 1).downto(0) do |slot| # candidates = [] # (0..8).each do |i| # candidate = part_2 + i # _, _, output = execute({A: candidate, B: 0, C: 0}, program) # new_program = output.split(",").map(&:to_i) # # if new_program == program[slot..] # candidates << candidate # unless [301,2566855701950, 20534845615581, 20534845615573, 20534845615583].include?(candidate) # part_2 = candidate # end # end # end # p candidates # if slot == 0 # p candidates.first # end # part_2 <<= 3 # end __END__ Register A: 117440 Register B: 0 Register C: 0 Program: 0,3,5,4,3,0