今天寫的一個 Ruby 程式,解 Interpreter 這個問題:
# PC/UVa IDs: 110106/10033
class Computer
def initialize(file)
@regs = Array.new(10, 0)
@ram = Array.new(1000, 0)
load_inst(file)
end
def load_inst(file)
pc = 0
file.each_line do |line|
line.chomp!
line.strip!
if line.length > 0 then
@ram[pc] = line
pc += 1
elsif pc > 0
break
end
end
end
MAX_INST = 1000
def execute
executed = 0
pc = 0
opcodes =
{
'1' => Proc.new { return executed },
'2' => Proc.new { |d,n| @regs[d] = n; @regs[d] %= MAX_INST },
'3' => Proc.new { |d,n| @regs[d] += n; @regs[d] %= MAX_INST },
'4' => Proc.new { |d,n| @regs[d] *= n; @regs[d] %= MAX_INST },
'5' => Proc.new { |d,s| @regs[d] = @regs[s]; @regs[d] %= MAX_INST },
'6' => Proc.new { |d,s| @regs[d] += @regs[s]; @regs[d] %= MAX_INST },
'7' => Proc.new { |d,s| @regs[d] *= @regs[s]; @regs[d] %= MAX_INST },
'8' => Proc.new { |d,a| @regs[d] = @ram[@regs[a]] },
'9' => Proc.new { |s,a| @ram[@regs[a]] = @regs[s] },
'0' => Proc.new { |d,s| pc = @regs[d] if @regs[s] != 0 },
}
loop do
break unless /(\d)(\d)(\d)/ =~ @ram[pc]
pc += 1
executed += 1
opcodes[$1][$2.to_i, $3.to_i]
end
end
end
fail "No input is given" if ARGV.length < 1
cases = 0
file = File.new(ARGV[0], "r")
file.each_line do |line|
cases = line.chomp.strip.to_i
break if cases > 0
end
# puts "There are #{cases} cases"
cases.times do
puts Computer.new(file).execute
end
file.close
本來是用 case 平鋪直述地去執行所有指令,後來想了一下發覺用 hash 來做 opcode 的實作也蠻酷的。