[2022][ruby][21.x]
change wpqnoypsrsmtmqzyxmtxsywrzlnzslmu
commit 8b40c44c9ed755f51857e853821932540dc4f062
author Alpha Chen <alpha@kejadlen.dev>
date
parent wlzvxmvp
diff --git a/2022/ruby/day_21.rb b/2022/ruby/day_21.rb
new file mode 100644
index 0000000..b0ee219
--- /dev/null
+++ b/2022/ruby/day_21.rb
@@ -0,0 +1,81 @@
+monkeys = ARGF.read.lines(chomp: true).to_h {|line| line.split(": ") }
+
+# part one
+# monkeys.each do |name, body|
+#   define_method(name) do
+#     eval(body)
+#   end
+# end
+
+# p root
+
+# part two
+sub_monkeys = monkeys.delete("root").split(" + ")
+monkeys.delete("humn")
+
+monkeys.each do |name, body|
+  define_method(name) do
+    eval(body)
+  end
+end
+
+target, unknown = sub_monkeys.partition { eval(_1) rescue nil}.map(&:first)
+target = eval(target)
+
+monkeys = monkeys.to_h {|monkey, job|
+  a, op, b = job.split(" ")
+  [monkey, { op:, a:, b: }]
+}
+monkeys["humn"] = { op: :humn }
+
+def apply(monkeys, monkey)
+  job = monkeys.fetch(monkey)
+  case op = job.fetch(:op)
+  when nil
+    job.fetch(:a).to_i
+  when :humn
+    :humn
+  else
+    a = apply(monkeys, job.fetch(:a))
+    b = apply(monkeys, job.fetch(:b))
+    if a.is_a?(Integer) && b.is_a?(Integer)
+      eval([a, op, b].join(" "))
+    else
+      [job.fetch(:op), a, b]
+    end
+  end
+end
+
+tree =  apply(monkeys, unknown)
+
+def reverse(target, tree)
+  loop do
+    case tree
+    in :humn
+      return target
+    in [op, Integer, b]
+      a = tree.fetch(1)
+      case op
+      when ?* then target /= a
+      when ?+ then target -= a
+      when ?- then target = a - target
+      else         fail tree.inspect
+      end
+      tree = b
+    in [op, a, Integer]
+      b = tree.fetch(2)
+      case op
+      when ?- then target += b
+      when ?/ then target *= b
+      when ?* then target /= b
+      when ?+ then target -= b
+      else         fail tree.inspect
+      end
+      tree = a
+    else
+      fail tree.inspect
+    end
+  end
+end
+
+p reverse(target, tree)