Here is my straight-to-the-point answer:

class Turtle

include Math # turtles understand math methods

DEG = Math:

I / 180.0

attr_accessor :track

alias run instance_eval

def initialize

clear

end

attr_reader

y, :heading

# Place the turtle at [x, y]. The turtle does not draw when it

changes

# position.

def xy=(coords)

raise ArgumentError if !coords.is_a?(Array) ||

coords.size != 2 ||

coords.any? { |c| !c.is_a?(Numeric) }

@xy = coords

end

# Set the turtle's heading to <degrees>.

def heading=(degrees)

raise ArgumentError if !degrees.is_a?(Numeric)

set_heading(degrees)

end

# Raise the turtle's pen. If the pen is up, the turtle will not

draw;

# i.e., it will cease to lay a track until a pen_down command is

given.

def pen_up

@pen_down = false

end

# Lower the turtle's pen. If the pen is down, the turtle will draw;

# i.e., it will lay a track until a pen_up command is given.

def pen_down

@pen_down = true

end

# Is the pen up?

def pen_up?

!@pen_down

end

# Is the pen down?

def pen_down?

@pen_down

end

# Places the turtle at the origin, facing north, with its pen up.

# The turtle does not draw when it goes home.

def home

pen_up

@xy = [0,0]

@heading = 0

end

# Homes the turtle and empties out it's track.

def clear

home

@track = []

end

# Turn right through the angle <degrees>.

def right(degrees)

set_heading(@heading + degrees)

end

# Turn left through the angle <degrees>.

def left(degrees)

set_heading(@heading - degrees)

end

# Move forward by <steps> turtle steps.

def forward(steps)

dx, dy = calc_delta(steps)

go [ @xy[0] + dx, @xy[1] + dy ]

end

# Move backward by <steps> turtle steps.

def back(steps)

dx, dy = calc_delta(steps)

go [ @xy[0] - dx, @xy[1] - dy ]

end

# Move to the given point.

def go(pt)

track << [ @xy, pt ] if pen_down?

@xy = pt

end

# Turn to face the given point.

def toward(pt)

@heading = atan(pt[0].to_f / pt[1].to_f) / DEG

end

# Return the distance between the turtle and the given point.

def distance(pt)

sqrt((@xy[0] - pt[0]) ** 2 + (@xy[1] - pt[1]) ** 2)

end

# Traditional abbreviations for turtle commands.

alias fd forward

alias bk back

alias rt right

alias lt left

alias pu pen_up

alias pd pen_down

alias pu? pen_up?

alias pd? pen_down?

alias set_h heading=

alias set_xy xy=

alias face toward

alias dist distance

private

def set_heading(degrees)

@heading = degrees % 360

end

def calc_delta(steps)

[ sin(heading * DEG) * steps,

cos(heading * DEG) * steps ]

end

end

Ruby Quiz wrote:

> The three rules of Ruby Quiz:

>

> 1. Please do not post any solutions or spoiler discussion for this quiz until

> 48 hours have passed from the time on this message.

>

> 2. Support Ruby Quiz by submitting ideas as often as you can:

>

> http://www.rubyquiz.com/

>

> 3. Enjoy!

>

> Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone

> on Ruby Talk follow the discussion. Please reply to the original quiz message,

> if you can.

>

> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

>

> by Morton Goldberg

>

> [Editor's Note: You can download the files for this quiz at:

>

> http://rubyquiz.com/turtle.zip

>

> --JEG2]

>

> Turtle Graphics

> ===============

>

> Turtle graphics is a form of computer graphics based on the ideas of turtle

> geometry, a formulation of local (coordinate-free) geometry. As a brief

> introduction to turtle graphics, I quote from [1]:

>

> Imagine that you have control of a little creature called a turtle

> that exists in a mathematical plane or, better yet, on a computer

> display screen. The turtle can respond to a few simple commands:

> FORWARD moves the turtle in the direction it is facing some

> number of units. RIGHT rotates it clockwise in its place some

> number of degrees. BACK and LEFT cause the opposite movements. ...

> The turtle can leave a trace of the places it has been: [its

> movements] can cause lines to appear on the screen. This is

> controlled by the commands PENUP and PENDOWN. When the pen is

> down, the turtle draws lines.

>

> For example, the turtle commands to draw a square, 100 units on a side, can be

> written (in a Ruby-ized form) as:

>

> pen_down

> 4.times { forward 100; right 90 }

>

> For more information, see [2] and [3].

>

> This quiz is a bit different from most. If the usual Ruby quiz can be likened to

> an essay exam, this one is a fill-in-the-blanks test. I'm supplying you with a

> complete turtle graphics package, except -- to give you something to do -- I've

> removed the method bodies from the key file, lib/turtle.rb. Your job is to

> repair the damage I've done and make the package work again.

>

> Turtle Commands

> ===============

>

> There are quite a few turtle commands, but that doesn't mean you have to write a

> lot of code to solve this quiz. Most of the commands can be implemented in a

> couple of lines. It took me a lot longer to write a description of the commands

> than it did for me to implement and test all of them.

>

> I use the following format to describe turtle commands:

>

> long_name | short_name <arg>

> description ...

> Example: ...

>

> All turtle commands take either one argument or none, and not all turtle

> commands have both a long name and a short name.

>

> Required Commands

> -----------------

>

> These commands are required in the sense that they are needed to reproduce the

> sample designs. Actually, you could get away without implementing 'back' and

> 'left', but implementing them is far easier than trying to write turtle code

> without them.

>

> pen_up | pu

> Raises the turtle's pen. The turtle doesn't draw (lay down a visible

> track) when its pen is up.

>

> pen_down | pd

> Lowers the turtle's pen. The turtle draws (lays down a visible track)

> when its pen is down.

>

> forward | fd <distance>

> Moves the turtle forwards in the direction it is facing.

> Example: forward(100) advances the turtle by 100 steps.

>

> back | bk <distance>

> Moves the turtle backwards along its line of motion.

> back <distance> == forward -<distance>

> Example: back(100) backs up the turtle by 100 steps.

>

> right | rt <angle>

> Turns the turtle clockwise by <angle> degrees.

> Example: right(90) turns the turtle clockwise by a right angle.

>

> left | lt <angle>

> Turns the turtle counterclockwise by <angle> degrees.

> left <angle> == right -<angle>

> Example: left(45) turns the turtle counterclockwise by 45 degrees.

>

> Traditional Commands

> --------------------

>

> These commands are not needed to reproduce any of the sample designs, but they

> are found in all implementations of turtle graphics that I know of.

>

> home

> Places the turtle at the origin, facing north, with its pen up. The

> turtle does not draw when it goes home.

>

> clear

> Homes the turtle and empties out it's track. Sending a turtle a clear

> message essentially reinitializes it.

>

> xy

> Reports the turtle's location.

> Example: Suppose the turtle is 10 turtle steps north and 15 turtle steps

> west of the origin, then xy will return [-15.0, 10.0].

>

> set_xy | xy= <point>

> Places the turtle at <point>. The turtle does not draw when this command

> is executed, not even if its pen is down. Returns <point>.

> Example: Suppose the turtle is at [10.0, 20.0], then self.xy = [50, 80]

> moves the turtle to [50.0, 80.0], but no line will drawn between the [10,

> 20] and [50, 80].

>

> heading

> Reports the direction in which the turtle is facing. Heading is measured

> in degrees, clockwise from north.

> Example: Suppose the turtle is at the origin facing the point [100, 200],

> then heading will return 26.565 (approximately).

>

> heading= | set_h <angle>

> Sets the turtle's heading to <angle>. <angle> should be given in degrees,

> measured clockwise from north. Returns <angle>.

> Example: After self.heading = 135 (or set_h(135) which is easier to

> write), the turtle will be facing southeast.

>

> pen_up? | pu?

> Reports true if the turtle's pen is up and false otherwise.

>

> pen_down? | pd?

> Reports true if the turtle's pen is down and false otherwise.

>

> Optional Commands

> -----------------

>

> These commands are only found in some implementations of turtle graphics. When

> they are implemented, they make the turtle capable of doing global (coordinate)

> geometry in addition to local (coordinate-free) geometry.

>

> I used one of these commands, go, to draw the mandala design (see

> designs/mandala.tiff and samples/mandala.rb). If you choose not to implement the

> optional commands, you might try writing a turtle program for drawing the

> mandala design without using go. But, believe me, it is much easier to implement

> go than to write such a program.

>

> go <point>

> Moves the turtle to <point>.

> Example: Suppose the turtle is home (at the origin facing north). After

> go([100, 200]), the turtle will be located at [100.0, 200.0] but will

> still be facing north. If its pen was down, it will have drawn a line

> from [0, 0] to [100, 200].

>

> toward | face <point>

> Turns the turtle to face <point>.

> Example: Suppose the turtle is at the origin. After toward([100, 200]),

> its heading will be 26.565 (approximately).

>

> distance | dist <point>

> Reports the distance between the turtle and <point>.

> Example: Suppose the turtle is at the origin, then distance([400, 300])

> will return 500.0 (approximately).

>

> Interfacing to the Turtle Graphics Viewer

> =========================================

>

> Implementing turtle graphics without being able to view what the turtle draws

> isn't much fun, so I'm providing a simple turtle graphics viewer. To interface

> with the viewer, turtle instances must respond to the message track by returning

> an array which the viewer can use to generate a line drawing.

>

> The viewer expects the array returned by track to take the following form:

>

> track ::= [segment, segment, ...] # drawing data

> segment ::= [point, point, ...] # points to be joined by line segments

> point ::= [x, y] # pair of floats

>

> Example: [[[0.0, 0.0], [200.0, 200.0]], [[200.0, 0.0], [0.0, 200.0]]]

>

> This represents an X located in the upper-right quadrant of the viewer; i.e.,

> two line segments, one running from the center of the viewer up to its

> upper-right corner and the other running from the center of the top edge down to

> the center of the right edge.

>

> [Editor's Note: I added a script to dump your turtle graphics output to PPM

> image files, for those that don't have TK up and running. It works identically

> to Morton's turtle_viewer.rb, save that it writes output to a PPM image file in

> the current directory. For example, to output the included tree image, use

> `ruby turtle_ppm_writer.rb samples/tree.rb`. --JEG2]

>

> Unit Tests

> ==========

>

> I'm including the unit tests which I developed to test turtle commands. For the

> purposes of the quiz, you can ignore tests/turtle_view_test.rb. But I hope you

> will find the other test suite, tests/turtle_test.rb, helpful. It tests every

> one of the turtle commands described above as well as argument checking by the

> commands. Don't hesitate to modify any of the unit tests to meet the needs of

> your quiz solution.

>

> References

> ==========

>

> [1] Abelson, H. & A. diSessa, "Turtle Geometry", MIT Press, 1981.

> [2] Harvey, B., "Computer Science Logo Style", Chapter 10.

> http://www.cs.berkeley.edu/~bh/pdf/v1ch10.pdf

> [3] Wikipedia, http://en.wikipedia.org/wiki/LOGO_programming_language