More intcode
This commit is contained in:
parent
b004c936f0
commit
d30e3f9600
@ -1,79 +0,0 @@
|
||||
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
|
||||
16
ruby/2019/5/bin/problem
Normal file
16
ruby/2019/5/bin/problem
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "intcode"
|
||||
|
||||
intcode = Intcode.for STDIN.read.chomp
|
||||
intcode.input.push 1
|
||||
intcode.run!
|
||||
|
||||
puts "Part 1: #{intcode.output.last}"
|
||||
|
||||
intcode.reset!
|
||||
intcode.input.push 5
|
||||
intcode.run!
|
||||
|
||||
puts "Part 2: #{intcode.output.first}"
|
||||
|
||||
155
ruby/2019/lib/intcode.rb
Normal file
155
ruby/2019/lib/intcode.rb
Normal file
@ -0,0 +1,155 @@
|
||||
class Intcode
|
||||
attr_reader :memory, :pc, :stopped, :input, :output
|
||||
def initialize(memory)
|
||||
@initial_memory = memory
|
||||
@memory = memory.clone
|
||||
@pc = 0
|
||||
@stopped = true
|
||||
@input = []
|
||||
@output = []
|
||||
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
|
||||
@output = []
|
||||
@input = []
|
||||
end
|
||||
|
||||
def step!
|
||||
log "pc: #{pc}, instruction: #{instruction}"
|
||||
case opcode
|
||||
when 1
|
||||
add!
|
||||
when 2
|
||||
multiply!
|
||||
when 3
|
||||
read_input!
|
||||
when 4
|
||||
write_output!
|
||||
when 5
|
||||
jump_if_true!
|
||||
when 6
|
||||
jump_if_false!
|
||||
when 7
|
||||
less_than!
|
||||
when 8
|
||||
equals!
|
||||
when 99
|
||||
halt!
|
||||
else
|
||||
raise "invalid opcode #{opcode} at #{pc}"
|
||||
end
|
||||
end
|
||||
|
||||
def parameters
|
||||
parameter_modes.each_with_index.map do |mode, index|
|
||||
case mode
|
||||
when 0
|
||||
peek(pc + 1 + index)
|
||||
when 1
|
||||
pc + 1 + index
|
||||
else
|
||||
raise "Invalid parameter mode #{mode}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add!
|
||||
log "adding #{peek(parameters[0])} and #{(parameters[1])}"
|
||||
poke(parameters[2], peek(parameters[0]) + peek(parameters[1]))
|
||||
@pc += 4
|
||||
end
|
||||
|
||||
def multiply!
|
||||
log "multiplying #{peek(parameters[0])} and #{peek(parameters[1])}"
|
||||
poke(parameters[2], peek(parameters[0]) * peek(parameters[1]))
|
||||
@pc += 4
|
||||
end
|
||||
|
||||
def read_input!
|
||||
i = input.shift
|
||||
log "reading input #{i} into #{parameters[0]}"
|
||||
poke(parameters[0], i)
|
||||
@pc += 2
|
||||
end
|
||||
|
||||
def write_output!
|
||||
o = peek(parameters[0])
|
||||
log "outputting #{o} from #{parameters[0]}"
|
||||
output.push o
|
||||
@pc += 2
|
||||
end
|
||||
|
||||
def jump_if_true!
|
||||
predicate = peek(parameters[0])
|
||||
log "jumping to #{peek(parameters[1])} if #{predicate}"
|
||||
@pc = predicate > 0 ? peek(parameters[1]) : @pc + 3
|
||||
end
|
||||
|
||||
def jump_if_false!
|
||||
predicate = peek(parameters[0])
|
||||
log "jumping to #{peek(parameters[1])} unless #{predicate}"
|
||||
@pc = predicate == 0 ? peek(parameters[1]) : @pc + 3
|
||||
end
|
||||
|
||||
def less_than!
|
||||
lt = peek(parameters[0]) < peek(parameters[1])
|
||||
poke(parameters[2], lt ? 1 : 0)
|
||||
@pc += 4
|
||||
end
|
||||
|
||||
def equals!
|
||||
eq = peek(parameters[0]) == peek(parameters[1])
|
||||
poke(parameters[2], eq ? 1 : 0)
|
||||
@pc += 4
|
||||
end
|
||||
|
||||
def halt!
|
||||
log "halting!"
|
||||
@stopped = true
|
||||
end
|
||||
|
||||
def instruction
|
||||
peek pc
|
||||
end
|
||||
|
||||
def opcode
|
||||
instruction % 100
|
||||
end
|
||||
|
||||
def parameter_modes
|
||||
[
|
||||
instruction / 100 % 10,
|
||||
instruction / 1000 % 10,
|
||||
instruction / 10000 % 10,
|
||||
]
|
||||
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
|
||||
@ -11,4 +11,4 @@ if [[ -z $source_file ]] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
time (cat ../data/$year/$day/input.txt | ruby -I$year/$day/lib $source_file)
|
||||
time (cat ../data/$year/$day/input.txt | ruby -I$year/$day/lib -I$year/lib $source_file)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user