My solution, which does pass your updated test_coord_cmnds, Morton...



require "matrix"

class Turtle
   include Math # turtles understand math methods
   DEG = Math::PI / 180.0
   ORIGIN = [0.0, 0.0]
   NORTH = 0.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=(pt)
      validate_point(pt)
      if pen_up?
         @xy = pt
      else
         pen_up
         @xy = pt
         pen_down
      end
      @xy
   end

   # Set the turtle's heading to <degrees>.
   def heading=(degrees)
      validate_angle(degrees)
      @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
      @segment = nil
   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
      if pen_up?
         @segment = [@xy.dup]
         @track << @segment
      end
   end

   # Is the pen up?
   def pen_up?
      not @segment
   end

   # Is the pen down?
   def pen_down?
      not pen_up?
   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, @heading = ORIGIN, NORTH
   end

   # Homes the turtle and empties out it's track.
   def clear
      home
      @track = []
   end

   # Turn right through the angle <degrees>.
   def right(degrees)
      validate_angle(degrees)
      self.heading += degrees
   end

   # Turn left through the angle <degrees>.
   def left(degrees)
      validate_angle(degrees)
      self.heading -= degrees
   end

   # Move forward by <steps> turtle steps.
   def forward(steps)
      validate_dist(steps)
      go offset(steps)
   end

   # Move backward by <steps> turtle steps.
   def back(steps)
      validate_dist(steps)
      go offset(-steps)
   end

   # Move to the given point.
   def go(pt)
      validate_point(pt)
      @xy = pt
      @segment << @xy if pen_down?
   end

   # Turn to face the given point.
   def toward(pt)
      validate_point(pt)
      d = delta(pt)
      self.heading = atan2(d[0], d[1]) / DEG
   end

   # Return the distance between the turtle and the given point.
   def distance(pt)
      validate_point(pt)
      delta(pt).r
   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

   # Given a heading, build a unit vector in that direction.
   def facing
      rd = @heading * DEG
      Vector[ sin(rd), cos(rd) ]
   end

   # Offset the current position in the direction of the current
   # heading by the specified distance.
   def offset(dist)
      (Vector[*@xy] + (facing * dist)).to_a
   end

   # Build a delta vector to the specified point.
   def delta(pt)
      (Vector[*pt] - Vector[*@xy])
   end

   def validate_point(pt)
      raise ArgumentError unless pt.is_a?(Array)
      raise ArgumentError unless pt.size == 2
      pt.each { |x| validate_dist(x) }
   end

   def validate_angle(deg)
      raise ArgumentError unless deg.is_a?(Numeric)
   end

   def validate_dist(dist)
      raise ArgumentError unless dist.is_a?(Numeric)
   end

   private :facing
   private :offset
   private :delta
   private :validate_point
   private :validate_angle
   private :validate_dist
end