diff --git a/2024/ruby/day_17.rb b/2024/ruby/day_17.rb index 4e61325..993b71f 100644 --- a/2024/ruby/day_17.rb +++ b/2024/ruby/day_17.rb @@ -1,62 +1,120 @@ registers, program = DATA.read.split("\n\n") -a, b, c = registers.scan(/\d+/).map(&:to_i) -program = program.scan(/\d+/).map(&:to_i) +def run(a, b, c, program) + return enum_for(__method__, a, b, c, program) unless block_given? -combo = ->(operand) { - case operand - when 0, 1, 2, 3 then operand - when 4 then a - when 5 then b - when 6 then c - else - fail - end -} - -ip = 0 -out = [] -while (0...program.size).cover?(ip) - opcode = program.fetch(ip) - operand = program.fetch(ip+1) - case opcode - when 0 - a = (a / 2**combo[operand]).to_i - ip += 2 - when 1 - b = b ^ operand - ip += 2 - when 2 - b = combo[operand] % 8 - ip += 2 - when 3 - if a.zero? + combo = ->(operand) { + case operand + when 0, 1, 2, 3 then operand + when 4 then a + when 5 then b + when 6 then c + else + fail + end + } + + ip = 0 + while (0...program.size).cover?(ip) + opcode = program.fetch(ip) + operand = program.fetch(ip+1) + case opcode + when 0 + a = (a / 2**combo[operand]).to_i + ip += 2 + when 1 + b = b ^ operand + ip += 2 + when 2 + b = combo[operand] % 8 + ip += 2 + when 3 + if a.zero? + ip += 2 + else + ip = operand + end + when 4 + b = b ^ c + ip += 2 + when 5 + yield combo[operand] % 8 + ip += 2 + when 6 + b = (a / 2**combo[operand]).to_i + ip += 2 + when 7 + c = (a / 2**combo[operand]).to_i ip += 2 else - ip = operand + fail end - when 4 - b = b ^ c - ip += 2 - when 5 - out << combo[operand] % 8 - ip += 2 - when 6 - b = (a / 2**combo[operand]).to_i - ip += 2 - when 7 - c = (a / 2**combo[operand]).to_i - ip += 2 - else - fail end end -puts out.join(?,) +a, b, c = registers.scan(/\d+/).map(&:to_i) +program = program.scan(/\d+/).map(&:to_i) + +# puts (211000000..).find {|a| +# pp a if a % 100_000 == 0 +# program.each.lazy.zip(run(a, b, c, program)).all? { _1 == _2 } +# } + +def run(a) + return enum_for(__method__, a) unless block_given? + + # 14: 3 0 # jnz + until a.zero? + # 0: 2 4 # bst + # 2: 1 2 # bxl + # b = ((a & 0b111) ^ 0b010) + + # 4: 7 5 # cdv + # c = a >> ((a & 0b111) ^ 0b010) + + # 8: 1 7 # bxl + # 10: 4 1 # bxc + # b = ((a & 0b111) ^ 0b010) ^ c ^ 0b111 + # b = ((a & 0b111) ^ 0b010) ^ (a >> ((a & 0b111) ^ 0b010)) ^ 0b111 + b = (a & 0b111) ^ 0b101 ^ (a >> ((a & 0b111) ^ 0b010)) + + # 12: 5 5 # out + yield b & 0b111 + + # 6: 0 3 # adv + a >>= 3 + end +end + +def run(a) + return enum_for(__method__, a) unless block_given? + + a.to_s(8).chars.map(&:to_i).reverse.map.with_index {|x,i| + yield (x ^ 0b101 ^ (a >> 3*i >> (x ^ 0b010))) & 0b111 + } +end + +pp run(27334280).to_a.join(?,) + +TARGET = "2412750317415530".chars.map(&:to_i) +def solve(a) + return [a] if a.size == 16 + + (0..7) + .map { a + [_1] } + .select {|a| + TARGET.reverse[0,a.size].zip( + run(a.join.ljust(14, ?0).to_i(8)).to_a.reverse + ).all? { _1 == _2 } + }.flat_map { solve(_1) } +end + +pp solve([]).map(&:join).map { _1.to_i(8) }.min +pp run(190615597431823).to_a == program __END__ -Register A: 729 +Register A: 27334280 Register B: 0 Register C: 0 -Program: 0,1,5,4,3,0 +Program: 2,4,1,2,7,5,0,3,1,7,4,1,5,5,3,0