We have how to use the turtle package in several ways; now it is
time to look at how the package itself is implemented. This was done
in several layers. At the highest or outermost layer is the
TurtleCmd
procedure,5.19which does all the work of interpreting the turtle ``language''. Much
of this procedure is implemented in other ``lower level'' procedures, such
as Forward
and Left
, which exist to make the programming
of the higher-level routines easier. And these procedures may be
implemented using even other lower-level procedures.
Why was it programmed this way? In part, to make it easier to understand and to change. This program is modular, and to write the top-level program we don't need to know all the ins and outs of the lower levels, just what is available and what it does. This sort of thing is very common and useful in programming, and in everyday life as well. For example, to go to the store you might drive a car. But you don't need to know how to build a car to drive it, nor do you need to know how to build a road. You just need to know what it does and how to use it. And the man in the body shop who repairs your windshield (after a rock from the construction site you passed on the way to the store cracks it) doesn't need to know how to manufacture a windshield, he only needs to know where to get the right one for your car and how to install it properly.
Without going into the deepest details, let's pop off the shell of
TurtleCmd
and see how it works.
>
TurtleCmd := proc(cmd::name)
local c, i;
ClearPage();
for i from 1 to length(cmd) do
c:=substring(cmd,i);
DoCommand(c);
od;
ShowPath();
end:
Not much to it, is there? The procedure uses the command
ClearPage
to wipe the slate clean, setting the turtle's
position to (0, 0), aiming in the initial direction, and so on.
Then, for each character in its command string, it calls
DoCommand
to perform that command, and finally uses
ShowPath
to actually render the plot. We won't discuss exactly
how ClearPage
and ShowPath
now (feel free to look at
them yourself, of course). But here is DoCommand
:
DoUserCommand:=c->false:
>
DoCommand:=proc(c)
if (c=`F`) then
Forward();
elif (c=`B`) then
Back();
elif (c=`L`) then
Left();
elif (c=`R`) then
Right();
elif (c=`S`) then
Shrink();
elif (c=`G`) then
Grow();
elif (c=`U`) then
PenUp();
elif (c=`D`) then
PenDown();
elif (c=` `) then
NULL;
else
if (not DoUserCommand(c)) then
WARNING(sprintf("Unknown turtle command fi;
fi;
NULL;
end:
All this does is look at its argument (a single character), and call
the corresponding lower-level routine. For example,
DoCommand(`F`)
just calls Forward()
, which advances the
internal position of the turtle ahead one step. Note that there are
two commands we haven't used yet, namely U
and D
, which
raise and lower the pen that the turtle holds. For example, the
turtle command FUFDF
produces two line segments separated by a
gap. The line with DoUserCommand
will be discussed in the
next section; it is a way to allow the user of the turtle package to
add his or her own commands.
In the previous paragraph, we refered to the ``internal position of
the turtle''-- what did we mean by this? We think of the turtle as
having a current position, direction, step size, and so on. Each of
these are stored in variables internal to the turtle package and
updated by commands such as Back
, Shrink
, or
SetTurtleAngle
. A history of the positions of the turtle since
the last ClearPage
is kept, and when ShowPage
is called,
they are formatted into an appropriate maple Plot
command.