From 475ad99996cf52107c7bbdee31267d89131a428e Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Thu, 5 Dec 2019 09:20:31 -0800 Subject: [PATCH] [2019][ruby][2.x] refactor a computer class out of day 2 --- 2019/ruby/computer.rb | 63 +++++++++++++++++++++++++++++++++++++++++++ 2019/ruby/day_02.rb | 61 ++++++++++++----------------------------- 2 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 2019/ruby/computer.rb 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