#!/usr/bin/env ruby require 'pp' require 'rubygems' require_gem 'multi' require 'amulti' require_gem 'sexp' require 'sexp' class Logo def initialize @x, @y = 100, 100 @angle = 0 @buffer = "" @pen = true amulti(:run, :right, Numeric) {|sym, r, rest| turn(r) ; run(rest) } amulti(:run, :left, Numeric) {|sym, l, rest| turn(-l) ; run(rest) } amulti(:run, :forward, Numeric) {|sym, f, rest| move(f) ; run(rest) } amulti(:run, :penup) {|sym, rest| @pen = true ; run(rest) } amulti(:run, :pendown) {|sym, rest| @pen = false ; run(rest) } amulti(:run, :repeat, Numeric, Array) do |sym, i, code, rest| i.to_i.times{ run(code) } run(rest) end amulti(:run) {} end def turn(num) @angle = (@angle + num) % 360 end def move(distance) oldx, oldy = @x, @y radians = @angle * Math::PI / 180 @x += distance * Math.cos(radians) @y += distance * Math.sin(radians) return unless @pen @buffer += <<-END END end def eval(string) run("(#{string})".parse_sexp) end def render return <<-END #{@buffer} END end end logo = Logo.new logo.eval %q{ repeat 4 (forward 100 right 90) forward 50 right 90 forward 100 } puts logo.render