Skip to content

Instantly share code, notes, and snippets.

@guicattani
Last active May 2, 2024 09:19
Show Gist options
  • Save guicattani/6fc7cf0a15c2fa7dbc3efd87d2afe707 to your computer and use it in GitHub Desktop.
Save guicattani/6fc7cf0a15c2fa7dbc3efd87d2afe707 to your computer and use it in GitHub Desktop.
Ruby interpreter for Esoteric Language Befunge https://en.wikipedia.org/wiki/Befunge
def interpret(code)
Befunge.new(code).interpret
end
class Array
def second
self[1]
end
def second=(val)
self[1]=val
end
def first=(val)
self[0]=val
end
end
class Befunge
attr_accessor :pointer, :stack, :current_direction
attr_reader :code_map, :code
def initialize(code)
@code = code
@pointer = [0,0]
@stack = []
@code_map = []
@current_direction = ">"
create_map!
end
def interpret
output = ""
while(true) do
val = code_map[pointer.first][pointer.second]
val ||= " "
case
when val.match(/\d/)
stack << val.to_i
when val == "+"
stack << stack.pop + stack.pop
when val == "-"
a = stack.pop.to_i
b = stack.pop.to_i
stack << b - a
when val == "*"
stack << stack.pop.to_i * stack.pop.to_i
when val == "/"
a = stack.pop.to_i
b = stack.pop.to_i
a.zero? ? stack << 0 : stack << floor(b / a)
when val == "%"
a = stack.pop.to_i
b = stack.pop.to_i
stack << b % a
when val == "!"
stack << (stack.pop.to_i.zero? ? 1 : 0)
when val == "`"
stack << (stack.pop < stack.pop ? 1 : 0)
when val == "?"
self.current_direction = "><v^".chars.shuffle.pop
when val == "_"
self.current_direction = (stack.pop.to_i.zero? ? ">" : "<")
when val == "|"
self.current_direction = (stack.pop.to_i.zero? ? "v" : "^")
when val =='"'
move!
while(code_map[pointer.first][pointer.second] != '"')
stack << code_map[pointer.first][pointer.second].ord
move!
end
when val ==":"
stack.empty? ? stack << 0 : stack << stack.last
when val == '\\'
a = stack.pop
b = stack.pop
a ||= 0
b ||= 0
stack << a
stack << b
when val == "$"
stack.pop
when val == "."
output += stack.pop.to_s
when val == ","
output += stack.pop.chr.to_s
when val == "#"
move!
when val == "p"
x = stack.pop
y = stack.pop
v = stack.pop
code_map[x][y] = v
when val == "g"
x = stack.pop
y = stack.pop
stack << code_map[x][y].ord
when val == "@"
break
end
move!(val)
end
output
end
private
def create_map!
code.split("\n").each {|line| @code_map << line.chars}
end
def move!(direction = "")
direction = current_direction if !direction.match(/[><\^v]/)
case direction
when ">"
self.current_direction = ">"
pointer.second += 1
pointer.second = 0 if code_map[pointer.first][pointer.second].nil?
when "<"
self.current_direction = "<"
pointer.second -= 1
if code_map[pointer.first][pointer.second].nil?
pointer.second = code_map[pointer.first].size
end
when "v"
self.current_direction = "v"
pointer.first += 1
pointer.first = 0 if pointer.first > code_map.size + 1
when "^"
self.current_direction = "^"
pointer.first -= 1
pointer.first = code_map.size - 1 if pointer.first < 0
end
end
end
one_to_nine = ">987v>.v\nv456< :\n>321 ^ _@"
hello_world = ">25*\"!dlrow ,olleH\":v\n v:,_@\n > ^"
factorial_8 = "8>:1-:v v *_$.@ \n ^ _$>\\:^"
sieve_of_eratosthenes = "2>:3g\" \"-!v\\ g30 <\n" +
" |!`\"O\":+1_:.:03p>03g+:\"O\"`|\n"+
" @ ^ p3\\\" \":<\n"+
"2 234567890123456789012345678901234567890123456789012345678901234567890123456789"
Befunge.new(one_to_nine).interpret
Befunge.new(hello_world).interpret
Befunge.new(factorial_8).interpret
Befunge.new(sieve_of_eratosthenes).interpret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment