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.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.
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
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
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;
SYNTAX DISPLAY
Child Package
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
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
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.