From: Pete Yandell Date: 2006-12-05T06:08:49+09:00 Subject: Re: tk.rb warning in Turtle Graphics (#104) On 04/12/2006, at 8:28 PM, Edwin Fine wrote: > Here's my solution. Ok, a couple of comments. First, your home method doesn't raise the pen as it should. Second, all that flipping between turtle space angles and normal angles is unnecessary. Just swap the x and y axes when doing the trig and you'll get the right result. Third, Ruby has an atan2 method that does most of what you do in your toward method. Fourth, your normalize_degrees method is overkill. Try '-10 % 360' in irb. Here's my solution: class Turtle include Math # turtles understand math methods DEG = Math::PI / 180.0 attr_accessor :track alias run instance_eval def initialize clear end attr_reader :xy, :heading # Place the turtle at [x, y]. The turtle does not draw when it changes # position. def xy=(coords) raise ArgumentError unless is_point?(coords) @xy = coords end # Set the turtle's heading to . def heading=(degrees) raise ArgumentError unless degrees.is_a?(Numeric) @heading = degrees % 360 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_is_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_is_down = true @track << [@xy] end # Is the pen up? def pen_up? !@pen_is_down end # Is the pen down? def pen_down? @pen_is_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 @heading = 0.0 @xy = [0.0, 0.0] @pen_is_down = false end # Homes the turtle and empties out it's track. def clear @track = [] home end # Turn right through the angle . def right(degrees) raise ArgumentError unless degrees.is_a?(Numeric) @heading += degrees @heading %= 360 end # Turn left through the angle . def left(degrees) right(-degrees) end # Move forward by turtle steps. def forward(steps) raise ArgumentError unless steps.is_a?(Numeric) @xy = [@xy.first + sin(@heading * DEG) * steps, @xy.last + cos (@heading * DEG) * steps] @track.last << @xy if @pen_is_down end # Move backward by turtle steps. def back(steps) forward(-steps) end # Move to the given point. def go(pt) raise ArgumentError unless is_point?(pt) @xy = pt @track.last << @xy if @pen_is_down end # Turn to face the given point. def toward(pt) raise ArgumentError unless is_point?(pt) @heading = (atan2(pt.first - @xy.first, pt.last - @xy.last) / DEG) % 360 end # Return the distance between the turtle and the given point. def distance(pt) raise ArgumentError unless is_point?(pt) return sqrt((pt.first - @xy.first) ** 2 + (pt.last - @xy.last) ** 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 is_point?(pt) pt.is_a?(Array) and pt.length == 2 and pt.first.is_a?(Numeric) and pt.last.is_a?(Numeric) end end