From: Matthew Moss Date: 2008-11-25T07:01:30+09:00 Subject: Re: [QUIZ] Befunge (#184) Hopefully the quiz isn't intimidating... It's a fairly simple language to implement. It took me about 30 minutes to get a simple, straightforward version working (my submission, shown below), and I may do some revisions later to try shrinking the code and making it more Ruby-ish. (Also to handle some conditions not currently handled well...) I mostly want to revise the run and step methods to be less case-y. Feel free to steal this and make it better, or just to look at to get an idea of how to implement your own. #!/usr/bin/env ruby class Befunge93 def self.load_and_run(filename) self.new(File.read(filename)).run end def initialize(text) rows = text.split(/[\r\n]+/) # split input into rows @hgt = rows.size # find program height @wid = rows.max { |a, b| a.size <=> b.size }.size # find program width @code = rows.map { |row| row + " " * (@wid - row.size) } # pad rows, store code (r, c) @pc, @dir = [0, 0], :east @stack = [] @stringmode = false end def run loop do if @stringmode case curr when ?" @stringmode = false else push curr end else case curr when ?0..?9 push (curr - ?0) when ?+, ?-, ?*, ?/, ?% b, a = pop, pop push a.send(curr.to_sym, b) when ?! push (pop.zero? ? 1 : 0) when ?` b, a = pop, pop push (a > b ? 1 : 0) when ?. puts pop when ?> @dir = :east when ?< @dir = :west when ?^ @dir = :north when ?v @dir = :south when ?? @dir = [:east, :west, :north, :south][rand(4)] when ?_ @dir = pop.zero? ? :east : :west when ?| @dir = pop.zero? ? :south : :north when ?" @stringmode = true when ?: push top when ?\\ a = pop # what about underflow? b = pop push a push b when ?$ pop when ?. print pop when ?, print pop.chr when ?# step when ?g r, c = pop, pop push @code[r][c] when ?p r, c, v = pop, pop, pop @code[r][c] = v when ?& print "int?> " push gets.to_i when ?~ print "chr?> " push gets[0] # Ruby 1.8, maybe not 1.9? when ?@ break end end step # move program counter end end private def curr @code[ @pc[0] ][ @pc[1] ] end def step case @dir when :north @pc[0] = (@pc[0] - 1 + @hgt) % @hgt when :south @pc[0] = (@pc[0] + 1) % @hgt when :east @pc[1] = (@pc[1] + 1) % @wid when :west @pc[1] = (@pc[1] - 1 + @wid) % @wid end end def push(val) @stack.push(val) end def pop @stack.pop || 0 end def top @stack.last || 0 end end if __FILE__ == $0 Befunge93.load_and_run(ARGV.shift) end