home *** CD-ROM | disk | FTP | other *** search
/ Solo Programadores 22 / SOLO_22.iso / docs / lovelace / lesson18.les < prev    next >
Encoding:
Text File  |  1995-11-21  |  25.1 KB  |  656 lines

  1. <COMMENT This is a lesson file for the Lovelace Ada tutorial>
  2. <COMMENT A program called genlesson is used to transform this file into a set>
  3. <COMMENT of useful HTML files for use by Mosaic & other WWW browsers.>
  4.  
  5. <COMMENT  Edit the following lines. >
  6. <TUTOR NAME="Lovelace">
  7. <LESSON NUMBER=18>
  8. <AUTHOR NAME="David A. Wheeler" EMAIL="wheeler@ida.org">
  9. <AUTHOR ADDRESS="<A HREF="dwheeler.htm">David A. Wheeler (wheeler@ida.org)</A>">
  10. <COMMENT $Id$ >
  11.  
  12. <SECTION NAME="Example Program Small (Introduction)">
  13.  
  14. Now that you've seen various parts of the Ada 95 programming language,
  15. it's time to walk through and create a program more than a few lines
  16. long.
  17. This program will use many of the different Ada capabilities at one time,
  18. so you can see how they work together.
  19. I can't walk you through every detailed little decision, but I'll try to
  20. carry you through the highlights.
  21. <P>
  22.  
  23. The program we'll create is a small text adventure game.
  24. This program will simulate a small world, describing the current
  25. situation to the user.
  26. The user can then type in commands (like "look" and "get key")
  27. to make things happen.
  28. First we will implement "look" and "quit" commands;
  29. we will then add "get object" and "drop object" commands;
  30. and then we'll add
  31. "go <EM>direction</EM>" (north, south, etc.) commands.
  32. We'll want to be flexible so we can easily add other commands (like "open")
  33. and have different operations do different things (for example, perhaps
  34. you can get some objects but not others).
  35. <P>
  36.  
  37. Given those simple requirements, what should the basic program design be?
  38. Let's try to break it down into logical groupings.
  39. An adventure game involves manipulating different things, of
  40. different but related types, performing possibly different actions when given
  41. the same commands.
  42. It sounds like an object-oriented approach would be appropriate
  43. for this kind of problem, so we'll probably have a set of different object
  44. type definitions.  We'll figure out how to define them in a moment, but we'll
  45. probably need to define a "root" type of all these different things, since
  46. they'll probably share many of the same operations.
  47. For the moment, let's assume that we'll define a package called "Things"
  48. that defines the root tagged type called Thing:
  49. <P>
  50. <PRE>
  51.  package Things is
  52.    type Thing is tagged ...; -- We'll figure this out later.
  53.    type Thing_Access is access all Thing'Class; -- Usual OO definition.
  54.    -- Operations to be determined ...
  55.  end Things;
  56. </PRE>
  57. <P>
  58.  
  59. We also need to take a line of text and attempt to execute it.
  60. We might want that functionality for other reasons (for example, perhaps
  61. objects can have lines of text that are executed, or perhaps monsters
  62. can accept commands), so let's separate
  63. that capability into a separate package rather than incorporating
  64. it inside package Things.
  65. So let's make a package called "Parser" and a procedure inside it called
  66. "Execute"; Execute will take one parameter (a line of text), parse that
  67. line, and execute it:
  68. <PRE>
  69.  package Parser is
  70.   procedure Execute(Command : in Unbounded_String);
  71.  end Parser;
  72. </PRE>
  73. <P>
  74.  
  75. Finally, we'll need to kick off this whole program, so we'll create
  76. a main procedure that gets everything going.
  77. In general, it's good for main procedures to be relatively small;
  78. in this case the main procedure will run a simple loop -
  79. wait for input, and then send that input to Execute to execute the command.
  80. Let's call the main procedure (and thus the program) "Small", since it's
  81. a small text adventure game:
  82. <PRE>
  83.  procedure Small is
  84.  begin
  85.   -- Repetitively get a command, then send it to Parser.Execute.
  86.  end Small;
  87. </PRE>
  88. <P>
  89.  
  90. We already have another package called "Ustrings" that provides a routine
  91. to read a text line into an Unbounded_String; that will be
  92. useful for implementing procedure Small.
  93. <P>
  94.  
  95. But wait - how will the main procedure know when "quit" has been commanded?
  96. There might be other reasons a player would stop the game (for example,
  97. if the player is "killed"). Probably Execute should return a Boolean
  98. value, which says whether or not more commands should be accepted.
  99. So we'll go back to Execute and change it to:
  100. <PRE>
  101.   procedure Execute(Command : in Unbounded_String; Quit : out Boolean);
  102. </PRE>
  103. <P>
  104.  
  105. This particular change is only one example of many changes - I actually
  106. restructured this example several times as I was designing it.
  107. This is <EM>normal</EM>. You should try to break the system down, and
  108. then carefully examine the design to repair omissions in the
  109. interface between components.
  110. You should also strive to have a general structure so that changes
  111. you can anticipate can be easily handled.
  112. <P>
  113.  
  114. Note that we're <EM>only</EM> worrying about the major design components
  115. and making sure their interfaces are sufficient for the job.
  116. In Ada, that means that you generally define the package
  117. declarations (specifications) <EM>first</EM>, and then once you think
  118. you've got them (basically) right you then implement the bodies.
  119. You'll notice that I haven't written any bodies yet - why bother, since I'm
  120. still working on the program's basic structure?
  121. You'll find that implementing bodies is easy if the specifications are right.
  122. <P>
  123.  
  124. <QUESTION Type=Multiple-Choice>
  125. How many program units have we broken this problem into so far?
  126. <CHOICES>
  127. <CHOICE ANS=1>1
  128. <CHOICE ANS=2>2
  129. <CHOICE ANS=3>3
  130. <CHOICE ANS=4>4
  131. <CHOICE ANS=5>5
  132. </CHOICES>
  133. <ANSWER ANS=4>
  134. <RESPONSES>
  135. <WHEN ANS=2>
  136. No, that's not right. Program units are packages or
  137. top-level procedures.
  138. <WHEN ANS=3>
  139. Sorry, not quite right.
  140. Did you forget package Ustrings or procedure Small?
  141. Try again!
  142. <WHEN ANS=4>
  143. That's right.
  144. We have package Things, package Parser, procedure Small,
  145. and package Ustrings.
  146. We'll add more as we deal with package Things.
  147. </RESPONSES>
  148.  
  149. <SECTION NAME="Small's Object-Oriented Class Hierarchy">
  150.  
  151. We still haven't dealt with what's in package "Things", and
  152. other packages related to it; these are arguably the
  153. most important packages.
  154. Lots of different things can exist in the world, and things can
  155. contain other things.
  156. Usually adventure games have "rooms" where the players can go,
  157. items to pick up, and possibly monsters to meet.
  158. <P>
  159.  
  160. <IMG ALIGN=right SRC="small.gif" ALT="[Object Hierarchy]">
  161. To the right is a figure showing the class hierarchy that I've
  162. dreamed up; examine it and see if it makes sense to you.
  163. Anything in this world is considered a Thing; a Thing has a name,
  164. a description, and may contain other Things.
  165. Things can be Rooms or Occupants.
  166. Rooms can have connections (north, south, etc).
  167. There are two kinds of Occupants, Items and Creatures.
  168. Items are things like keys and tables.
  169. Creatures can be either Players or Monsters.
  170. By "Monster" I mean the technical role-playing game definition: a Monster
  171. is anything that does actions on its own that is not a player.
  172. I've intentionally not used the word "Object" here, because we might
  173. have other objects in other packages that aren't Things.
  174. <P>
  175.  
  176. In some sense this class hierarchy is more than we need at first (I'm
  177. not planning to implement Monsters right now), but
  178. this gives us room to grow into.
  179. Future versions might expand this further - for example, perhaps there
  180. should be types Door and Key that are extensions of Item.
  181. <P>
  182.  
  183. So, if we know the hierarchy of types, how will the packages holding
  184. these types be organized?
  185. In Ada, types are placed in packages, and they don't <EM>need</EM> to
  186. match one-for-one.
  187. You can declare more than one type in a package, and you can use
  188. child packages to group them in special ways.
  189. However, unless there's some reason to do otherwise, the
  190. "simple" way is usually best: create a package for each tagged type.
  191. As a naming convention I use the plural for the package and the singular
  192. for the type, so tagged type "Occupant" is in package "Occupants".
  193. We could use child packages, but I find them unnecessary for many OO
  194. applications; we can just use simple, basic packages to do the job in this
  195. case.
  196. Each package will need to "with" the package of its parent.
  197. So we'll have packages named Things, Rooms, Occupants, Items, Creatures,
  198. Monsters, and Players.
  199. <P>
  200.  
  201. Now that we know what packages to create, how do we define the types
  202. inside them?
  203. Well, Thing and all its descendants must be tagged types, since we have
  204. inheritance.
  205. All of the type definitions for the children Room, Occupant, and so on
  206. will probably look like this:
  207. <P>
  208. <PRE>
  209.  type X is new PARENT with private;
  210. </PRE>
  211. <P>
  212.  
  213. Ah, but how do I define the "root" of this hierarchy (in this
  214. case type Thing)?
  215. Although we don't need it right away, we probably want to be able to
  216. cause special things to happen when some objects are created or destroyed.
  217. That sounds like we need a "controlled" type, which would let us do that.
  218. However, we probably don't need to be able to assign between them, so we
  219. should probably create type Thing as new version of
  220. the "Limited_Controlled" type.
  221. Type Thing is not something you'd instantiate directly; instead, you'd create
  222. instances of its children.
  223. Thus Thing should be an abstract type; by declaring
  224. it abstract, people won't be able to create an instance of it.
  225. Here's the definition of Thing (which we'll place in package Things):
  226. <P>
  227. <PRE>
  228.  type Thing is abstract new Limited_Controlled with private;
  229. </PRE>
  230. <P>
  231.  
  232. There's a key rule of thumb that underlies some of these decisions:
  233. <EM>never expose in a package specification more than you have to</EM>.
  234. For example, notice that I've chosen to say "with private" everywhere.
  235. That means that the actual implementation of these types is hidden
  236. in the private part of the package specification and can't be used
  237. directly by its users.
  238. That means we'll be able to change the implementation later without
  239. impacting users.
  240.  
  241. <QUESTION Type=Multiple-Choice>
  242. Is a Player a member of the class of Things?
  243. <CHOICES>
  244. <CHOICE ANS=1>Yes.
  245. <CHOICE ANS=2>No.
  246. </CHOICES>
  247. <ANSWER ANS=1>
  248. <RESPONSES>
  249. <WHEN ANS=1>
  250. Yes indeed.
  251. In Ada terms, Player is a member of Thing'Class.
  252. <WHEN ANS=2>
  253. Sorry, that's not it.
  254. The "class of things" is the set of all types that are derived,
  255. directly or indirectly, from Thing.
  256. Take a look at the hierarchy again.
  257. </RESPONSES>
  258.  
  259. <SECTION NAME="Any Structures Missing (Locating Operations)?">
  260.  
  261. It's best to try to identify all the major components of a program
  262. and their purpose before going further.
  263. One way to do this is to think of important operations and data values
  264. and then determine if they have a "home" in our program structure.
  265. We've already covered the basic hierarchy of tagged types, and that
  266. seems to cover most of our needs.
  267. Let's think about the kinds of operations we'll need, and where
  268. they will be defined, to see if
  269. there are any that can't easily be located on our current design.
  270. <P>
  271.  
  272. I think most of the commands should be attached to type Occupant (and
  273. thus placed in the Occupants package), with possible
  274. overriding for more specific types.
  275. You'd like to be able to command things other than the player to
  276. do things; it would be useful to command monsters and magic swords,
  277. for example.
  278. Even if you don't want a user to be able to "get" a monster, you want to print
  279. a reasonable message (not raise an exception) if the user attempts it.
  280. On the other hand, it's not as easy to imagine a room "getting" things
  281. (though you <EM>could</EM> define what that means), so for our
  282. purposes we'll attach many operations to Occupant.
  283. <P>
  284.  
  285. The parser package will need to be able to command objects to Look, Get,
  286. Drop, and so on.
  287. It sounds like the operations like Look, Get, Drop, and so on will
  288. need to be in the specification of the various packages defining their
  289. corresponding tagged types.
  290. We'll come back to that later, but it looks like the structure
  291. we've developed so far will handle that easily.
  292. <P>
  293.  
  294. The parser will need to break apart the text and then send a message to
  295. the player object to do something. Hmm, how can we find the player object?
  296. We could just define a global variable, but if this game ever became a
  297. multi-player game that wouldn't be very flexible.
  298. Let's define a function called "Me" that returns something that
  299. can represent the player.
  300. That way, we can create a function that varies who "Me" is easily.
  301. <P>
  302.  
  303. Okay, where should that function "Me" go? It could be part of the
  304. Occupant class, but I'd rather have a separate package that sets up and
  305. keeps track of the "current state of the world".
  306. That way, all the other packages
  307. only need to react to specific commands and requests given to them, and
  308. they won't need (or even have available!) global information about the
  309. state of the world without specifically requesting that information.
  310. I'll call the package that keeps track of the general world state
  311. package "World".
  312. <P>
  313.  
  314. We've already identified package Ustrings as a useful package, and I
  315. can't think of anything else we'd need, so it looks like we have
  316. a basic structure for program Small.
  317.  
  318. <QUESTION Type=Multiple-Choice>
  319. What new package have we identified?
  320. <CHOICES>
  321. <CHOICE ANS=1>package World
  322. <CHOICE ANS=2>package Ustrings
  323. <CHOICE ANS=2>package Me
  324. </CHOICES>
  325. <ANSWER ANS=1>
  326. <RESPONSES>
  327. <WHEN ANS=1>
  328. That's right.
  329. It's not the end of the world (he!) if we later determine that we need to add
  330. new components to our design, but it's best to try to identify design
  331. components earlier.
  332. That way, we can have a more coherent design (maximizing reuse of lower-level
  333. components and working coherently together).
  334. <WHEN ANS=2>
  335. We identified package Ustrings in the previous section.
  336. I don't think you've been reading very carefully; try again!
  337. <WHEN ANS=3>
  338. Is "Me" a package?
  339. No - "Me" is a function inside another package.
  340. Try again.
  341. </RESPONSES>
  342. <SECTION NAME="Attributes and Operations of Objects">
  343.  
  344. Well, we have the general structure laid out.
  345. Now we need to figure out what data values and operations apply to the
  346. different tagged types.
  347. <P>
  348.  
  349. Type Thing should probably have the attributes Name and Description.
  350. It should also have a way of referring to its container, so we'll
  351. add a "Container" value in its implementation.
  352. For example, if Player "Fred" is the Room "kitchen", then Fred's
  353. Container would refer to the kitchen.
  354. <P>
  355.  
  356. Let's completely hide these attributes with other procedures; that way
  357. we can control what happens to these values.
  358. In fact, to change "where" an object is, let's only provide the operation
  359. "Place", which places a given Thing inside another thing.
  360. That way we can make sure that the internal data values
  361. are kept consistent.
  362. <P>
  363.  
  364. Let's implement "looking" as a pair of procedures. The first procedure,
  365. called "Look", is a message sent to the object
  366. doing the looking (i.e. a player).
  367. That procedure, should it consider looking okay (for example, if it
  368. determines that the player can see), will then call Put_View of
  369. whatever object the the player is looking at (i.e. the player's room).
  370. <P>
  371.  
  372. I suspect that, if a player is inside a room, the view is different than
  373. if the player is inside a dragon's belly.
  374. Therefore Put_View should be a
  375. dispatching operation so that it can do different things depending on the
  376. type of the object being viewed.
  377. In Ada 95, to make a subprogram dispatchable (primitive),
  378. place the subprogram's declaration in the specification declaring the type.
  379. <P>
  380.  
  381. By the same reasoning "Look" should be a primitive operation;
  382. perhaps different players have different kinds of vision
  383. (such as X-ray vision or vision that doesn't require light),
  384. so we'll want that to dispatch depending on the "looker" as well.
  385. <P>
  386.  
  387. We'll also need to handle getting and dropping objects.
  388. Many of the operations in an adventure game involve both the Actor
  389. (i.e. the Player) and the object being acted on.
  390. That's similar to how we handled looking, since looking
  391. involves both the looker and the looked-at object.
  392. For example, for a "Get" to work, the player must be able to get things,
  393. and the object being gotten must agree that it can be acquired by the player.
  394. So let's define pairs of operations for Get: Get itself, which asks
  395. a given actor to get an object, and May_I_Get, which asks the object if
  396. the given actor can get it.  The same argument applies to drop, which will
  397. have the pair Drop and May_I_Drop.
  398. <P>
  399.  
  400. <QUESTION Type=Multiple-Choice>
  401. If Item box and Player Fred are both in Room Kitchen,
  402. and Item knife is in Item box, what is the container of Item box?
  403. <CHOICES>
  404. <CHOICE ANS=1>Room Kitchen
  405. <CHOICE ANS=2>Player Fred
  406. <CHOICE ANS=3>Item knife
  407. <CHOICE ANS=4>Item box
  408. <CHOICE ANS=5>None of the above
  409. </CHOICES>
  410. <ANSWER ANS=1>
  411. <RESPONSES>
  412. <WHEN ANS=1>
  413. That's correct.
  414. You probably had to read that question several times, but
  415. I wanted to make sure you got the concept.
  416. <P>
  417. Notice that this hierarchy of containment (Room contains an Item which
  418. contains another Item) is completely different than the inheritance
  419. hierarchy.
  420. A kitchen may contain a box, and a box may contain a knife, but that
  421. does not mean that a knife is a kind of box.
  422. The concept of "hierarchy" is a useful concept, but it appears in several
  423. different contexts.
  424. Don't confuse an inheritance hierarchy (where one thing is an extension of
  425. another) with a containment hierarchy (where one thing is contained in another).
  426. <WHEN ANS=2>
  427. No, the container of Player Fred is the Room Kitchen, and
  428. none of the things mentioned were contained by Player Fred.
  429. Try again!
  430. <WHEN ANS=3>
  431. No, sorry.
  432. The container of Item knife is Item box, but that's not what was asked.
  433. The container of Item box is not Item knife, but something else.
  434. Please try again.
  435. <WHEN ANS=4>
  436. No, Item box doesn't contain itself.
  437. As an aside, self-containing objects are usually a sign of trouble in
  438. a text adventure game - you'll find that program "Small" specifically checks
  439. for this and prevents it.
  440. Try again.
  441. <WHEN ANS=5>
  442. No, sorry. Room kitchen didn't have any container mentioned for it,
  443. but there was a specific container listed for Item box.
  444. Go back to the question and see if you can determine what that is.
  445. </RESPONSES>
  446. <SECTION NAME="Parameter Types">
  447.  
  448. Now, I haven't mentioned how to define parameter types for all these
  449. operations. Ada provides several different choices - you can use a specific
  450. type name or an entire type class, and you can use an "access mode" or
  451. a normal mode (<I>in</I>, <I>in out</I>, or <I>out</I>).
  452. If you want to
  453. dispatch on a specific parameter, you can define operations as either of:
  454. <P>
  455. <PRE>
  456.   procedure Look(Actor : in Occupant);      -- Option 1.
  457.   procedure Look(Actor : access Occupant);  -- Option 2.
  458. </PRE>
  459. <P>
  460. For option 1, you're passing the Occupant to Look; in option 2,
  461. you're passing an access-to-Occupant value.
  462. Both will dispatch, both can be overridden, and you
  463. can use both approaches in the same program (it's no big deal to convert
  464. between them).
  465. Personally, I find that option 2 closer to the way I think
  466. about the problem, so I've used it throughout program Small where appropriate.
  467. Why do I find it more natural?
  468. Well, I think of Things lying out there in the simulated
  469. world, and that these subprogram simply pass around references to them.
  470. You'll find different people have different preferences depending on the
  471. circumstance.
  472. <P>
  473.  
  474. If you do <EM>not</EM> need to dispatch on an operation, you can define
  475. operations as:
  476. <P>
  477. <PRE>
  478.   procedure X(Actor : in Occupant'Class);       -- Option 3.
  479.   procedure X(Actor : access Occupant'Class);   -- Option 4.
  480.   procedure X(Actor : in Occupant_Access);      -- Option 5.
  481. </PRE>
  482. <P>
  483. Option 3 basically says we can accept any type at all as long as that
  484. type is a member of the class Occupant.
  485. Option 4 says we can take any access value at all, as long as 
  486. it accesses a type that's a member of Occupant'Class.
  487. Option 5 uses an access type defined elsewhere, and if that type
  488. (Occupant_Access)
  489. is defined as access Occupant'Class it's quite similar to option 4
  490. except in one very important way - option 5 permits a null value to
  491. be passed in.
  492. <P>
  493.  
  494. Thus, if we're passing around access values and we want to
  495. permit a null value, we should use "Occupant_Access" as the parameter type.
  496. Otherwise,
  497. if we don't need to pass a null value, we can use option 4 (so that
  498. it uses access values as well).
  499. <P>
  500.  
  501. Generally, if you use option 1 you'll use option 3, and if you use
  502. option 2 you'll use options 4 and 5 (depending on whether or not
  503. you want to permit a null value).
  504. Which you choose depends mainly on how you think about your problem -
  505. are you thinking in terms of passing around specific objects, or
  506. are you thinking in terms of passing access (reference) values to those
  507. objects?
  508. Your answer suggests which you should use.
  509. <P>
  510.  
  511. So what do we do about the function "Me" we mentioned earlier?
  512. Conceivably a future version might permit a Player to command a Monster
  513. or Item, so let's make
  514. function "Me" return an Occupant_Access.
  515. <P>
  516.  
  517. At this point we have the basic idea on how to implement Look, Quit,
  518. Get, Drop, and Inventory.
  519. <P>
  520.  
  521. <QUESTION Type=Multiple-Choice>
  522. Could the actual accessed object function "Me" returns be of type Player?
  523. <CHOICES>
  524. <CHOICE ANS=1>Yes.
  525. <CHOICE ANS=2>No.
  526. </CHOICES>
  527. <ANSWER ANS=1>
  528.  
  529. <SECTION NAME="Starting Implementation">
  530.  
  531. Okay, let's start implementing program Small.
  532. I started by writing a version of procedure body Small, package Parser,
  533. package Thing, and package World, just enough to make it possible to
  534. run "look" and "quit".
  535. Rather than looking at everything in program Small, let's quickly
  536. look at some specific areas.
  537. For example, let's look at how
  538. we can now define package Things more specifically:
  539. <P>
  540. <PRE>
  541.  
  542. package Things is
  543.  
  544.  -- "Thing" is the root class for all things in this small world.
  545.  -- Rooms, Players, Items, and Monsters are derived from Thing.
  546.  
  547.  type Thing is abstract new Limited_Controlled with private;
  548.  type Thing_Access is access all Thing'Class;
  549.  
  550.  -- Public Dispatching operations.
  551.  
  552.  procedure Put_View(T : access Thing; Agent : access Thing'Class) is abstract;
  553.   -- Put what Agent sees inside T.
  554.  
  555.   -- Public non-Dispatching operations:
  556.  
  557.  procedure Set_Description(T : access Thing'Class;
  558.                            Description : in String);
  559.  function Long_Description(T : access Thing'Class) return Unbounded_String;
  560.  function Short_Description(T : access Thing'Class) return Unbounded_String;
  561.  
  562.  -- ...
  563. end Things;
  564.  
  565. </PRE>
  566. <P>
  567. We now have a root type called "Thing" defined in package "Things".
  568. We can set its description using procedure Set_Description,
  569. and retrieve descriptions using functions Long_Description
  570. or Short_Description.
  571. Any player who successfully looks at some thing will call procedure
  572. Put_View to print whatever that Thing looks like.
  573. Now we can implement procedure "Look" in package Occupants; it will
  574. figure out what you're looking at and call the corresponding Put_View.
  575. <P>
  576.  
  577. For Get and Drop we'll add the corresponding operations to package Occupants.
  578. However, to implement Get and Drop we need to be able to move objects around.
  579. To do this, let's add this operation to package Thing:
  580. <P>
  581. <PRE>
  582.  procedure Place(T : access Thing'Class; Into : Thing_Access);
  583.    -- Place T inside "Into" (removing it from wherever it was).
  584.    -- Attempting to place T into itself will print an error message
  585.    -- and fail.
  586. </PRE>
  587. <P>
  588. Procedure Place doesn't need to dispatch, and we're passing access values
  589. around, so the first parameter is access Thing'Class (if we wanted
  590. this to dispatch, we could change it to "access Thing").
  591. The second parameter is Thing_Access, not Thing'Class, because
  592. "null" should be a valid value for "Into"
  593. (that would mean we'll move T so it will have no container).
  594. <P>
  595.  
  596. I've added support for directions -
  597. that way players can go north, south, east, west, up, or down.
  598. To do so, I've added a "Direction" type that has the values
  599. North, South, East, West, Up, and Down.
  600. Rooms have data on what's at a given direction, Occupants
  601. have commands to go in a given direction, and the Parser recognizes
  602. those commands.
  603. Since different packages (Rooms, Occupants, and Parser) need to know about
  604. directions, I've added another package (Directions) to define
  605. this new type Direction.
  606. <P>
  607.  
  608. <QUESTION Type=Multiple-Choice>
  609. Between Look and Put_View, which would be called first?
  610. <CHOICES>
  611. <CHOICE ANS=1>Look
  612. <CHOICE ANS=2>Put_View
  613. </CHOICES>
  614. <ANSWER ANS=1>
  615. <SECTION NAME="Closing Remarks on Program Small">
  616.  
  617. I haven't explained every detail of <A HREF="small.htm">program Small</A>,
  618. but hopefully by now you've got a flavor of it.
  619. <P>
  620.  
  621. There are lots of ways to extend this program; it's a small world, after all.
  622. You could add lots of specialized types of Item (door, key, weapon, etc.).
  623. You could add multi-playerness (this would involve finding a way to get
  624. data from multiple players,
  625. say a bindings to BSD-style sockets, and switching from Text_IO
  626. to an IO routine that would use the interface).
  627. You could permit dynamic creation and modification of the world at run-time
  628. (add a "wizard" command, and then add wizard-only commands like
  629. @create object, @destroy object, @view object, and @set object attribute=value).
  630. I haven't implemented independently active monsters, or a combat system, or
  631. magic; you might want one or more of them.
  632. Perhaps you could permit scripts to be executed at run-time.
  633. <P>
  634.  
  635. The best way to understand Small is probably to look at it.
  636. There are several ways you can look at it:
  637. <UL>
  638. <LI><A HREF="small.htm">You can look at the source code for
  639. program Small as a set of hypertext documents</A>;
  640. you can easily wander about the whole program in a little time, stopping
  641. and examining whatever parts interest you.
  642. <LI>You can view the
  643. <A HREF="small.txt">source code as a single large ASCII file</A>.
  644. <LI>You can download the
  645. <A HREF="small.zip">source files as a "zip" file</A>.
  646. </UL>
  647. <P>
  648.  
  649. You are strongly encouraged to wander about and look at
  650. <A HREF="small.htm">the hypertext source code for Small</A>, but
  651. you do not have to.
  652. The Lovelace home page has a link to Small if you choose to look
  653. at it later.
  654. <P>
  655.  
  656.