Intcode with ruby yay

This commit is contained in:
Bill Rossi 2025-12-05 20:33:50 -05:00
parent c368f223c4
commit 9889ffdd81
4 changed files with 124 additions and 92 deletions

24
ruby/2019/2/bin/problem Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env ruby
require "intcode"
intcode = Intcode.for STDIN.read.chomp
intcode.poke(1, 12)
intcode.poke(2, 2)
intcode.run!
puts "Part 1: #{intcode.peek(0)}"
noun_verb = nil
0.upto(99).each do |noun|
0.upto(99).each do |verb|
intcode.reset!
intcode.poke(1, noun)
intcode.poke(2, verb)
intcode.run!
noun_verb = noun * 100 + verb if intcode.peek(0) == 19690720
break if noun_verb
end
break if noun_verb
end
puts "Part 2: #{noun_verb}"

View File

@ -0,0 +1,79 @@
class Intcode
attr_reader :memory, :pc, :stopped
def initialize(memory)
@initial_memory = memory
@memory = memory.clone
@pc = 0
@stopped = true
end
def self.for(string)
new string.split(",").map(&:to_i)
end
def run!
@stopped = false
@pc = 0
step! until stopped
end
def reset!
@memory = @initial_memory.clone
@pc = 0
end
def step!
case instruction
when 1
add!
when 2
multiply!
when 99
halt!
else
raise "invalid instuction #{instruction} at #{pc}"
end
end
def add!
v1 = peek(peek(pc + 1))
v2 = peek(peek(pc + 2))
log "adding #{v1} and #{v2}"
poke(peek(pc + 3), v1 + v2)
@pc += 4
end
def multiply!
v1 = peek(peek(pc + 1))
v2 = peek(peek(pc + 2))
log "multiplying #{v1} and #{v2}"
poke(peek(pc + 3), v1 * v2)
@pc += 4
end
def halt!
log "halting!"
@stopped = true
end
def instruction
peek pc
end
def peek(address)
memory[address]
end
def poke(address, value)
log "poking #{value} into #{address}"
memory[address] = value
end
def log(message)
puts message if logging?
end
def logging?
false
end
end

View File

@ -1,92 +0,0 @@
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)}"

View File

@ -0,0 +1,21 @@
require "minitest/autorun"
require "intcode"
class TestIntcode < Minitest::Test
def test_addition
i = Intcode.for("1,0,0,3,99")
i.run!
assert_equal(1, i.peek(0))
assert_equal(0, i.peek(1))
assert_equal(0, i.peek(2))
assert_equal(2, i.peek(3))
assert_equal(99, i.peek(4))
end
def test_multiplication
i = Intcode.for("1,9,10,3,2,3,11,0,99,30,40,50")
i.run!
assert_equal(3500, i.peek(0))
assert_equal(70, i.peek(3))
end
end