class Computer attr_reader :data def initialize(data) @data = data @program_counter = 0 @halted = true end def run @halted = false while !@halted instruction_range = data[@program_counter..(@program_counter + 3)] opcode = OpCode.for(self, *instruction_range) opcode.execute @program_counter += 4 end end def read(index) data[index] end def write(index, value) data[index] = value end def halt @halted = true end def self.from_string(string) new(string.split(",").map(&:to_i)) end def self.from_file(file_path) from_string(File.read file_path) end end class OpCode attr_reader :computer def initialize(computer) @computer = computer end def self.for(computer, *args) case args[0] when 1 OpCode1.new(computer, *args[1..]) when 2 OpCode2.new(computer, *args[1..]) when 99 OpCode99.new(computer) end end end class OpCode1 < OpCode attr_reader :destination, :first_position, :second_position def initialize(computer, arg1, arg2, arg3) super(computer) @first_position = arg1 @second_position = arg2 @destination = arg3 end def value_to_write computer.read(first_position) + computer.read(second_position) end def execute computer.write destination, value_to_write end end class OpCode2 < OpCode1 def value_to_write computer.read(first_position) * computer.read(second_position) end end class OpCode99 < OpCode def execute computer.halt end end c = Computer.from_file("../data/2019/2/input.txt") c.write(1, 12) c.write(2, 2) c.run puts "Part 1: #{c.read(0)}"