# Shoegoo: Logo in Shoes
# Example:
# right 180
# move 50
# left 90
# def square x
# repeat 4 do
# move x
# right 90
# end
# end
# @x = 5
# repeat 20 do
# right 18
# square @x
# @x += 5
# end


BOARD_WIDTH = 500
BOARD_HEIGHT = 500
CONTROLS_WIDTH = 150

class Logo
class << self; attr_accessor :board; end
def self.setup(board, turtle)
self.board = board
self.board.turtle = LogoSandbox.turtle = turtle
@@buff = []
@@depth = 0
self.board.draw
end
def self.read(text)
if text =~ /^(def |repeat )/
@@buff << text
@@depth += 1
elsif @@depth == 0
LogoSandbox.instance_eval(text)
else
@@buff << text
if text =~ /^end/
@@depth -= 1
if @@depth == 0
LogoSandbox.instance_eval(@@buff.join("\n"))
@@buff = []
end
end
end
self.board.draw
text
end
end

class LogoSandbox
attr_accessor :turtle
def self.repeat(times, &block)
times.times {block.call}
end
def self.move(steps)
self.turtle.move(steps)
end
def self.turn(degrees)
self.turtle.turn(degrees / 180.0 * Math::PI)
end
def self.left(degrees)
turn(-degrees.to_f)
end
def self.right(degrees)
turn(degrees.to_f)
end
end

class Turtle
attr_accessor :x, :y, :points
def initialize(x, y)
@x, @y = x, y
@dir = [0.0, 1.0]
@points = [[@x, @y]]
end
def draw
$app.stroke(rgb(0, 1.0, 0))
# π turn
v = [-@dir[1], @dir[0]]
# turn - 5 units
p1 = [@x - 5 * v[0], @y - 5 * v[1]]
# turn + 5 units
p2 = [@x + 5 * v[0], @y + 5 * v[1]]
# forward 10 units
p3 = [@x + 10 * @dir[0], @y + 10 * @dir[1]]
$app.line(p1[0], p1[1], p2[0], p2[1])
$app.line(p2[0], p2[1], p3[0], p3[1])
$app.line(p3[0], p3[1], p1[0], p1[1])
end
def move(dist)
@x += dist * @dir[0]
@y += dist * @dir[1]
@points << [@x, @y]
end
def turn(r)
@dir = [@dir[0] * Math.cos(r) - @dir[1] * Math.sin(r),
@dir[0] * Math.sin(r) + @dir[1] * Math.cos(r)]
end
def each_line
for i in (0...@points.size-1)
yield [@points[i][0], @points[i][1], @points[i+1][0], @points[i+1][1]]
end
end
end

class LogoBoard
attr_accessor :turtle
def initialize
@canvas = $app.flow(:margin => 0, :top => 0, :left => 0, :width => BOARD_WIDTH, :height => BOARD_HEIGHT)
end
def draw
@canvas.clear do
$app.background("#333333")
$app.stroke(rgb(0, 0.8, 0))
@turtle.each_line { |l| $app.line(*l) }
@turtle.draw
end
end
end

class ControlPanel
def self.setup
$app.stack :top => 0, :left => BOARD_WIDTH, :width => CONTROLS_WIDTH + 20, :margin => 10 do
@@log = $app.edit_box :width => CONTROLS_WIDTH, :height => CONTROLS_WIDTH, :editable => false
$app.para "" # spacing ick!
@@input = $app.edit_line :width => CONTROLS_WIDTH, :height => 25
$app.para "" # more spacing
$app.button("go", :width => CONTROLS_WIDTH) do
@@log.text += Logo.read(@@input.text) + "\n"
@@input.text = ''
end
end
end
end

Shoes.app :width => BOARD_WIDTH + CONTROLS_WIDTH + 20, :height => BOARD_HEIGHT do
$app = self
ControlPanel.setup
Logo.setup(LogoBoard.new, Turtle.new(250,250))
keypress {|key| self.clear if key == '\n'}
end