diff --git a/2024/ruby/day_17.rb b/2024/ruby/day_17.rb
index e190a47..99df161 100644
--- a/2024/ruby/day_17.rb
+++ b/2024/ruby/day_17.rb
@@ -1,57 +1,115 @@
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__