Ora
Ora is a (semi)reversible language created by User:zeotrope, it is influenced heavily by 2D-Reverse.
Instructions
- $ : Start position of program, moving right. u, d, l and r may also be used instead of $ to specify both a start position and direction.
- @ : Ends program.
- \ : Right reflector.
- / : Left reflector.
- - : Vertical reflector, does nothing if encountered when moving horizontally.
- | : Horizontal reflector, does nothing if encountered when moving vertically.
- C : Clockwise Rotate.
- A : Anti-clockwise Rotate.
- X : If current buffer element is non zero acts like a right reflector, otherwise it acts like a left reflector.
- x : If current buffer element is non zero acts like a left reflector, otherwise it acts like a right reflector.
- u : Set pointer direction to up.
- d : Set pointer direction to down.
- l : Set pointer direction to left.
- r : Set pointer direction to right.
Operation
The program pointer starts travelling at the $ symbol, moving towards the right. The starting direction may be altered by using the u, d, l and r instructions as a start instruction instead of $.
If the program encounters a space or a "." as it moves it manipulates an infinite one dimensional buffer based on the direction it is travelling in the following manner:
- If the program is moving right the current buffer element is incremented.
- If the program is moving left the current buffer element is decremented.
- If the program is moving up the next (right) buffer element is set as the current element.
- If the program is moving up the previous (left) buffer element is set as the current element.
If a program move is performed without encountering a "." or a space, none of the above is executed.
Examples
Cell Clear
Decrement current buffer element until it is zero.
/.A
$....r-x
@
Brainfuck equivalent:
++++[-]
Rewind
Move left along buffer until a zero element is encountered, increment it.
/.\/.@
. rX
/./ |.
. \/
/./
.
$-/
Brainfuck equivalent:
>+>+>+[<]>
Clear Previous Cell
Decrement current buffer cell and all previous buffer cells until zero, stop at first zero encountered.
/..\
. |/.A
r../ \r-x
| .
\-x@
Add
Add 3 and 4.
/...\/-----\
. .|@ |
$..../ \rX /.\|
/./ . .|
\---/ \/
Interpreter
class TwoD
attr_reader :prog, :len, :current, :bf
attr_accessor :pos, :direction, :bpos, :buffer
def initialize(string)
@prog = string.split("\n").collect {|x| x.split("")}
@len = @prog.length
@direction = :right
@bpos = 0
@buffer = [0]
@bf = []
locate_start
read_current
end
def gen_bf(i)
@bf << i
end
def print_bf
puts ""
@bf.each {|x| print x}
puts ""
end
def locate_start
@pos = [0, 0]
(0..@len-1).each do |i|
case
when @prog[i].include?("$") then
@pos = [i, @prog[i].index("$")]
when @prog[i].include?("u") then
@pos = [i, @prog[i].index("u")]
@direction = :up
when @prog[i].include?("d") then
@pos = [i, @prog[i].index("d")]
@direction = :down
when @prog[i].include?("l") then
@pos = [i, @prog[i].index("l")]
@direction = :left
when @prog[i].include?("r") then
@pos = [i, @prog[i].index("r")]
@direction = :right
end
end
end
def read_current
@current = @prog[@pos[0]][@pos[1]]
end
def buffer_right
if (@bpos += 1) >= @buffer.length
@buffer << 0
end
gen_bf(">")
end
def buffer_left
if (@bpos -= 1) < 0
@buffer = [0]+@buffer
end
gen_bf("<")
end
def step
case @direction
when :up then @pos[0] -= 1
when :down then @pos[0] += 1
when :right then @pos[1] += 1
when :left then @pos[1] -= 1
end
read_current
eval
end
def eval_spaces
case @direction
when :up then buffer_right
when :down then buffer_left
when :left then @buffer[@bpos] -= 1; gen_bf("-")
when :right then @buffer[@bpos] += 1; gen_bf("+")
end
end
def eval
case @current
when "/" then
case @direction
when :up then @direction = :right
when :down then @direction = :left
when :left then @direction = :down
when :right then @direction = :up
end
when "\\" then
case @direction
when :up then @direction = :left
when :down then @direction = :right
when :left then @direction = :up
when :right then @direction = :down
end
when "C" then
case @direction
when :up then @direction = :right
when :down then @direction = :left
when :left then @direction = :up
when :right then @direction = :down
end
when "A" then
case @direction
when :up then @direction = :left
when :down then @direction = :right
when :left then @direction = :down
when :right then @direction = :up
end
when "X" then
if @buffer[@bpos] != 0
@current = "\\"
else
@current = "/"
end
eval
when "x" then
if @buffer[@bpos] != 0
@current = "/"
else
@current = "\\"
end
eval
when "u" then @direction = :up
when "d" then @direction = :down
when "r" then @direction = :right
when "l" then @direction = :left
when "|" then
case @direction
when :left then @direction = :right
when :right then @direction = :left
end
when "-" then
case @direction
when :up then @direction = :down
when :down then @direction = :up
end
when ".", " " then eval_spaces
when "@" then disp; print_bf; exit(1)
end
end
def disp
puts "\tbuffer #{$test.buffer}\tpos #{$test.pos}\tcurrent #{$test.current}\tdirection #{$test.direction}"
end
def run
disp
step
end
def print_prog
(0..@len-1).each do |i|
(0..@prog[i].length).each do |j|
if ([i, j] == @pos)
print "\033[44;37;5m#{@current} \033[0m"
else
print @prog[i][j]
end
end
print "\n"
end
STDOUT.flush
sleep(0.3)
system("clear")
end
end
$test = TwoD.new(File.read(ARGV[0]))
$steps = ARGV[1]
system("clear")
if $steps.nil?
loop do
$test.print_prog
$test.disp
$test.step
end
else
$steps.to_i.times do |x|
$test.print_prog
$test.disp
$test.step
end
end
ruby 2d.rb <file> <steps>
Ideas
- Function definition using <,>, ^ and v. Code in between these symbols is stored as a named function, these symbols may also be used as entry point specifiers , note: function's 2d representation must be stored. If a function omits certain entry points, it will not be called if it is executed using that entry point. 2 entry points must be specified at a minimum.
Defines a function s which can be executed from the left or from the bottom:
>s]...\
.
^
Definition of the built-in clockwise operator C.
$\ v C @ ] v />/<->C]\]C\ | ] ^ | | C \--/ | ^ \-/