Ora

From Esolang
Jump to navigation Jump to search

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     \--/
 | ^
 \-/