Spider | Previous | Next | Full Table of Contents | Index | Program List | Copyright
Let's pay another visit to the spider. You've seen so far how to command the spider to move around and draw shapes on the screen. Now that you know how to write procedures, let's consider how to add our own commands to the set of commands the spider can obey. Look again at the specification, Program 3.11. Specifically, we note the absence of two useful commands:
Left
(the spider can already turn right); and
Step(HowMany: Positive)
, that is, step forward a
given number of steps, not just a single step.
Suppose we were just writing a spider program. How could we get
the effect of the Left
command? There are several ways,
as we show in these code fragments. First, we can turn left by
turning right:
Spider.Right; Spider.Right; Spider.Right;
This works, but it is not very realistic--would you turn left that way? Another approach is to ask which direction the spider is facing and then tell it to face in another direction:
IF Spider.IsFacing = North THEN Spider.Face(WhichWay => West); ELSIF Spider.IsFacing = East THEN Spider.Face(WhichWay => North); ELSIF Spider.IsFacing = South THEN Spider.Face(WhichWay => East); ELSE -- Spider must be facing West Spider.Face(WhichWay => South); END IF;
This will work, but we have to be very careful in writing it that
all the directions are covered and that the Face
command has the right parameter. We note that Spider.Directions
is an enumeration type,
TYPE Directions IS (North, East, South, West);
and that a left turn can be implemented very easily as the
predecessor of the current direction. We've seen a similar problem
before, in Program 4.4, where given a representation of today,
we needed to find yesterday and tomorrow. We must be a
bit careful in taking the predecessor: If the current direction is
North
, just taking the predecessor will fail on
Constraint_Error
because the enumeration doesn't "wrap
around." The statement we need is, in fact,
IF Spider.IsFacing = Spider.North THEN Spider.Face(Spider.West); ELSE Spider.Face(Spider.Directions'Pred(Spider.IsFacing)); END IF;
or, to write it in more general terms (in case some day the directions are given in French),
IF Spider.IsFacing = Spider.Directions'First THEN Spider.Face(Spider.Directions'Last); ELSE Spider.Face(Spider.Directions'Pred(Spider.IsFacing)); END IF;
Implementing the new Step
is much easier: it's just
a counting loop with Spider.Step
as the loop body.
It is now time to implement the new commands as a set of procedures. Because these are commonly used commands, it is best to put them in a package. Since this new package is not just using the original spider package but is, in fact, closely related to it, we can define this relationship in an Ada child package.
We have seen child packages before; indeed, all the standard
packages we've used are children of Ada.[1] The
specification for our child package, Spider.My_Stuff
,
appears as Program 6.13 and just codes the
procedure specifications we've discussed here.
Program 6.13
Specification for Child Package Spider.My_Stuff
PACKAGE Spider.My_Stuff IS ------------------------------------------------------------------------ --| Additional Spider Commands; this is a child package. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ PROCEDURE Left; -- Pre: None -- Post: Spider turns 90 degrees to the left. PROCEDURE Step(HowMany: IN Positive); -- Pre: None -- Post: Spider takes HowMany steps forward -- in the direction it is facing. -- Raises: Hit_the_Wall is if spider tries to step into a wall. END Spider.My_Stuff;
The body of Spider.My_Stuff
appears as
Program 6.14. The procedure bodies incorporate
the statements we just discussed; note, however, that no
qualifications are necessary on the various calls. That is, we can
write IsFacing
instead of Spider.IsFacing
,
and so on. This tells us that the body of the child package can
automatically "see" everything in its parent's package specification
(it cannot see into its parent's package body, though).
Program 6.14
Body of Child Package Spider.My_Stuff
PACKAGE BODY Spider.My_Stuff IS ------------------------------------------------------------------------ --| Child Package Body for Additional Spider Commands --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ PROCEDURE Left IS BEGIN IF IsFacing = Directions'First THEN Face(Directions'Last); ELSE Face(Directions'Pred(IsFacing)); END IF; END Left; PROCEDURE Step(HowMany: IN Positive) IS BEGIN FOR Count IN 1..HowMany LOOP Step; END LOOP; END Step; END Spider.My_Stuff;
Parent.Child
. The parent package must exist already
to permit compilation of the child package. Under normal
circumstances, one is not permitted to compile new children of the
package Ada
since this parent package is reserved
for standard (language-defined) packages.
Program 6.15 shows how to use the packages
Spider
and Spider.My_Stuff
. Note that
because this program uses both packages, it must have context clauses
(WITH
s) for both. The spider draws a box, turning left
at the corners instead of right. This program is simpler than
Program 5.11 because we can take
advantage of the multiple-step command in the child package. We omit
the sample run because it is very similar to the output of the box
programs of Section 5.5.
Program 6.15
The Spider Draws a Counterclockwise Box
WITH Spider; WITH Spider.My_Stuff; PROCEDURE Draw_Box_with_Loops_Left IS ------------------------------------------------------------------------ --| Draw 4 x 4 box with spider - use nested loops and turn left --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ BEGIN -- Draw_Box_with_Loops_Left Spider.Start; FOR Side IN 1..4 LOOP Spider.My_Stuff.Step(HowMany => 5); Spider.My_Stuff.Left; END LOOP; Spider.Quit; END Draw_Box_with_Loops_Left;
Finally, in Program 6.16 we show a program
that commands the spider to move from its starting position in the
center of its room to the wall, then inspect the edges of the room,
turning left at the corners. This program uses WHILE
loops to get the spider to turn before it steps into the wall. One
WHILE
loop gets the spider to the first wall, then
another WHILE
loop is nested inside the FOR
loop that counts the walls.
Note in the sample run that the spider does not quite get back to where it started and that it leaves half of one wall uninspected. We leave correcting this as an exercise.
Program 6.16
The Spider Tours the Edges of Its Room
WITH Spider; WITH Spider.My_Stuff; PROCEDURE Tour_Room IS ------------------------------------------------------------------------ --| Spider takes a tour around the edges of its room. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ BEGIN -- Tour_Room Spider.Start; -- first get to a wall WHILE NOT Spider.AtWall LOOP Spider.Step; END LOOP; -- now turn and tour the four walls FOR Wall IN 1..4 LOOP Spider.My_Stuff.Left; -- walk the length of this wall WHILE NOT Spider.AtWall LOOP Spider.Step; END LOOP; END LOOP; Spider.Quit; END Tour_Room;
Sample Run
----------------------------------------- --- |O O O O O O O O O O O . . . . . . . . . *| | ^ | |O . . . . . . . . . O . . . . . . . . . O| | O | |O . . . . . . . . . O . . . . . . . . . O| --- |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . O . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O . . . . . . . . . . . . . . . . . . . O| |O O O O O O O O O O O O O O O O O O O O O| -----------------------------------------
Copyright ©1996 by Addison-Wesley Publishing Company, Inc.