From: Morton Goldberg Date: 2006-12-05T13:09:29+09:00 Subject: Re: [QUIZ] Turtle Graphics (#104) On Dec 4, 2006, at 6:21 PM, Edwin Fine wrote: > Pete Yandell wrote: >> # 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 >> > > What is the correct behavior if calling toward(pt) and @xy == pt. In > this case, atan2 returns 0.0 (North in turtle). This means that > setting > the turtle to point to where it already is makes it always face North, > which seems wrong. I would think that this should be a no-op (heading > does not change). > > irb(main):004:0> Math.atan2(0,0) > => 0.0 > > Try this test case. > > def test_toward > east = [100, 0] > @turtle.face east > assert_equal(90, @turtle.heading.round) > assert_nothing_raised { @turtle.face [0, 0] } > assert_equal(90, @turtle.heading.round) > end You bring up a good point here. Commanding the turtle to face the point where it's located is really an indeterminate operation. I think there are three reasonable responses to such a command: 1. Raise an error (because an indeterminate operation should be treated like 0/0). 2. Make it a no-op (as you suggest). 3. Accept the value returned by Math#atan2 (a show of faith in the C math library :). Philosophically, I favor the first response because I think this situation would most likely arise from a programmer error. But it's not an error that's commonly made. Also, in implementations maintaining the turtle's location with floats, testing whether or not @xy is the same as the argument given to toward/face is rather expensive. So in practice, I take the lazy way out and go with the atan2 flow. However, I would not fault an implementation that goes one of the other routes. Regards, Morton