バグ修正 というか仕様くらいよもう Befunge
全然読んでなかった(爆)
http://catseye.tc/projects/befunge93/doc/befunge93.html
A Befunge-93 program is treated as an 80x25 torus
なんて馬鹿なんだおいら。というわけで修正しました。
def load_program(prog) @prog = prog.split("\n") @width = 80 @height = 25 @prog = @prog.map {|l| l.ljust(@width)} + ["".ljust(@width)] * (25 - @prog.length) end
いわもとさんのご指摘、
Befunge-93ではコード領域は80x25と決まっているので、初めから80x25分確保してしまってもいいのかも知れません。
をみて、一瞬「width_max , height_max で torus 。putで毎回最大値チェックして torus範囲が変わる」というbefunge改を連想してしまったのだけれど、それは面倒。これでいいや。
追記:
バカしてしまった。なんて天然教育的配慮人間なんだろう僕って。上のままでは "".ljust(*)は全部同じものをさしてしまう。うーん、別インスタンスにするうまい方法がわからない。
def load_program(prog) @prog = prog.split("\n") @width = 80 @height = 25 (25-@prog.length).times {|i| @prog += [""] } @prog = @prog.map {|l| l.ljust(@width)} end
あんまりかっこいい実装ではないけど、とりいそぎ修正。
追記2:
さらにこうしたほうが良い気がしてきた。前のままだと""の中とか Stringになってしまうので演算とか出来ない。
120c120 < @stack.push read_raw(Point.new(x,y)) --- > @stack.push read_raw(Point.new(x,y)).ord 126,127c126,127 < v = @stack.pop.chr < write_raw(Point.new(x,y), v) --- > v = @stack.pop > write_raw(Point.new(x,y), v.chr) 147c147 < @stack.push(c) --- > @stack.push(c.ord) 165c165 < when ?~ then @stack.push STDIN.getc --- > when ?~ then @stack.push STDIN.getc.ord
全体に反映済。
全体:
#!/usr/bin/env ruby # for <=1.8.6 compatibility # added by K.Iwamoto unless String.method_defined? :ord class String def ord self[0] end end end # for <=1.8.6 compatibility # added by K.Iwamoto unless Integer.method_defined? :ord class Integer def ord self end end end class VM class Stack < Array def pop v = super v ? v: 0 end # added by K.Iwamoto def last empty? ? 0 : super end end class Point attr_accessor :x, :y def initialize(x,y) @x = x @y = y end def to_s "(#{x} , #{y})" end end attr_reader :dir UP = 0 DOWN = 1 LEFT = 2 RIGHT = 3 DIR = {'>'=>RIGHT, '<'=>LEFT, '^'=>UP, 'v'=>DOWN} attr_reader :state MODE_NORMAL = 0 MODE_STRING = 1 attr_reader :curpos attr_reader :stack attr_reader :prog OP = { '+' => Proc.new { |x,y| x + y }, '-' => Proc.new { |x,y| x - y }, '*' => Proc.new { |x,y| x * y }, '/' => Proc.new { |x,y| x / y }, '%' => Proc.new { |x,y| x % y } } def read_raw(p) @prog[p.y][p.x] end def write_raw(p, v) @prog[p.y][p.x] = v end def read read_raw(@curpos) end def initialize(prog=nil) @stack = Stack.new @curpos = Point.new(0,0) @dir = RIGHT @state = MODE_NORMAL @debug = false if prog then load_program(prog) end end def load_program(prog) @prog = prog.split("\n") @width = 80 @height = 25 (25-@prog.length).times {|i| @prog += [""] } @prog = @prog.map {|l| l.ljust(@width)} end def nextpos case @dir when RIGHT @curpos.x = (@curpos.x+1) % @width when LEFT @curpos.x = (@curpos.x-1) % @width when UP @curpos.y = (@curpos.y-1) % @height when DOWN @curpos.y = (@curpos.y+1) % @height end end # utils for isrns def doublequote @state = (MODE_STRING+MODE_NORMAL) - @state end def changedir(pred, oneway, anotherway) @dir = (pred == 0)? oneway : anotherway end def swaplast2 t = @stack.pop @stack.push(t, @stack.pop) end def alu(op) y = @stack.pop x = @stack.pop @stack.push OP[op].call(x,y) end def cmp y = @stack.pop x = @stack.pop @stack.push x > y ? 1 : 0 end def negate @stack.push @stack.pop == 1? 0 : 1 end def get y = @stack.pop x = @stack.pop @stack.push read_raw(Point.new(x,y)).ord end def put y = @stack.pop x = @stack.pop v = @stack.pop write_raw(Point.new(x,y), v.chr) end def show_program if @debug STDERR.puts @prog.join("-\n") end end # main dispatcher def step(n=1) c = read if @debug STDERR.print "pos: #{@curpos} mnemonic: #{c.chr} " STDERR.puts "dir: #{@dir} stack: #{@stack.join(',')}" end if @state == MODE_STRING && c != ?" @stack.push(c.ord) else case c #control when ?v,?<,?>,?^ then @dir = DIR[c.chr] when ?_ then changedir(@stack.pop, RIGHT, LEFT) when ?| then changedir(@stack.pop, DOWN, UP ) when ?? then @dir = rand(4) when ?# then nextpos # through! when ?@ then return false #literal when ?0 .. ?9 then @stack.push c.chr.to_i when ?" then doublequote #I/O when ?& then @stack.push STDIN.readline.to_i when ?~ then @stack.push STDIN.getc.ord when ?. then print @stack.pop when ?, then print @stack.pop.chr #arith & logic when ?+,?-,?*,?/,?% then alu(c.chr) when ?` then cmp when ?! then negate #stack manip when ?: then @stack.push @stack.last when ?\\ then swaplast2 when ?$ then @stack.pop #just discard #mem manip when ?g then get when ?p then put #debug when ?= then show_program end end nextpos end def debugenable @debug = true end end vm = VM.new if ARGV[0] == "-d" ARGV.shift vm.debugenable end begin vm.load_program(File.open(ARGV[0]).read) rescue puts "#{$0}: file not found" exit end while vm.step end
debug専用の変な命令 '='を入れてしまった。 -d 時に = を読むと全プログラムスペースを表示する。
"egoh@...."44p45p46p47p48pv 0123v = <
pos: (0 , 0) mnemonic: " dir: 3 stack: pos: (1 , 0) mnemonic: e dir: 3 stack: pos: (2 , 0) mnemonic: g dir: 3 stack: e pos: (3 , 0) mnemonic: o dir: 3 stack: e,g pos: (4 , 0) mnemonic: h dir: 3 stack: e,g,o pos: (5 , 0) mnemonic: @ dir: 3 stack: e,g,o,h pos: (6 , 0) mnemonic: . dir: 3 stack: e,g,o,h,@ pos: (7 , 0) mnemonic: . dir: 3 stack: e,g,o,h,@,. pos: (8 , 0) mnemonic: . dir: 3 stack: e,g,o,h,@,.,. pos: (9 , 0) mnemonic: . dir: 3 stack: e,g,o,h,@,.,.,. pos: (10 , 0) mnemonic: " dir: 3 stack: e,g,o,h,@,.,.,.,. pos: (11 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@,.,.,.,. pos: (12 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@,.,.,.,.,4 pos: (13 , 0) mnemonic: p dir: 3 stack: e,g,o,h,@,.,.,.,.,4,4 pos: (14 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@,.,.,. pos: (15 , 0) mnemonic: 5 dir: 3 stack: e,g,o,h,@,.,.,.,4 pos: (16 , 0) mnemonic: p dir: 3 stack: e,g,o,h,@,.,.,.,4,5 pos: (17 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@,.,. pos: (18 , 0) mnemonic: 6 dir: 3 stack: e,g,o,h,@,.,.,4 pos: (19 , 0) mnemonic: p dir: 3 stack: e,g,o,h,@,.,.,4,6 pos: (20 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@,. pos: (21 , 0) mnemonic: 7 dir: 3 stack: e,g,o,h,@,.,4 pos: (22 , 0) mnemonic: p dir: 3 stack: e,g,o,h,@,.,4,7 pos: (23 , 0) mnemonic: 4 dir: 3 stack: e,g,o,h,@ pos: (24 , 0) mnemonic: 8 dir: 3 stack: e,g,o,h,@,4 pos: (25 , 0) mnemonic: p dir: 3 stack: e,g,o,h,@,4,8 pos: (26 , 0) mnemonic: v dir: 3 stack: e,g,o,h pos: (26 , 1) mnemonic: < dir: 1 stack: e,g,o,h pos: (25 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (24 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (23 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (22 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (21 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (20 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (19 , 1) mnemonic: = dir: 2 stack: e,g,o,h "egoh@...."44p45p46p47p48pv - 0123v = < - - - . - . - . - . - @ - - - - - - - - - - - - - - - - pos: (18 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (17 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (16 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (15 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (14 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (13 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (12 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (11 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (10 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (9 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (8 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (7 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (6 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (5 , 1) mnemonic: dir: 2 stack: e,g,o,h pos: (4 , 1) mnemonic: v dir: 2 stack: e,g,o,h pos: (4 , 2) mnemonic: dir: 1 stack: e,g,o,h pos: (4 , 3) mnemonic: dir: 1 stack: e,g,o,h pos: (4 , 4) mnemonic: . dir: 1 stack: e,g,o,h pos: (4 , 5) mnemonic: . dir: 1 stack: e,g,o pos: (4 , 6) mnemonic: . dir: 1 stack: e,g pos: (4 , 7) mnemonic: . dir: 1 stack: e pos: (4 , 8) mnemonic: @ dir: 1 stack: hoge