[2019][ruby][2.x] refactor a computer class out of day 2
diff --git a/2019/ruby/computer.rb b/2019/ruby/computer.rb
new file mode 100644
index 0000000..cbec2d2
--- /dev/null
+++ b/2019/ruby/computer.rb
@@ -0,0 +1,63 @@
+OPCODES = {
+ 1 => ->(m, a, b, c) { m[c] = m[a] + m[b] },
+ 2 => ->(m, a, b, c) { m[c] = m[a] * m[b] },
+ 99 => ->(*) { throw :halt },
+}
+
+class Computer
+ def self.from(input)
+ new(input.split(?,).map(&:to_i))
+ end
+
+ def initialize(program)
+ @memory = program
+ @pc = 0
+ end
+
+ def run
+ each.inject(nil) {|_,i| i }
+ end
+
+ def each
+ return enum_for(__method__) unless block_given?
+
+ catch(:halt) do
+ loop do
+ opcode = OPCODES.fetch(@memory.fetch(@pc))
+ @pc += 1
+
+ n = opcode.arity - 1
+ args = (0...n).map {|i| @memory.fetch(@pc + i) }
+ @pc += n
+
+ opcode.call(@memory, *args)
+
+ yield @memory
+ end
+ end
+ end
+end
+
+require "minitest"
+
+class TestComputer < Minitest::Test
+ def test_samples
+ c = Computer.from("1,9,10,3,2,3,11,0,99,30,40,50").each
+
+ assert_equal 70, c.next.fetch(3)
+ assert_equal 3500, c.next.fetch(0)
+ end
+
+ def test_more_samples
+ run = ->(p) { Computer.from(p).run }
+
+ assert_equal 2, run.call("1,0,0,0,99").fetch(0)
+ assert_equal 6, run.call("2,3,0,3,99").fetch(3)
+ assert_equal 9801, run.call("2,4,4,5,99,0").fetch(5)
+ assert_equal 30, run.call("1,1,1,4,99,5,6,0,99").fetch(0)
+ end
+end
+
+if __FILE__ == $0
+ require "minitest/autorun"
+end
diff --git a/2019/ruby/day_02.rb b/2019/ruby/day_02.rb
index 35dc040..014ac98 100644
--- a/2019/ruby/day_02.rb
+++ b/2019/ruby/day_02.rb
@@ -1,47 +1,20 @@
-OPCODES = ARGF.read.split(?,).map(&:to_i)
+require_relative "computer"
-# opcodes[1] = 12
-# opcodes[2] = 2
+program = ARGF.read.split(?,).map(&:to_i)
-# pc = 0
-# loop do
-# p opcodes
-# case opcodes[pc]
-# when 1
-# opcodes[opcodes[pc+3]] = opcodes[opcodes[pc+1]] + opcodes[opcodes[pc+2]]
-# pc += 4
-# when 2
-# opcodes[opcodes[pc+3]] = opcodes[opcodes[pc+1]] * opcodes[opcodes[pc+2]]
-# pc += 4
-# when 99
-# puts opcodes[0]
-# exit
-# end
-# end
+# modified = program.dup
+# modified[1] = 12
+# modified[2] = 2
+# c = Computer.new(modified)
+# puts c.each.inject(nil) {|_,i| i }.fetch(0)
-def run(noun, verb)
- memory = OPCODES.dup
- memory[1] = noun
- memory[2] = verb
-
- pc = 0
- loop do
- case memory[pc]
- when 1
- memory[memory[pc+3]] = memory[memory[pc+1]] + memory[memory[pc+2]]
- pc += 4
- when 2
- memory[memory[pc+3]] = memory[memory[pc+1]] * memory[memory[pc+2]]
- pc += 4
- when 99
- return memory[0]
- end
- end
-end
-
-(0..99).each do |noun|
- (0..99).each do |verb|
- value = run(noun, verb)
- puts 100 * noun + verb and exit if value == 19690720
- end
-end
+noun, verb = (0..99).flat_map {|noun| (0..99).map {|verb| [noun, verb] } }
+ .find {|(noun, verb)|
+ modified = program.dup
+ modified[1] = noun
+ modified[2] = verb
+ c = Computer.new(modified)
+ final = c.run
+ final.fetch(0) == 19690720
+ }
+puts 100 * noun + verb