#!/usr/bin/env ruby require "debug" DEBUG = false input = (ARGV.first.nil? ? DATA : ARGF) .readlines(chomp: true) split = input.index("") registers = input[...split] .map { _1.split(": ") } .map(&:last) .map(&:to_i) .zip(%i[A B C]) .map(&:reverse) .to_h program = input[split+1] .split(" ") .last .split(",") .map(&:to_i) OPERANDS = [ ->() { 0 }, ->() { 1 }, ->() { 2 }, ->() { 3 }, ->() { registers[:A] }, ->() { registers[:B] }, ->() { registers[:C] }, ->() { :noop }, ] def execute(registers, program) stdout, commands = Array.new, Array.new ic = 0 while ic < program.size opcode = program[ic] literal_operand = program[ic+1] combo_operand = OPERANDS[literal_operand].call ic += 2 case opcode when 0 numerator = registers[:A] denominator = 2 ** combo_operand registers[:A] = numerator / denominator commands << [:adv, numerator, denominator] when 1 registers[:B] = registers[:B] ^ literal_operand commands << [:bxl, literal_operand] when 2 registers[:B] = combo_operand % 8 commands << [:bst, combo_operand % 8] when 3 if registers[:A] == 0 commands << [:noop] else ic = literal_operand commands << [:jnz, literal_operand] end when 4 registers[:B] = registers[:B] ^ registers[:C] commands << [:bxc, registers[:B], registers[:C]] when 5 stdout << combo_operand % 8 commands << [:out, combo_operand % 8] when 6 numerator = registers[:A] denominator = 2 ** combo_operand registers[:B] = numerator / denominator commands << [:bdv, numerator, denominator] when 7 numerator = registers[:A] denominator = 2 ** combo_operand registers[:C] = numerator / denominator commands << [:cdv, numerator, denominator] end end if DEBUG commands.each { puts _1.join(" ") } end [registers, program, stdout.join(",")] end part_2 = registers[:A].dup _, _, part_1 = execute(registers, program) p part_1 while true part_2 += 100_00 registers = {A: part_2, B: 0, C: 0} _, _, output = execute(registers, program) p "#{part_2} (a): #{output}" break if output.match?(/4,1,5,5,0,3,3,0$/) end while part_2 <<= 3 registers = {A: part_2, B: 0, C: 0} _, _, output = execute(registers, program) next if output.size < 31 p "#{part_2} (b): #{output}" raise if output.size > 31 end __END__ Register A: 2024 Register B: 0 Register C: 0 Program: 0,3,5,4,3,0