Report abuse


			
# 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