Befunge (#184)

Hello all,

Here’s my Befunge interpreter, my first submission for a Ruby-Quiz. I’m
a relative Ruby novice, so I doubt it’s as elegant or clever as some of
the other solutions, but it does work, and runs even relatively
complicated Befunge programs such as befbef.bf and life.bf. The one
exception I’ve found so far is mandel.bf - because I chose to store
Befunge-space values as single-character Strings, and because Ruby
Strings will not hold negative (signed) bytes, and finally because
mandel.bf relies on storing negative values in the Befunge-space grid,
it cannot run correctly. I may go back and fix this later.

I intentionally avoided looking at anyone else’s solutions while I was
working on this, as I wanted to keep it a challenge for myself. This may
mean that there are some boneheaded choices in the code, but I did learn
a lot doing this, which I think is the point.

Thanks,

  • Adam G.

On Wed, Nov 26, 2008 at 9:32 PM, [email protected] wrote:

On Wed, Nov 26, 2008 at 4:41 PM, Robert D. [email protected] wrote:

For those who want to play around I have extended Matthew’s code with
some enhancements

Cool, I took a quick run at adding these couple of extensions to my
previous submission:

http://gist.github.com/29673

On Nov 26, 2008, at 8:54 PM, [email protected] wrote:

http://gist.github.com/29673

Note that Befunge-93 was revised and extended a bit into Funge 98
(http://quadium.net/funge/spec98.html
) for those curious. I just got back from vacation, so I haven’t
compared these extensions with F98’s and don’t know if they’re similar
or not.

On Sun, Nov 30, 2008 at 11:04 PM, Matthew M. [email protected] wrote:
b.com/29673

Note that Befunge-93 was revised and extended a bit into Funge 98
(http://quadium.net/funge/spec98.html) for those curious. I just got back
from vacation, so I haven’t compared these extensions with F98’s and don’t
know if they’re similar or not.
By all means check it out but I will share the little I have read
Funge98 is N-dimensional but I have only seen implementation details
for 3 dimensions.
The grid is not limited in size anymore… Befunge93 was an excellent
choice for the Quiz.
:slight_smile:
R.

Forwarding a submission from Chris J.:

====

Here’s my submission for Ruby Q. 184 …

It’s not interactive on the command line, instead the run method takes
a hash with two arrays, one for integer input and the other for ASCII
input. The output is a string. The test/tc_sample_programs.rb file
runs many of the example programs.

Thanks,
Chris

Here is my solution. It’s not a revolutionary implementation, but I
had an emphasis on readability and testing. I believe it correctly
runs all the example programs from the Befunge-93 site that the C
reference implementation does.

While debugging I had a “C interpreter mode” which did a few things
slightly differently such as division and mod with negative numbers to
match the behaviour of the reference implementation. I eventually
removed it for clarity since it didn’t gain much, other than
accounting for those differences.

For example, the following program will output -1 when run with the C
implementation and -2 with a standard Ruby implementation. Solutions
to Ruby Q. #85 have some methods which provide C-like division and
mod.

3-2/.@

I couldn’t find a simple solution for single character input, so it
goes without. Thus for programs like namegame.bf you have to hit enter
between each character.

Spec file is below the source. Thanks for the interesting quiz.

Jeff Dallien

------- befunge.rb

#!/usr/bin/env ruby

Befunge-93 interpreter for Ruby Q. #184

Jeff Dallien ([email protected])

class Stack
attr_reader :stack

def initialize
@stack = []
end

def pop
return 0 if @stack.empty?
@stack.pop
end

def push(value)
@stack.push(value)
end

def swap!
first = pop
second = pop
push(first)
push(second)
end

def dup!
top = pop
push(top)
push(top)
end
end

class Instruction
attr_reader :value

def initialize(value)
@value = value
end

digits 0-9

def value_for_stack?
(@value[0] >= 48 && @value[0] <= 57)
end

" (double quote) toggles string mode

def string_mode_toggle?
(34 == @value[0])
end
end

class ProgramCounter
attr_reader :x
attr_reader :y
attr_accessor :direction

def initialize
@x = 0
@y = 0
@direction = :right
end

def move!
send(“move_#{@direction}!”)
end

private

def move_right!
@x = (@x + 1) % 80
end

def move_left!
@x = (@x - 1) % 80
end

def move_down!
@y = (@y + 1) % 25
end

def move_up!
@y = (@y - 1) % 25
end
end

class BefungeProgram
def initialize
@program = []
end

def load_from_file(filename)
File.open(filename) do |f|
25.times do
add_program_line(f.gets.to_s)
end
end
end

def
@program[index]
end

def load_from_string_array(program_strings)
25.times do |index|
add_program_line(program_strings[index].to_s)
end
end

private

def add_program_line(line)
padded_line = line.chomp[0…80].ljust(80)
@program << padded_line.split(‘’).map { |c| c[0] }
end
end

class Befunger
INSTRUCTION_TABLE = { ‘@’ => :exit,
’ ’ => :blank,
‘\’ => :swap,
‘:’ => :dup,
‘$’ => :pop,
‘,’ => :output_ascii,
‘.’ => :output_int,
‘+’ => :add,
‘-’ => :subtract,
‘*’ => :multiply,
‘/’ => :divide,
‘%’ => :mod,
‘!’ => :not,
‘`’ => :greater,
‘>’ => :pc_right,
‘<’ => :pc_left,
‘^’ => :pc_up,
‘v’ => :pc_down,
‘?’ => :pc_random,
‘_’ => :horizontal_if,
‘|’ => :vertical_if,
‘g’ => :get,
‘p’ => :put,
‘&’ => :input_value,
‘~’ => :input_character,
‘#’ => :bridge,
‘"’ => :toggle_string_mode
}

def initialize(program)
@program = program
@pc = ProgramCounter.new
@stack = Stack.new
@exit_called = false
@string_mode = false
end

def run
until @exit_called
execute_instruction
@pc.move!
end
end

private

used so that output can be captured during testing

def output(value)
print value
STDOUT.flush
end

def read_instruction
Instruction.new(@program[@pc.y][@pc.x].chr)
end

def execute_instruction
instruction = read_instruction

if @string_mode && !instruction.string_mode_toggle?
  @stack.push(instruction.value[0])
elsif instruction.value_for_stack?
  @stack.push(instruction.value.to_i)
else
  begin
    send(INSTRUCTION_TABLE[instruction.value])
  rescue TypeError, NoMethodError
    raise "Unknown instruction: #{instruction.inspect}"
  end
end

end

def exit
@exit_called = true
end

def blank
end

def swap
@stack.swap!
end

def dup
@stack.dup!
end

def pop
@stack.pop
end

def output_ascii
value = @stack.pop
output value.chr
end

def output_int
value = @stack.pop
output "#{value.to_i} "
end

def generic_math_instruction(operation)
rhs = @stack.pop
lhs = @stack.pop
result = lhs.send(operation, rhs)
@stack.push(result)
end

def add
generic_math_instruction(‘+’)
end

def subtract
generic_math_instruction(‘-’)
end

def divide
generic_math_instruction(‘/’)
end

def mod
generic_math_instruction(‘%’)
end

def multiply
generic_math_instruction(‘*’)
end

def not
value = @stack.pop
result = (value == 0) ? 1 : 0
@stack.push(result)
end

def greater
rhs = @stack.pop
lhs = @stack.pop
result = (lhs > rhs) ? 1 : 0
@stack.push(result)
end

def pc_right
@pc.direction = :right
end

def pc_left
@pc.direction = :left
end

def pc_up
@pc.direction = :up
end

def pc_down
@pc.direction = :down
end

def pc_random
directions = [:right, :left, :up, :down]
@pc.direction = directions[rand(4)]
end

def horizontal_if
value = @stack.pop
@pc.direction = (value == 0) ? :right : :left
end

def vertical_if
value = @stack.pop
@pc.direction = (value == 0) ? :down : :up
end

def get
y = @stack.pop
x = @stack.pop
@stack.push(@program[y][x])
end

def put
y = @stack.pop
x = @stack.pop
@program[y][x] = @stack.pop
end

def input_value
input = $stdin.gets.to_i
@stack.push(input)
end

def input_character
input_char = $stdin.gets[0]
@stack.push(input_char)
end

def bridge
@pc.move!
end

def toggle_string_mode
@string_mode = !@string_mode
end
end

if $0 == FILE
if ARGV[0]
program = BefungeProgram.new
program.load_from_file(ARGV[0])
befunger = Befunger.new(program)
befunger.run
else
puts “Usage: ruby befunge.rb program.bf”
end
end

-------- befunge_spec.rb

require ‘befunge’

describe Stack, “popping a value” do
before :each do
@it = Stack.new
end

it “should return a zero when attempting to pop from an empty stack”
do
@it.pop.should == 0
end
end

describe Befunger, “processing instructions” do
before :each do
@output = ‘’
@stack = Stack.new
@pc = ProgramCounter.new
@program = BefungeProgram.new
ProgramCounter.should_receive(:new).and_return(@pc)
Stack.should_receive(:new).and_return(@stack)
end

def run_program(program_strings)
@program.load_from_string_array(program_strings)
processor = Befunger.new(@program)
processor.should_receive(:output).any_number_of_times { |o|
@output << o }
processor.run
end

describe “blank instruction” do
before :each do
run_program([" @",
“111@”,
“@@@@”])
end

it "should not add any value the stack" do
  @stack.pop.should == 0
end

it "should not change the program counter direction" do
  @pc.direction.should == :right
end

end

describe “an unknown instruction” do
it “should raise an error” do
lambda { run_program([“=@”]) }.should raise_error(/Unknown
instruction/)
end
end

describe “add instruction” do
before :each do
run_program([“12+@”])
end

it "should put the result of the addition on the stack" do
 @stack.pop.should == 3
end

end

describe “substract instruction” do
describe “with a positive result” do
before :each do
run_program([“65-@”])
end

  it "should put the correct result on the stack" do
    @stack.pop.should == 1
  end
end

describe "with a negative result" do
  before :each do
    run_program(["56-@"])
  end

  it "should put the correct result on the stack" do
    @stack.pop.should == -1
  end
end

end

describe “multiplication instruction” do
before :each do
run_program([“55*@”])
end

it "should put the correct result on the stack" do
  @stack.pop.should == 25
end

end

describe “mod instruction” do
describe “calculating with positive numbers” do
before :each do
run_program([“52%@”])
end

  it "should put the correct value on the stack" do
    @stack.pop.should == 1
  end
end

describe "calculating with a negative number" do
  before :each do
    run_program(["1-2*3%@"])
  end

  it "should put the correct value on the stack" do
    @stack.pop.should == 1
  end
end

end

describe “division instruction” do
describe “calculating with positive numbers” do
before :each do
run_program([“93/@”])
end

  it "should put the correct value on the stack" do
    @stack.pop.should == 3
  end
end

describe "calculating with negative numbers" do
  before :each do
    run_program(["3-2/@"])
  end

  it "should put the correct negative value on the stack" do
    @stack.pop.should == -2
  end
end

end

describe “swap instruction” do
before :each do
run_program([“123\@”])
end

it "should swap the two top values of the stack" do
  @stack.pop.should == 2
  @stack.pop.should == 3
end

it "should not change the anything below the top two values" do
  @stack.pop
  @stack.pop
  @stack.pop.should == 1
end

end

describe “duplication instruction” do
before :each do
run_program([“1:@”])
end

it "should put two copies of the value on the stack" do
  @stack.pop.should == 1
  @stack.pop.should == 1
end

end

describe “pop instruction” do
before :each do
run_program([“123$@”])
end

it "should remove a value from the stack" do
  @stack.pop.should == 2
  @stack.pop.should == 1
end

it "should not output anything" do
  @output.should == ''
end

end

describe “not instruction” do
describe “with a 0 on the top of the stack” do
before :each do
run_program([“0!@”])
end

  it "should put a 1 on top of the stack" do
    @stack.pop.should == 1
  end

end

describe “with a non-zero value on the top of the stack” do
before :each do
run_program([“1!@”])
end

 it "should put a 0 on top of the stack" do
   @stack.pop.should == 0
 end

end
end

describe “greater instruction” do
describe “with the larger value placed on the stack first” do
before :each do
run_program([“52`@”])
end

  it "should place a 1 on the top of the stack" do
    @stack.pop.should == 1
  end

  it "should remove the compared values from the stack" do
    @stack.pop
    @stack.pop.should == 0
  end
end

describe "with the smaller value placed on the stack first" do
  before :each do
    run_program(["38`@"])
  end

  it "should put a 0 on the top of the stack" do
    @stack.pop.should == 0
  end
end

describe "comparing the same value" do
  before :each do
    run_program(["44`@"])
  end

  it "should place a 0 on the top of the stack" do
    @stack.pop.should == 0
  end
end

end

describe “bridge instruction” do
before :each do
run_program([“123#…@”])
end

it "should skip the next instruction" do
  @output.should == "3 2 "
end

it "should leave remaining values on the stack" do
  @stack.pop.should == 1
end

end

describe “ASCII output instruction” do
before :each do
run_program([“665+*1-,@”])
end

it "should output the ASCII character of the value on the top of

the stack" do
@output.should == “A”
end
end

describe “integer output instruction” do
before :each do
run_program([“665+*1-.@”])
end

it "should output the integer on the top of the stack, followed by

a space" do
@output.should == "65 "
end
end

describe “string mode” do
before :each do
run_program([“"Ab"@”])
end

it "should place the ASCII values on the stack" do
  @stack.pop.should == 98
  @stack.pop.should == 65
end

end

describe “get instruction” do
describe “getting a value from within the given program” do
before :each do
run_program([“11g@”,
" * "])
end

  it "should get the value from the program and put it on the

stack" do
@stack.pop.should == ‘*’[0]
end
end

describe "getting a value outside the given program but in the

program space" do
before :each do
run_program([“88g@”])
end

  it "should put the ASCII value of the space character (32) on

the stack" do
@stack.pop.should == 32
end
end

describe "attempting to get a value outside the 80x25 program

space" do
it “should raise an error” do
lambda { run_program([“066*g@”]) }.should raise_error
end
end
end

describe “put instruction” do
describe “within the 80x25 program space” do
before :each do
run_program([“522p@”])
end

  it "should put the correct value inside the program space" do
    @program[2][2].should == 5
  end
end

describe "outside the 80x25 program space" do
  it "should raise an error" do
    lambda { run_program(["1188*p@"]) }.should raise_error
  end
end

end

describe “horizontal if instruction” do
def horizontal_if_program(stack_value)
run_program(["#{stack_value} v @ ",
'@,“left”_“thgir”, @ ',
’ @ '])
end

describe "with a zero on top of the stack" do
  before :each do
    horizontal_if_program('0')
  end

  it "should move the program counter to the right" do
    @output.should == "right"
  end
end

describe "with a non-zero value on top of the stack" do
  before :each do
    horizontal_if_program('4')
  end

  it "should move the program counter to the left" do
    @output.should == "left"
  end
end

end

describe “vertical if instruction” do
def vertical_if_program(stack_value)
run_program([“#{stack_value} |@”,
’ 5 ',
’ @ ',
’ 4 '])
end

describe "with a zero on top of the stack" do
  before :each do
    vertical_if_program('0')
  end

  it "should move the program counter down" do
    @stack.pop.should == 5
  end
end

describe "with a non-zero value on top of the stack" do
  before :each do
    vertical_if_program('2')
  end

  it "should move the program counter up" do
    @stack.pop.should == 4
  end
end

end

describe “controlling the program counter direction” do
describe “to the up direction” do
before :each do
run_program([" ^@“,
" @”,
" 7"])
end

  it "should set the program counter direction to :up" do
     @pc.direction.should == :up
  end

  it "should move upwards and loop to the bottom of the program"

do
@stack.pop.should == 7
end
end

describe "to the down direction" do
  before :each do
    run_program(["v8@",
                 " @ ",
                 ">v@"])
  end

  it "should set the program counter direction to :down" do
    @pc.direction.should == :down
  end

  it "should move downwards and loop to the top of the program" do
    @stack.pop.should == 8
  end
end

describe "to the left direction" do
  before :each do
    run_program(["<@5"])
  end

  it "should set the program counter direction to :left" do
    @pc.direction.should == :left
  end

  it "should move left and loop to the right side of the program"

do
@stack.pop.should == 5
end
end

describe "to the right direction" do
  describe "as the default direction" do
    before :each do
      run_program(["   1@"])
    end

    it "should set the program counter direction to :right" do
      @pc.direction.should == :right
    end

    it "should move right when a program starts" do
      @stack.pop.should == 1
    end
  end

  describe "and reaching the edge of the program" do
    before :each do
      run_program(["     v ",
                   "2@   > ",
                   "     @ "])
    end

    it "should move right and loop to the left side of the

program" do
@stack.pop.should == 2
end
end
end

describe "in a random direction" do
  before :each do
    srand(3)  # force predictable 'random' numbers, will always

choose :up first
run_program(["v@ ",
“>?@”,
" @ "])
end

  it "should set the program counter direction based on the random

number" do
@pc.direction.should == :up
end
end
end
end

My solution looks like, not surprisingly, a giant case statement; not
worth reprinting here.

I did write my solution test-first, here are my tests. I didn’t do a
full
implementation, but it turned out sufficient to run the “beer” sample
programs.

Thank you for the quiz, Matt, it was fun!

-Kay

require ‘befunge’
require ‘test/unit’

class BefungeTest < Test::Unit::TestCase

def test_output_numbers
befunge(“1234…@”).expect “4321”
end

def test_exit
befunge(“1.@2.@”).expect “1”
end

def test_pop_empty_stack_returns_zero
befunge(".@").expect “0”
end

def test_add
befunge(“12+.@”).expect “3”
end

def test_subtract
befunge(“73-.@”).expect “4”
end

def test_multiply
befunge(“53*.@”).expect “15”
end

def test_divide
befunge(“83/.@”).expect “2”
end

def test_modulo
befunge(“73%.@”).expect “1”
end

def test_not_nonzero_is_zero
befunge(“7!.@”).expect “0”
end

def test_not_zero_is_one
befunge(“0!.@”).expect “1”
end

def test_greater_than
befunge(“43`.@”).expect “1”
end

def test_less_than
befunge(“34`.@”).expect “0”
end

def test_equal
befunge(“44`.@”).expect “0”
end

def test_duplicate
befunge(“5:…@”).expect “55”
end

def test_swap
befunge(‘87…@’).expect “87”
end

def test_skip
befunge(“5#.@”).expect “”
end

def test_pop
befunge(“12$.@”).expect “1”
end

def test_space_is_noop
befunge(“4 .@”).expect(“4”)
end

def test_stringmode
befunge(’“A”.@’).expect(“65”)
end

def test_output_character
befunge(’“A”,@’).expect(“A”)
end

def test_left
befunge(‘12#@.<@’).expect(‘21’)
end

def test_right
befunge(‘1<>@#.’).expect(‘1’)
end

def test_down
befunge( <<EOD
5v@
.
@
EOD
).expect “5”
end

def test_up
befunge( <<EOD
3v@
.

^@
EOD
).expect “3”
end

def test_loop_around_right
befunge( <<EOD
v
.@>1
EOD
).expect “1”
end

def test_loop_around_down
befunge( <<EOD
1v
.
@
v<
EOD
).expect(“1”)
end

def test_if_goes_right_if_zero
befunge(“0:_.@”).expect “0”
end

def test_if_goes_left_if_nonzero
befunge(“5:_.@”).expect “”
end

def test_if_goes_up_if_nonzero
befunge( <.@

1:|@
@
EOD
).expect(“1”)
end

def test_if_goes_down_if_zero
befunge( <<EOD
v @

0:|@
.@
EOD
).expect(“0”)
end

def test_pad_input_lines_to_maximum_length
befunge( <<EOD
1:v @

2^
EOD
).expect(“1”)
end

protected

def befunge(input)
@befunge = Befunge.new(input)
self
end

def expect(expected)
assert_equal expected, @befunge.output
end

end

Writing a Befunge interpreter isn’t terribly difficult. Some things
need to be handled with care – stack underflow and program counter
wraparound, for example – but overall Befunge is a pretty
straightforward, stack-based language. That the program counter can
move in two dimensions isn’t really cumbersome in itself. The
interpreter still executes code sequentially; code just “bends” about
to suit the user’s whim. I suspect most any Befunge program could be
written in a single line, though it’s certainly more convenient to
have a 2D space.

I’m not going to do a long summary of any one of the interpreters.
Most of the code I saw was easy to understand. For younger Rubyists,
check out my solution (i.e. the first solution by Matthew M.) for a
plain, simple, no-frills approach. There is very little in my code
that is spectacularly Ruby specific. (Also excuse a few bugs in my
code; some, but not all, were discussed on the mailing list, but I
never got around to revising my submission.)

For a summary, I will compare a few pieces of different solutions,
just to show the various techniques used while writing these
interpreters. Befunge isn’t so fancy that it needs a fancy solution,
but of course these techniques are certainly applicable to more
complex systems.

First, a brief look at the stack. There really isn’t much needed here,
since Ruby’s Array provides push and pop methods, and so can act
as a stack with no extra code. However, one minor detail of Befunge is
that if you pop an empty stack, it should return zero. Several
submissions did this with a custom version of pop:

 def pop
   @stack.pop || 0
 end

If @stack is an empty array, pop returns nil. As nil evaluates
to false in a boolean context, the logical-or operator || will then
evaluate the right side, returning zero. If pop returned an actual
value, the logical-or operator would short-circuit, skipping the right
side. It works very similar to another submissions version of pop:

 def pop
   x = @stack.pop
   x.nil? ? 0 : x
 end

This is more explicit in intent, and perhaps clearer for those
unfamiliar with ||.

Let’s look next at some implementations of the program counter. One
implementation looked like this (code stripped down to relevant
portions):

 PC = Struct.new(:row, :col, :direction)
 @pc = PC.new(0, 0, :right)

def current_cell
@program[@pc.row][@pc.col]
end

 def tick_pc
   case @pc.direction
   when :right
     if @pc.col == @program[@pc.row].size - 1
       @pc.col = 0
     else
       @pc.col += 1
     end
   # other direction cases here... implemented similarly
   end
 end

I like the use of Struct here to easily create a class (PC) with
well-named members row and col. These seem more appropriate than
x and y, since the typical access pattern into a 2D array (often
as pulled from the file) will be row-first, then column. As you can
see in current_cell here, the names make it very clear.
@program[@pc.y][@pc.x] would also be correct, but the order of x and
y is reversed from what might be expected, and so could be a source of
bugs if the coder does not pay careful attention to this detail.

While I like the struct and cell access here, updating the program
counter is a little cumbersome; it’s not wrong, but it is a lot of
code for what should be a simple operation: modular addition. Here is
a version that’s much more compact:

 def step
   case @direction
   when :right:  @PC_x += 1
   when :left:    @PC_x -= 1
   when :down:    @PC_y += 1
   when :up:    @PC_y -= 1
   end
   @PC_x %= 80
   @PC_y %= 25
 end

There is excess work being done: if @PC_x is updated, for example,
we don’t need to modulate @PC_y. However, the cost of this is
likely to be rather low. The alternative is simply to move the modulo
operations up into each case: minor code duplication for minor
performance gains. Personally, I’d leave it as it is.

One note on the modulo operator. My own solution modified the program
counter as such:

 @pc[0] = (@pc[0] - 1 + @hgt) % @hgt

Adding in @hgt before taking the modulo by @hgt was insurance that
I would get an expected value, not knowing ahead of time whether the
modulus of a negative number (as could happen if I simply subtracted 1
from the pc) would be positive or negative. As it turns out, Ruby
keeps the result positive if the second argument of the modulus
operator is positive, so my insurance here was unnecessary.

Finally, let’s take a look at “method” dispatch. As the program
counter moves through the Befunge source code, each character
represents an operation to be performed. The naive (umm… old-skool)
implementation is a big case statement:

 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 ?,
 print pop.chr
  when ?>
    @dir = :east
  # ...

Not very Rubyish. Let’s look at something cooler. A number of
solutions used a “code block” technique, creating a hash of code
blocks, the various Befunge symbols as keys into that hash. Here’s a
portion of one submission:

 module Befunge
   Commands = {
     "0" => lambda { @stack.push(0) },
     "1" => lambda { @stack.push(1) },
     "2" => lambda { @stack.push(2) },
     # ...
     "*" => lambda { @stack.push(@stack.pop * @stack.pop) },
     "/" => lambda { val2, val1 = @stack.pop, @stack.pop;

@stack.push(val1 / val2) },
“%” => lambda { val2, val1 = @stack.pop, @stack.pop;
@stack.push(val1 % val2) },
# …
“>” => lambda { @pc.direction = :right },
“<” => lambda { @pc.direction = :left },
# …
}
end

Executing the appropriate lambda block is done like so:

 def process_cell
   cell = current_cell
   raise "Unknown command: #{cell} at (#{@pc.col}, #{@pc.row})"

if !Commands.include? cell
instance_eval(&Commands[cell])
cell
end

cell is looked up in the Commands hash and passed to
instance_eval. This executes the code block in the context of the
interpreter (i.e. the object of process_cell). This ensures that the
interpreter’s @stack and @pc, etc. are available for access by
these code blocks.

One last technique for handling these various commands is the “define
method” technique: each Befunge symbol becomes a method of the
interpreter. Here is a portion of that submission:

 class Befunge93
   instance_methods.each { |m| undef_method m unless (m =~ /^__|

send/) }

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

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

# etc...

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

end

First, notice that we have code right in the class definition, outside
of any method. If you’re new to Ruby, this may look rather strange,
but this code executes when the class is defined. Quite a handy thing:
code that executes once at definition let’s you do some very meta-ish
things.

Here, we start with the interesting line at the top enumerating over
all the class’ instance methods. Most methods (except for send and a
few special methods) are undefined; this gives us a “clean” object
free of any methods that would interfere with the Befunge methods.

Next, define_method is called for all the Befunge symbols. (Only
some shown here.) Inside define_method is the code for that
particular Befunge symbols. Since we are defining instance methods on
the interpreter itself, these bits of code can access other instance
methods (such as pop). This sort of technique is very convenient for
the digits and the arithmetic operators shown above, as their
implementation is nearly identical. The direction changing commands
are handled in a similar way, though the rest of the commands must be
done individually (at which point, the hash of lambdas is more compact).

Finally, note how these defined methods are executed in run: via the
send method, one of the few that was allowed to remain. The Befunge
symbol is accessed via @memory[@position] and sent to the interpreter.

Thanks for all the submissions! I intentionally wrote a simple, case-
based interpreter in the hopes that others would provide some more
Ruby-ish solutions, and we got 'em. Now I’m off to write a Ruby
interpreter in Befunge…

Befunge (#184)

I haven’t actually finished a Ruby Q. since #13. Four years is a
long time! But this one I had to do. Literally the day before the quiz
was posted I was talking with some coworkers about Befunge, Brainf*ck,
and the like. That this was the very next Ruby Q. was fate.

Because I was going slowly, I peeked at some of the answers here, I
did borrow a little. I love to use the Hash of Procs approach to the
the command pattern, which someone here talked about. Matthew’s trick
using % to do the wrap-arounds was really cool, so I had to use that.

Most importantly, even before I saw all the talk about writing a
debugger, I had decided the real challenge was to make a GUI IDE for
Befunge. After looking at some options, I decided to implement it in
Rails. So that gave me a few days in which to learn Rails (I’ve been
procrastinating a few years on that). I also had to move my personal
web site to a Rails-friendly host (and way more Ruby/programmer
friendly, in general). So this quiz really helped me get going on my
“professional development” to-do list. :slight_smile:

I didn’t quite get all the way to an IDE, but it is fun to watch a
Befunge program execute. With fancy 2D graphics and 8-bit color and
everything.

I also didn’t conquer the input problem, so I just have stub methods
that use random numbers for that.

So here my befunge.rb – which acts as interpreter, debugger, and
Rails model class (you’d drop it in app/models)

If you want to see the Rails-based Befunge “IDE” in action, head over
to http://www.mikelibby.com/befunge

If anyone wants to see the relevant Rails bits, just ask and I’ll put
it on GitHub.

-Michael C. Libby
www.mikelibby.com