On Tue, Nov 25, 2008 at 11:07 AM,  <brabuhr / gmail.com> wrote:
> My first thought was a big case statement like that, but wanted
> something a bit more "fun".  My next thoughts were to try something
> with lambda or define_method.  Here's a really rough, partial (and
> almost entirely untested) implementation built around define_method:

Still not-tested :(, but less-incomplete:

class Befunge93
  instance_methods.each { |m| undef_method m unless (m =~ /^__|send/) }
  attr_accessor :stack, :memory, :position, :direction

  def initialize
    @stack, @memory, @position, @direction = [], {}, [0,0], [1,0]
  end

  def move
    @position[0] = (@position[0] + @direction[0]) % 80
    @position[1] = (@position[1] + @direction[1]) % 25
  end

  def run
    loop do
      send @memory[@position]
      move
    end
  end

  (0..9).each do |d|
    define_method :"#{d}" do
      @stack.push d
    end
  end

  %w{ + - * / % }.each do |o|
    define_method :"#{o}" do
      a, b = @stack.pop, @stack.pop
      @stack.push b.send(:"#{o}", a)
    end
  end

  define_method :"!" do
    @stack.pop.zero? ? 1 : 0
  end

  define_method :"`" do
    a, b = @stack.pop, @stack.pop
    @stack.push (b > a ? 1 : 0)
  end

  define_method :":" do
    @stack.push @stack.last
  end

  define_method :"\\" do
    a, b = @stack.pop, @stack.pop
    @stack.push a; @stack.push b
  end

  define_method :"$" do
    @stack.pop
  end

  [
    [ '^', [ 0,-1] ],
    [ 'v', [ 0, 1] ],
    [ '<', [-1, 0] ],
    [ '>', [ 1, 0] ]
  ].each do |d|
    define_method :"#{d[0]}" do
      @direction = d[1]
    end
  end

  define_method :"?" do
    [[0,-1],[0,1],[-1,0],[1,0]][rand(4)]
  end

  [
    [ '_', [ 0, 1], [ 0,-1] ],
    [ '|', [ 1, 0], [-1, 0] ]
  ].each do |d|
    define_method :"#{d[0]}" do
      @direction = (@stack.pop.zero? ? d[1] : d[2])
    end
  end

  define_method :"#" do
    move
  end

  define_method :"." do
    print @stack.pop
  end

  define_method :"," do
    print @stack.pop.chr
  end

  define_method :"&" do
    push gets.to_i
  end

  define_method :"~" do
    push getc
  end

  define_method :g do
    a, b = @stack.pop, @stack.pop
    @stack.push @memory[[b,a]]
  end

  define_method :p do
    a, b, c = @stack.pop, @stack.pop, @stack.pop
    @memory[[b,a]] = c
  end

  define_method :"@" do
    puts
    exit
  end

  define_method :"\"" do
    move
    until (a = @memory[@position]) == "\""
      a[0,1].each_byte{|b| @stack.push b}
      move
    end
  end

  define_method :" " do
  end
end

bf = Befunge93.new

#bf.memory = {
#  [0,0] => "v", [1,0] => " ", [2,0] => " ", [3,0] => " ", [4,0] => " ",
#  [0,1] => "1", [1,1] => "v", [2,1] => "<", [3,1] => " ", [4,1] => " ",
#  [0,2] => "1", [1,2] => "3", [2,2] => "2", [3,2] => " ", [4,2] => " ",
#  [0,3] => ">", [1,3] => "+", [2,3] => "^", [3,3] => " ", [4,3] => " ",
#  [0,4] => " ", [1,4] => "-", [2,4] => " ", [3,4] => " ", [4,4] => " ",
#  [0,5] => " ", [1,5] => ".", [2,5] => " ", [3,5] => " ", [4,5] => " ",
#  [0,6] => " ", [1,6] => "@", [2,6] => " ", [3,6] => " ", [4,6] => " ",
#  [0,7] => " ", [1,7] => " ", [2,7] => " ", [3,7] => " ", [4,7] => " ",
#  [0,8] => " ", [1,8] => " ", [2,8] => " ", [3,8] => " ", [4,8] => " ",
#}
#bf.run #=> -3

s = ">              vv  ,,,,,\"Hello\"<>48*,          vv,,,,,,\"World!\"<>25*,@"
16.times{|a|
  5.times{|b|
    bf.memory[[a,b]] = s[a + (b * 16), 1]
  }
}

bf.run #=> "Hello World!\n"