[2024][ruby][17.2]
change wzrmmspluzkknroyosmmqtoqnzolynoy
commit 97c64dbc903048ddfd260d25a0e4dc161fc70de9
author Alpha Chen <alpha@kejadlen.dev>
date
parent nvtxnozs
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__