Skip to content

Commit

Permalink
Interpreter 'finished' but untested
Browse files Browse the repository at this point in the history
  • Loading branch information
m-ender committed Aug 23, 2015
1 parent a3561f0 commit 4e37e0d
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 2 deletions.
41 changes: 41 additions & 0 deletions direction.rb
@@ -0,0 +1,41 @@
require_relative 'point2d'

class North
def right() East.new end
def left() West.new end
def reverse() South.new end
def vec() Point2D.new(0,-1) end

def ==(other) other.is_a?(North) end
def coerce(other) return self, other end
end

class East
def right() South.new end
def left() North.new end
def reverse() West.new end
def vec() Point2D.new(1,0) end

def ==(other) other.is_a?(East) end
def coerce(other) return self, other end
end

class South
def right() West.new end
def left() East.new end
def reverse() North.new end
def vec() Point2D.new(0,1) end

def ==(other) other.is_a?(South) end
def coerce(other) return self, other end
end

class West
def right() North.new end
def left() South.new end
def reverse() East.new end
def vec() Point2D.new(-1,0) end

def ==(other) other.is_a?(West) end
def coerce(other) return self, other end
end
186 changes: 184 additions & 2 deletions labyrinth.rb
Expand Up @@ -115,11 +115,17 @@ def initialize(src)
@grid = parse(src)
@ip = find_start
@dir = East.new

@main = []
@aux = []
end

def run
loop do
cmd = cell @ip
if cmd[0] == :terminate
break
end
process cmd
@dir = get_new_dir
@ip += @dir.vec
Expand Down Expand Up @@ -168,12 +174,188 @@ def cell coords
line[coords.x] || [:wall]
end

def push_main val
@main << val
end

def push_aux val
@aux << val
end

def pop_main
@main.pop || 0
end

def pop_aux
@aux.pop || 0
end

def peek_main
@main[-1] || 0
end

def process cmd
p cmd
opcode, param = *cmd

case opcode
# Arithmetic
when :push_zero
push_main 0
when :digit
push_main(pop_main*10 + param)
when :inc
push_main(pop_main+1)
when :dec
push_main(pop_main-1)
when :add
push_main(pop_main+pop_main)
when :sub
a = pop_main
b = pop_main
push_main(b-a)
when :mul
push_main(pop_main*pop_main)
when :div
a = pop_main
b = pop_main
push_main(b/a)
when :mod
a = pop_main
b = pop_main
push_main(b%a)

# Stack manipulation
when :dup
push_main(peek_main)
when :pop
pop_main
when :move_to_main
push_main(pop_aux)
when :move_to_aux
push_aux(pop_main)
when :swap_tops
a = pop_aux
m = pop_main
push_aux m
push_main a
when :depth
push_main(@main.size)

# I/O
when :input_char
push_main(read_byte.ord)
when :output_char
$> << pop_main.chr
when :input_int
val = 0
sign = 1
byte = read_byte
case byte
when '+'.ord
sign = 1
when '-'.ord
sign = -1
else
@next_byte = byte
end

loop do
byte = read_byte.chr
if byte[/\d/]
val = val*10 + byte.to_i
else
@next_byte = byte
break
end
end

push_main(sign*val)
when :output_int
$> << pop_main

# Grid manipulation
when :rotate_west
@grid[y+pop_main].rotate!(1)
when :rotate_east
@grid[y+pop_main].rotate!(-1)
when :rotate_north
grid = @grid.transpose
grid[x+pop_main].rotate!(1)
@grid = grid.transpose
when :rotate_south
grid = @grid.transpose
grid[x+pop_main].rotate!(-1)
@grid = grid.transpose

# Others
when :terminate
raise '[BUG] Received :terminate. This shouldn\'t happen.'
when :nop
# Nop(e)
end
end

def get_new_dir
@dir
neighbors = []
[North.new,
East.new,
South.new,
West.new].each do |dir|
neighbors << dir if cell(@ip + dir.vec)[0] != :wall
end
case neighbors.size
when 0
# Remain where you are by moving back one step.
# This can only happen at the start or due to shifting.
@ip += @dir.reverse
@dir
when 1
# Move in the only possible direction
neighbors[0]
when 2
neighbors = neighbors.select {|d| d.reverse != @dir}
# If we came from one of the two directions, pick the other.
# Otherwise, keep moving straight ahead (this can only happen
# at the start or due to shifting).
if neighbors.size == 2
@dir
else
neighbors[0]
end
when 3
val = peek_main
if val < 0
dir = @dir.left
elsif val == 0
dir = @dir
else
dir = @dir.right
end
if !neighbors.include? dir
dir = dir.reverse
end
dir
when 4
val = peek_main
if val < 0
@dir.left
elsif val == 0
@dir
else
@dir.right
end
end
end

def read_byte
result = nil
if @next_byte
result = @next_byte
@next_byte = nil
else
result = STDIN.read(1)
end
result
end
end

Expand Down
31 changes: 31 additions & 0 deletions point2d.rb
@@ -0,0 +1,31 @@
class Point2D
attr_accessor :x, :y

def initialize(x, y)
@x = x
@y = y
end

def self.from_string(string)
coords = string.split.map(&:to_i)
Point2D.new(coords[0], coords[1])
end

def +(other)
if other.is_a?(Point2D)
return Point2D.new(@x+other.x, @y+other.y)
end
end

def coerce(other)
return self, other
end

def to_s
"#{@x} #{@y}"
end

def pretty
"(% d,% d)" % [@x, @y]
end
end

0 comments on commit 4e37e0d

Please sign in to comment.