Intcode with ruby yay
This commit is contained in:
parent
c368f223c4
commit
9889ffdd81
24
ruby/2019/2/bin/problem
Normal file
24
ruby/2019/2/bin/problem
Normal 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}"
|
||||
79
ruby/2019/2/lib/intcode.rb
Normal file
79
ruby/2019/2/lib/intcode.rb
Normal 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
|
||||
@ -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)}"
|
||||
21
ruby/2019/2/test/test_intcode.rb
Normal file
21
ruby/2019/2/test/test_intcode.rb
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user