about summary refs log blame commit diff stats
path: root/js/games/nluqo.github.io/~bh/61a-pages/Volume1/Project3/adv.txt
blob: 755f2ed3e42f3e0a8dd081df7826089ae7120178 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718













































































































































































































































































































































































































































































































































































































































































































































                                                                               
Project:  Write an adventure game.  We'll provide most of the program.  You
will mostly make modification and some additions.

This project is designed to be done by two people working in parallel, then
combining your results into one finished product.  (Hereafter the two partners
are called Person A and Person B.)  But you will combine your work to hand in
a single report for your group.

The project begins with two exercises that everyone should do; these
exercises do not require new programming, but rather familiarize you
with the overall structure of the program as we've provided it.  After
that, each person has separate exercises.  There is one final exercise
for everyone that requires the two partners' work to be combined.
(Therefore, you should probably keep notes about all of the procedures
that you've modified during the project, so you can notice the ones that
both partners modified independently.)

This is a two-week project.  Each week, your group should
hand in one paper (not one per person) including a listing of your modified
adv.scm program with the modifications highlighted, and a transcript of the
testing of your work.  Indicate on the paper which of you is person A and
which is person B.

Scoring:  Each person works on nine problems.  Three of these (numbers
1, 2, and 9) are common to the two partners; the others are separate.
You hand in a single solution to each problem.  Both partners get
the points awarded to the group for problems 1, 2, and 9; each
person gets the points for his or her own problems 3 through 8.  This means
that your score for the project is mostly based on your individual work but
also relies partly on the other member of your group.  For the first two
problems, you could get away with letting your partner do the
work, but you shouldn't because those problems are necessary to help you
understand the structure of the entire project.  Problem 9 requires that both
partners have already done their separate work, and meet together to
understand each other's solutions, so probably nobody will get credit for it
unless both have done their jobs.

(Acknowledgement:  This assignment is loosely based on an MIT homework
assignment in their version of this course.  But since this is Berkeley we've
changed it to be politically correct; instead of killing each other, the
characters go around eating gourmet food all the time.  N.B.:  Unless you
are a diehard yuppie you may feel that eating gourmet food does not express
appropriate sensitivity to the plight of the homeless.  But it's a start.)

In this laboratory assignment, we will be exploring two key ideas: the
simulation of a world in which objects are characterized by a set of state
variables, and the use of message passing as a programming technique for
modularizing worlds in which objects interact.

OBJECT-ORIENTED PROGRAMMING is becoming an extremely popular methodology for
any application that involves interactions among computational entities.
Examples:

	-- operating systems (processes as objects)
	-- window systems (windows as objects)
	-- games (asteroids, spaceships, gorillas as objects)
	-- drawing programs (shapes as objects)


GETTING STARTED
To start, copy the following five files into your directory:
   ~cs61a/lib/obj.scm           The object-oriented system
   ~cs61a/lib/adv.scm           The adventure game program
   ~cs61a/lib/tables.scm	An ADT you'll need for parts A5 and B4
   ~cs61a/lib/adv-world.scm     The specific people, places, and things
   ~cs61a/lib/small-world.scm   A smaller world you can use for debugging

To work on this project, you must load these files into Scheme in the
correct order: obj.scm first, then adv.scm and tables.scm when you're using
that, and finally the particular world you're using, either adv-world.scm or
small-world.scm.  The work you are asked to do refers to adv-world.scm;
small-world.scm is provided in case you'd prefer to debug some of your
procedures in a smaller world that may be less complicated to remember and
also faster to load.

The reason the adventure game is divided into adv.scm (containing the
definitions of the object classes) and adv-world.scm (containing the
specific instances of those objects in Berkeley) is that when you change
something in adv.scm you may need to reload the entire world in order for
your changed version to take effect.  Having two files means that you don't
also have to reload the first batch of procedures.


In this program there are three classes: THING, PLACE, and PERSON.

Here are some examples selected from adv-world.scm:

;;; construct the places in the world
(define Soda (instantiate place 'Soda))
(define BH-Office (instantiate place 'BH-Office))
(define art-gallery (instantiate place 'art-gallery))
(define Pimentel (instantiate place 'Pimentel))
(define 61A-Lab (instantiate place '61A-Lab))
(define Sproul-Plaza (instantiate place 'Sproul-Plaza))
(define Telegraph-Ave (instantiate place 'Telegraph-Ave))
(define Noahs (instantiate place 'Noahs))
(define Intermezzo (instantiate place 'Intermezzo))
(define s-h (instantiate place 'sproul-hall))

;;; make some things and put them at places
(define bagel (instantiate thing 'bagel))
(ask Noahs 'appear bagel)

(define coffee (instantiate thing 'coffee))
(ask Intermezzo 'appear coffee)

;;; make some people
(define Brian (instantiate person 'Brian BH-Office))
(define hacker (instantiate person 'hacker Pimentel))

;;; connect places in the world

(can-go Soda 'up art-gallery)
(can-go art-gallery 'west BH-Office)
(can-go Soda 'south Pimentel)

Having constructed this world, we can now interact with it by sending
messages to objects.  Here is a short example.

; We start with the hacker in Pimentel.

> (ask Pimentel 'exits)
(NORTH SOUTH)
> (ask hacker 'go 'north)
HACKER moved from PIMENTEL to SODA


We can put objects in the different places, and the people can then take the
objects:

> (define Jolt (instantiate thing 'Jolt))
JOLT
> (ask Soda 'appear Jolt)
APPEARED
> (ask hacker 'take Jolt)
HACKER took JOLT
TAKEN

You can take objects away from other people, but the management is not
responsible for the consequences...  (Too bad this is a fantasy game, and
there aren't really vending machines in Soda that stock Jolt.)

PART I:

The first two exercises in this part should be done by everyone -- that is,
everyone should actually sit in front of a terminal and do it!  It's okay to
work in pairs as long as you all really know what's going on by the time
you're finished.  (Nevertheless, you should only hand in one solution, that
both agree about.)  The remaining exercises have numbers like "A3"
which means exercise 3 for Person A.

After you've done the work separately, you should meet together
to make sure that you each understands what the other person did, because
the second week's work depends on all of the first week's work.  You can
do the explaining while you're merging the two sets of modifications into
one adv.scm file to hand in.

1.  Create a new person to represent yourself.  Put yourself in a new place
called Dormitory (or wherever you live) and connect it to campus so that you
can get there from here.  Create a place called Kirin, north of Soda.
(It's actually on Solano Avenue.)  Put a thing called Potstickers there.
Then give the necessary commands to move your character to Kirin, take
the Potstickers, then move yourself to where Brian is, put down the
Potstickers, and have Brian take them. Then go back to the lab and get back
to work. (There is no truth to the rumor that you'll get an A in the course
for doing this in real life!)  All this is just to ensure that you know how
to speak the language of the adventure program.

LIST ALL THE MESSAGES THAT ARE SENT DURING THIS EPISODE.  It's a good idea
to see if you can work this out in your head, at least for some of the
actions that take place, but you can also trace the ASK procedure to get
a complete list.  You don't have to hand in this listing of messages.  (Do
hand in a transcript of the episode without the tracing.)  The point is that
you should have a good sense of the ways in which the different objects send
messages back and forth as they do their work.

[Tip:  we have provided a MOVE-LOOP procedure that you may find useful as
an aid in debugging your work.  You can use it to move a person repeatedly.]


2.  It is very important that you think about and understand the kinds of
objects involved in the adventure game.  Please answer the following questions:

2A.  What kind of thing is the value of variable BRIAN?

Hint:  What is returned by scheme in the following situation:
     You type:     > BRIAN


2B.   List all the messages that a PLACE understands.  (You might want to
maintain such a list for your own use, for every type of object, to help
in the debugging effort.)


2C.   We have been defining a variable to hold each object in our world.
For example, we defined bagel by saying:

     (define bagel (instantiate thing 'bagel))

This is just for convenience.  Every object does not have to have a
top-level definition.  Every object DOES have to be constructed and
connected to the world.  For instance, suppose we did this:

> (can-go Telegraph-Ave 'east (instantiate place 'Peoples-Park))

;;; assume BRIAN is at Telegraph
> (ask Brian 'go 'east)

What is returned by the following expressions and WHY?

> (ask Brian 'place)

> (let ((where (ask Brian 'place)))
       (ask where 'name))

>  (ask Peoples-park 'appear bagel)



2D.  The implication of all this is that there can be multiple names for
objects.  One name is the value of the object's internal NAME variable. In
addition, we can define a variable at the top-level to refer to an object.
Moreover, one object can have a private name for another object.  For
example, BRIAN has a variable PLACE which is currently bound to the object
that represents People's Park.  Some examples to think about:

      > (eq? (ask Telegraph-Ave 'look-in 'east) (ask Brian 'place))

      > (eq? (ask Brian 'place) 'Peoples-Park)

      > (eq? (ask (ask Brian 'place) 'name) 'Peoples-Park)


OK.  Suppose we type the following into scheme:

>  (define computer (instantiate thing 'Durer))


Which of the following is correct?  Why?

(ask 61a-lab 'appear computer)

or

(ask 61a-lab 'appear Durer)

or 

(ask 61a-lab 'appear 'Durer)

What is returned by (computer 'name)?  Why?


2E.  We have provided a definition of the THING class that does not use
the object-oriented programming syntax described in the handout.  Translate
it into the new notation.

2F.  Sometimes it's inconvenient to debug an object interactively because
its methods return objects and we want to see the names of the objects.  You
can create auxiliary procedures for interactive use (as opposed to use
inside object methods) that provide the desired information in printable
form.  For example:

(define (name obj) (ask obj 'name))
(define (inventory obj)
  (if (person? obj)
      (map name (ask obj 'possessions))
      (map name (ask obj 'things))))

Write a procedure WHEREIS that takes a person as its argument and returns
the name of the place where that person is.

Write a procedure OWNER that takes a thing as its argument and returns the
name of the person who owns it.  (Make sure it works for things that aren't
owned by anyone.)

Procedures like this can be very helpful in debugging the later parts of the
project, so feel free to write more of them for your own use.


Now it's time for you to make your first modifications to the adventure
game.  This is where you split the work individually.

PART I -- PERSON A:

A3.  You will notice that whenever a person goes to a new place, the place
gets an 'ENTER message.  In addition, the place the person previously
inhabited gets an 'EXIT message.  When the place gets the message, it calls
each procedure on its list of ENTRY-PROCEDURES or EXIT-PROCEDURES as
appropriate.  Places have the following methods defined for manipulating
these lists of procedures:  ADD-ENTRY-PROCEDURE, ADD-EXIT-PROCEDURE,
REMOVE-ENTRY-PROCEDURE,
REMOVE-EXIT-PROCEDURE, CLEAR-ALL-PROCS.  You can read their definitions in the
code.

Sproul Hall has a particularly obnoxious exit procedure attached to it.  Fix
SPROUL-HALL-EXIT so that it counts how many times it gets called, and stops
being obnoxious after the third time.

Remember that the EXIT-PROCS list contains procedures, not names of
procedures!  It's not good enough to redefine SPROUL-HALL-EXIT, since Sproul
Hall's list of exit procedures still contains the old procedure.  The best
thing to do is just to load adv-world.scm again, which will define a new
sproul hall and add the new exit procedure.



A4a.  We've provided people with the ability to say something using the
messages 'TALK and 'SET-TALK.  As you may have noticed, some people around
this campus start talking whenever anyone walks by.  We want to simulate this
behavior.  In any such interaction there are two people involved: the one
who was already at the place (hereafter called the TALKER) and the one who
is just entering the place (the LISTENER).  We have already provided a
mechanism so that the listener sends an ENTER message to the place when
entering.  Also, each person is ready to accept a NOTICE message, meaning
that the person should notice that someone new has come.  The talker should
get a NOTICE message, and will then talk, because we've made a person's
NOTICE method send itself a TALK message.  (Later we'll see that some special
kinds of people have different NOTICE methods.)

Your job is to modify the ENTER method for places, so that in addition to
what that method already does, it sends a NOTICE message to each person in
that place other than the person who is entering.  The NOTICE message should
have the newly-entered person as an argument.  (You won't do anything with
that argument now, but you'll need it later.)

Test your implementation with the following:

(define singer (instantiate person 'rick sproul-plaza))

(ask singer 'set-talk "My funny valentine, sweet comic valentine")

(define preacher (instantiate person 'preacher sproul-plaza))

(ask preacher 'set-talk "Praise the Lord")

(define street-person (instantiate person 'harry telegraph-ave))

(ask street-person 'set-talk "Brother, can you spare a buck")

YOU MUST INCLUDE A TRANSCRIPT IN WHICH YOUR CHARACTER WALKS AROUND AND
TRIGGERS THESE MESSAGES.


A4b.  So far the program assumes that anyone can go anywhere they want.
In real life, many places have locked doors.

Invent a MAY-ENTER? message for places that takes a person as an argument and
always returns #T.  Then invent a LOCKED-PLACE class in which the MAY-ENTER?
method returns #T if the place is unlocked, or #F if it's locked.  (It should
initially be locked.)  The LOCKED-PLACE class must also have an UNLOCK
message.  For simplicity, write this method with no arguments and have it
always succeed.  In a real game, we would also invent keys, and a mechanism
requiring that the person have the correct key in order to unlock the door.
(That's why MAY-ENTER? takes the person as an argument.)

Modify the person class so that it checks for permission to enter before
moving from one place to another.  Then create a locked place and test
it out.


A5.  Walking around is great, but some people commute from far away, so
they need to park their cars in garages.  A car is just a THING, but you'll
have to invent a special kind of place called a GARAGE.  Garages have two
methods (besides the ones all places have): PARK and UNPARK.  You'll also
need a special kind of THING called a TICKET; what's special about it is
that it has a NUMBER as an instantiation variable.

The PARK method takes a car (a THING) as its argument.  First check to be sure
that the car is actually in the garage.  (The person who possesses the car
will enter the garage, then ask to park it, so the car should have entered the
garage along with the person before the PARK message is sent.)  Then generate
a TICKET with a unique serial number.  (The counter for serial numbers should
be shared among all garages, so that we don't get in trouble later trying to
UNPARK a car from one garage that was parked in a different garage.)  Every
ticket should have the name TICKET.

You'll associate the ticket number with the car in a key-value table like the
one that we used with GET and PUT in 2.3.3.  However, GET and PUT refer to a
single, fixed table for all operations; in this situation we need a separate
table for every garage.  The file tables.scm contains an implementation of the
table Abstract Data Type:

constructor: (make-table) returns a new, empty table.

mutator: (insert! key value table) adds a new key-value pair to a table.

selector: (lookup key table) returns the corresponding value, or #F if
				the key is not in the table.

You'll learn how tables are implemented in 3.3.3 (pp. 266-268).
For now, just take them as primitive.

Make a table entry with the ticket number as the key, and the car as the
value.  Then ask the car's owner to lose the car and take the ticket.

The UNPARK method takes a ticket as argument.  First make sure the object
you got is actually a ticket (by checking the name).  Then look up the
ticket number in the garage's table.  If you find a car, ask the ticket's
owner to lose the ticket and take the car.  Also, insert #F in the table for
that ticket number, so that people can't unpark the car twice.

A real-life garage would have a limited capacity, and would charge money
for parking, but to simplify the project you don't have to simulate those
aspects of garages.


--- End of Part I for Person A


PART I, PERSON B:


B3.  Define a method TAKE-ALL for people.  If given that message, a person
should TAKE all the things at the current location that are not already
owned by someone.


B4a.  It's unrealistic that anyone can take anything from anyone.  We want to
give our characters a STRENGTH, and then one person can take something from
another only if the first has greater STRENGTH than the second.

However, we aren't going to clutter up the person class by adding a local
STRENGTH variable.  That's because we can anticipate wanting to add lots
more attributes as we develop the program further.  People can have CHARISMA
or WISDOM; things can be FOOD or not; places can be INDOORS or not.
Therefore, you will create a class called BASIC-OBJECT that keeps a local
variable called PROPERTIES containing an attribute-value table like the
one that we used with GET and PUT in 2.3.3.  However, GET and PUT refer to
a single, fixed table for all operations; in this situation we need a
separate table for every object.  The file tables.scm contains an
implementation of the table Abstract Data Type:

constructor: (make-table) returns a new, empty table.

mutator: (insert! key value table) adds a new key-value pair to a table.

selector: (lookup key table) returns the corresponding value, or #F if
				the key is not in the table.

You'll learn how tables are implemented in 3.3.3 (pp. 266-268).
For now, just take them as primitive.

You'll modify the person, place and thing classes so that they will inherit
from basic-object.  This object will accept a message PUT so that
	> (ask Brian 'put 'strength 100)
does the right thing.  Also, the basic-object should treat any message not
otherwise recognized as a request for the attribute of that name, so
	> (ask Brian 'strength)
	100
should work WITHOUT having to write an explicit STRENGTH method in the
class definition.

Don't forget that the property list mechanism in 3.3.3 returns #F if you ask
for a property that isn't in the list.  This means that
	> (ask Brian 'charisma)
should never give an error message, even if we haven't PUT that property in
that object.  This is important for true-or-false properties, which will
automatically be #F (but not an error) unless we explicitly PUT a #T
value for them.

Give people some reasonable (same for everyone) initial strength.  Next
week they'll be able to get stronger by eating.

B4b.  You'll notice that the type predicate PERSON? checks to see if the type
of the argument is a member of the list '(person police thief).  This means
that the PERSON? procedure has to keep a list of all the classes that
inherit from PERSON, which is a pain if we make a new subclass.

We'll take advantage of the property list to implement a better system for
type checking.  If we add a method named PERSON? to the person class, and
have it always return #T, then any object that's a type of person will
automatically inherit this method.  Objects that don't inherit from person
won't find a PERSON? method and won't find an entry for person? in their
property table, so they'll return #F.

Similarly, places should have a PLACE? method, and things a THING? method.

Add these type methods and change the implementation of the type predicate
procedures to this new implementation.


B5.  In the modern era, many places allow you to get connected to the net.
Define a HOTSPOT as a kind of place that allows network connectivity.  Each
hotspot should have a PASSWORD (an instantiation variable) that you must know
to connect.  (Note: We're envisioning a per-network password, not a per-person
password as you use with AirBears.)  The hotspot has a CONNECT method with two
arguments, a LAPTOP (a kind of thing, to be invented in a moment) and a
password.  If the password is correct, and the laptop is in the hotspot, add
it to a list of connected laptops.  When the laptop leaves the hotspot, remove
it from the list.

Hotspots also have a SURF method with two arguments, a laptop and a text
string, such as

		"http://www.cs.berkeley.edu"

If the laptop is connected to the network, then the surf method should

	(system (string-append "lynx " url))

where URL is the text string argument.

Now invent laptops.  A laptop is a thing that has two extra methods:  CONNECT,
with a password as argument, sends a CONNECT message to the place where the
laptop is.  SURF, with a URL text string as argument, sends a SURF message to
the place where it is.  Thus, whenever a laptop enters a new hotspot, the user
must ask to CONNECT to that hotspot's network; when the laptop leaves the
hotspot, it must automatically be disconnected from the network.  (If it's in
a place other than a hotspot, the SURF message won't be understood; if it's in
a hotspot but not connected, the hotspot won't do anything.)


--- End of Part I, PERSON B.


PART II:

This part of the project includes three exercises for each person, but YOU
HAVE TO READ EACH OTHER'S CODE midweek, because one partner's exercises 7 and
8 build on the other partner's exercise 6.  Finally, exercise 9 requires the
two partners' work to be combined.  You will have to create a version of
adv.scm that has both partners' changes.  This may take some thinking!  If
both parners modify the same method in the same object class, you'll have to
write a version of the method that incorporates both modifications.


PART II, PERSON A:

Adv.scm includes a definition of the class THIEF, a subclass of person.
A thief is a character who tries to steal food from other people.  Of
course, Berkeley can not tolerate this behavior for long.  Your job is to
define a POLICE class; police objects catch thieves and send them directly
to jail.  To do this you will need to understand how theives work.

Since a thief is a kind of person, whenever another person enters the place
where the thief is, the thief gets a NOTICE message from the place.  When
the thief notices a new person, he does one of two things, depending on the
state of his internal BEHAVIOR variable.  If this variable is set to STEAL,
the thief looks around to see if there is any food at the place.  If there
is food, the thief takes the food from its current possessor and sets his
behavior to RUN.  When the thief's behavior is RUN, he moves to a new random
place whenever he NOTICEs someone entering his current location.  The RUN
behavior makes it hard to catch a thief.

Notice that a thief object delegates many messages to its person object.


A6a.  To help the police do their work, you will need to create a place called
jail.  Jail has no exits.  Moreover, you will need to create a method for
persons and thieves called GO-DIRECTLY-TO.  Go-directly-to does not require
that the new-place be adjacent to the current-place.  So by calling (ASK
THIEF 'GO-DIRECTLY-TO JAIL) the police can send the thief to jail no matter
where the thief currently is located, assuming the variable thief is bound
to the thief being apprehended.


A6b.  Thieves sometimes try to leave their place in a randomly chosen
direction.  This, it turns out, won't work if there are no exits from
that place -- for example, the jail.  Modify the THIEF class so that
a thief won't try to leave a place with no exits.

** Now get your partner to explain problem B6 and its solution. **

A7a.  We are now going to invent restaurant objects.  People will interact
with the restaurants by buying food there.  First we have to make it possible
for people to buy stuff.  Give PERSON objects a MONEY property, which is a
number, saying how many dollars they have.  Note that money is not an
object.  We implement it as a number because, unlike the case of objects
such as chairs and potstickers, a person needs to be able to spend SOME
money without giving up all of it.  In principle we could have objects like
QUARTER and DOLLAR-BILL, but this would make the change-making process
complicated for no good reason.

To make life simple, we'll have every PERSON start out with $100.  (We should
really start people with no money, and invent banks and jobs and so on, but
we won't.)  Create two methods for people, GET-MONEY and PAY-MONEY, each of
which takes a number as argument and updates the person's money value
appropriately.  PAY-MONEY must return true or false depending on whether
the person had enough money.


A7b.  Another problem with the adventure game is that Noah's only has one
bagel.  Once someone has taken that bagel, they're out of business.

To fix this, we're going to invent a new kind of place, called a RESTAURANT.
(That is, RESTAURANT is a subclass of PLACE.)  Each restaurant serves only
one kind of food.  (This is a simplification, of course, and it's easy to see
how we might extend the project to allow lists of kinds of food.)  When a
restaurant is instantiated, it should have two extra arguments, besides the
ones that all places have: the class of food objects that this restaurant
sells,  and the price of one item of this type:

   > (define-class (bagel) (parent (food ...)) ...)

   > (define Noahs (instantiate restaurant 'Noahs bagel 0.50))

Notice that the argument to the restaurant is a CLASS, not a particular
bagel (instance).

Restaurants should have two methods.  The MENU method returns a list
containing the name and price of the food that the restaurant sells.
The SELL method takes two arguments, the person who wants to buy something
and the name of the food that the person wants.  The SELL method must first
check that the restaurant actually sells the right kind of food.  If so,
it should ASK the buyer to PAY-MONEY in the appropriate amount.  If that
succeeds, the method should instantiate the food class and return the new
food object.  The method should return #F if the person can't buy the food.


A8.  Now we need a BUY method for people.  It should take as argument the
name of the food we want to buy:  (ask Brian 'buy 'bagel).  The method must
send a SELL message to the restaurant.  If this succeeds (that is, if the
value returned from the SELL method is an object rather than #F) the new food
should be added to the person's possessions.

--- Person A skip to question 9 below.

PART II, PERSON B:

B6.  The way we're having people take food from restaurants is unrealistic
in several ways.  Our overall goal this week is to fix that.  As a first
step, you are going to create a FOOD class.
We will give things that are food two properties, an EDIBLE? property
and a CALORIES property.  EDIBLE?  will have the value #T if the object is a
food.  If a PERSON eats some food, the food's CALORIES are added to the
person's STRENGTH.

(Remember that the EDIBLE? property will automatically be false for objects
other than food, because of the way properties were implemented in question B4.
You don't have to go around telling all the other stuff not to be edible
explicitly.)

Write a definition of the FOOD class that uses THING as the parent class.
It should return #T when you send it an EDBILE? message, and it should
correctly respond to a CALORIES message.

Replace the procedure named EDIBLE? in the original adv.scm with a new
version that takes advantage of the mechanism you've created, instead of
relying on a built-in list of types of food.

Now that you have the FOOD class, invent some child classes for particular
kinds of food.  For example, make a bagel class that inherits from FOOD.
Give the bagel class a class-variable called NAME whose value is the word
bagel.  (We'll need this later when we invent RESTAURANT objects.)

Make an EAT method for people.  Your EAT method should look at your
possessions and filter for all the ones that are edible.  It should then add
the calorie value of the foods to your strength.  Then it should make the
foods disappear (no longer be your possessions and no longer be at your
location).

** Now get your partner to explain problem A6 and its solution. **

B7.  Your job is to define the police class.  A policeperson is to have the
following behavior:

The police stays at one location.  When the police notices a new person
entering the location, the police checks to see if that person is a thief.
If the person is a thief the police says "Crime Does Not Pay," then takes
away all the thief's possessions and sends the thief directly to jail.

Give thieves and police default strengths.  Thieves should start out stronger
than persons, but police should be stronger than thieves.  Of course, if you
eat lots you should be able to build up enough STRENGTH (mass?) to take food
away from a thief.  (Only a character with a lot of CHUTZPAH would take food
away from the police. :-)

Please test your code and turn in a transcript that shows the thief stealing
your food, you chasing the thief and the police catching the thief.  In case
you haven't noticed, we've put a thief in Sproul Plaza.


B8.  Now we want to reorganize TAKE so that it looks to see who previously
possesses the desired object.  If its possessor is 'NO-ONE, go ahead and
take it as always.  Otherwise, invoke
	(ask thing 'MAY-TAKE? receiver)
The MAY-TAKE? method for a thing that belongs to someone should compare
the strength of its owner with the strength of the requesting person to
decide whether or not it can be taken.  The method should return #F
if the person may not take the thing, or the thing itself if the person may
take it.  This is a little more complicated than necessary right now, but
we are planning ahead for a situation in which, for example, an object
might want to make a clone of itself for a person to take.

Note the flurry of message-passing going on here.  We send a message to the
taker.  It sends a message to the thing, which sends messages to two people
to find out their strengths.

--- End of Part II, Person B (but both partners do question 8 below).

9.  Combine the two partners' work.  For example, both partners have
created new methods for the PERSON class.  Both partners have done work
involving strengths of kinds of people; make sure they work together.

Now make it so that when a POLICE person asks to BUY some food the
restaurant doesn't charge him or her any money.  (This makes the game
more realistic...)

******** OPTIONAL **********
As you can imagine, this is a truly open-ended project.  If you have the
time and inclination, you can populate your world with new kinds of people
(e.g., punk-rockers), places (Gilman-St), and especially things (magic
wands, beer, gold pieces, cars looking for parking places...).

For your enjoyment we have developed a procedure that creates a labyrinth (a
maze) that you can explore.  To do so, load the file ~cs61a/lib/labyrinth.scm.
[Note: labyrinth.scm may need some modification to work with the procedures
you developed in part two of the project.]

Legend has it that there is a vast series of rooms underneath Sproul Plaza.
These rooms are littered with food of bygone days and quite a few theives.
You can find the secret passage down in Sproul Plaza.

You may want to modify FANCY-MOVE-LOOP so that you can look around in nearby
rooms before entering so that you can avoid thieves.  You might also want
your character to maintain a list of rooms visited on its property list so
you can find your way back to the earth's surface.