@comment(Hey, EMACS, this is -*- SCRIBE -*- input)
@device(dover)
@make(6001)

@modify(excounter, numbered [Exercise @1], referenced [@1])

@PageHeading(left "6.001 -- Fall Semester 1985",
             center "@Value(Page)",
             right "Problem set 7")

@begin(center)
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001 Structure and Interpretation of Computer Programs
Fall Semester, 1985

Problem Set 7
@end(center)
@blankspace(0.25 in)

@flushleft(Issued: October 29, 1985)
Due:
@begin(itemize)
Friday, November 8, 1985 --
For recitations meeting at 9:00, 10:00 and 11:00

Wednesday, November 6, 1985 --
For recitations meeting at 12:00, 1:00 and 2:00, 
@end(itemize)

Reading Assignment: Sections 3.4.1, 3.4.2, 3.4.3, plus attached code.

@blankspace(0.25 in)
@begin(center)
@b[Exercises]
@end(center)

Write up and turn in the following exercises from the text:

@begin(itemize)
Exercise 3.38: @a[left-accumulate]

Exercise 3.39: @a[accumulate-n]

Exercise 3.40: vector operations

@end(itemize)

@blankspace(0.25 in)

@begin(center)
@b[LABORATORY ASSIGNMENT: The Adventure Game]
@end(center)

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.  We will
do this in the context of a simplified version of the ``Adventure''
game, a ``Dungeons & Dragons'' style game that is available on many
computers and has provided an interesting waste of time for many
computer lovers.


The basic idea of such games is that the user is placed, as a
character, in an imaginary world inhabited by other (usually
imaginary) characters. The user plays the game by 
issuing commands to the computer that have the effect of
moving him around in the imaginary world and that perform acts in the
imaginary world, like picking up an object. The computer simulates his moves
and responds, allowing him to make legal moves and rejecting illegal ones.
For example, it is illegal to move between places that are not connected
(unless you have a magic wand). If a move is legal, the computer
updates its model of the world and allows the next move to be considered.

@paragraph(The essential  system -- places and persons)
In order to get going, we need to establish the structure of our
imaginary world -- the objects that exist and the ways they relate to
each other. The simulator for the world is contained in two files,
which can be found at the end of the problem set. The first file,
@a[ps7-adv.scm], contains procedures to create places and things, and
various other useful procedures that you will not need to modify. The
second file, @a[ps7-mods.scm], contains a procedure to create people,
which you may need to modify, as well as an initial data base defining
a particular world with various familiar and unfamilar places
represented, and with two people, ERIC and HAL, as well as procedures
for creating a TROLL and a DEAN. (The procedures defining the last two
are incomplete and will be finished as part of this laboratory.) Both
files will be loaded with the @a[load-problem-set] command.

Initially, the three procedures for creating objects in our world
are:
@begin(programexample)
	(make-place name)
	(make-thing name)
	(make-person name place threshold-for-moving)
@end(programexample)
For example, the procedure MAKE-PERSON is used to create the two
people, ERIC and HAL.  All of these procedures are standard message-passing
procedures, similar to what we have already seen in section
2.3.3 of the text and in the bank account example of Chapter 3.  For
example, MAKE-PERSON  creates and returns a dispatch function with a
set of procedures and local state attached to it.  Thus
ERIC is represented as a dispatch procedure, and
to perform some action on ERIC, we simply send him an appropriate message
by calling that procedure with the message as argument. 

For example, once these files are loaded, we will be able to find out
where ERIC and HAL are and to walk them around in the world:
@begin(programexample)
==> (eric 'current-position)
ERIC-OFFICE

==> (hal 'current-position)
HAL-OFFICE

==> (hal 'exits)
(UP DOWN)

==> ((hal 'go) 'down)
HAL moved from HAL-OFFICE to TECH-SQUARE
()

==> (hal 'exits)
(UP SOUTH)

==> ((hal 'go) 'south)
HAL moved from TECH-SQUARE to BLDG-36
()

==> (hal 'exits)
(WEST NORTH UP)

==> ((hal 'go) 'up)
HAL moved from BLDG-36 to COMPUTER-LAB
()

==> ((eric 'go) 'down)
ERIC moved from ERIC-OFFICE to HAL-OFFICE
()

==> ((eric 'go) 'down)
ERIC moved from HAL-OFFICE to TECH-SQUARE
()

==> ((eric 'go) 'south)
ERIC moved from TECH-SQUARE to BLDG-36
()

==> ((eric 'go) 'up)
ERIC moved from BLDG-36 to COMPUTER-LAB
ERIC says - Hi, HAL
()

==> (eric 'look-around)
HAL
()

==> (hal 'look-around)
ERIC
()

@end(programexample)

Note that some messages return a procedure that must then be applied to another
message.  For instance, (ERIC 'GO) returned a procedure that 
accepted the direction in which we wanted ERIC to go.

In principle, we could run the ADVENTURE system by simply issuing
commands to each of the creatures in the world, as we did above.
This, however,
defeats the notion of the game, since the user
has control over all the creatures.  Instead, we will
structure our system so that all the characters, with the possible
exception of ourselves, are manipulated in some fashion by the
computer, while we are able only to control our own actions.  We will
do this by creating a queue, consisting of all the creatures currently
active in our world, and using a clock to simulate the passage of time
in the world.  A special procedure, CLOCK, is provided, that upon
invocation sends a MOVE message to each of the creatures on the queue.
A MOVE message does not automatically imply that the creature
receiving it will change location.  Rather, like all of us, a creature
will tend to stay in one place until he or she (or it) gets bored
enough and moves on to a new place.  To account for this, the third
argument to MAKE-PERSON specifies the number of clock intervals that
the person will remain in his or her current place before moving.
Since different people get bored at different rates, this argument
obviously can be different for each creature in the world.

Before we trigger the clock to simulate a game, let's explore the
properties of our world a bit more.
First, let's create a COMPUTER-MANUAL and place it in the COMPUTER-LAB
(where HAL and ERIC now are).
@begin(programexample)
==> (define computer-manual (make-thing 'computer-manual))
COMPUTER-MANUAL

==> ((computer-lab 'appear) computer-manual)
APPEARED
@end(programexample)
Next, we'll have HAL look around.
@begin(programexample)
==> (hal 'look-around)
COMPUTER-MANUAL
ERIC
()
@end(programexample)
The manual looks useful, so HAL picks it up and adds it to his possessions.
@begin(programexample)
==> ((hal 'take) computer-manual)
HAL took COMPUTER-MANUAL
TAKEN
@end(programexample)
If HAL leaves, the manual goes with him.
@begin(programexample)
==> ((hal 'go) 'down)
HAL moved from COMPUTER-LAB to BLDG-36
()

==> (hal 'list-possessions)
COMPUTER-MANUAL
()
@end(programexample)
ERIC had also noticed the COMPUTER-MANUAL; he follows HAL and snatches the
manual away.
@begin(programexample)
==> ((eric 'go) 'down)
ERIC moved from COMPUTER-LAB TO BLDG-36
ERIC says - Hi, HAL
()

==> ((eric 'take) computer-manual)
ERIC took COMPUTER-MANUAL
Yaaaah! HAL is upset!
TAKEN

==> (eric 'list-possessions)
COMPUTER-MANUAL
()

==> (hal 'list-possessions)
()
@end(programexample)
The people, places, and things in our world have many other features built in.
and it is recommended that you look carefully at the code to see some
of them.  Still other features could
readily be added; building such programs is often a good deal of fun. For
the rest of this laboratory, we'll concentrate on a few aspects of the world
we have built.

For many of these problems, you can use the editor to enter your
definitions in your modifiable file. Notice that because the Adventure
model works by mutation of data, it is possible to get your SCHEME
into an inconsistent state while debugging. If this happens and if you
have been careful about the order in which you have entered your
definitions in the file @a[ps7-mods.scm], you can re-initialize
by reloading this file.

Many of the problems in this assignment are concerned with incremental
changes to the procedures MAKE-PERSON, MAKE-DEAN and MAKE-TROLL.  As a
consequence, rather than turning in several different versions of the
same procedures, we suggest that after having finished all nine
problems, you turn in one version of each of the modified procedures,
clearly marking all of your changes, and indicating for each change,
what problem the change was made in response to.  

@paragraph(Problem 1)
Make HAL and ERIC move around by repeatedly calling CLOCK (with no
arguments).  Which person is more restless?  How often do both of
them move at the same time?

@paragraph(Problem 2)
Define a new character -- yourself --
with a high enough threshold (say, 100) so that you have "free will" and will
not be moved by the clock.  Place yourself initially in the DORMITORY.
Create a new thing, LATE-HOMEWORK, and
also place it in the DORMITORY. Pick up the LATE-HOMEWORK, find out
where HAL is using the message CURRENT-POSITION, and move yourself to
HAL's location. Try to get HAL to TAKE the homework even though it's
late. Can you find a way to do this that does not leave @a[you] upset?
Turn in  a list of your definitions and actions.

@paragraph(Problem 3)
Draw an environment diagram (see section 3.2 of the text) for the procedure
object that was created when you defined your new character in Problem 2.
Don't draw the complete environment diagram for DORMITORY.

@paragraph(Problem 4)
Our system so far contains three types of objects, PLACE,
PERSON, and THING.  Note that objects of the same type may
be created by different procedures.  For instance, a DEAN, while a
PERSON, differs in some ways from ordinary people, and
hence is created by the procedure MAKE-DEAN rather than the general
procedure MAKE_PERSON.  PLACE, PERSON, and THING objects have one
thing in common -- they all accept the messages TYPE and NAME. In
addition to these two basic messages, however, each
object also supports a set of specialized messages. For example, a PLACE object
supports the message APPEAR.  Suppose we were going to design a new
procedure to create a new variation of some type of object, for example, we
might want to have a procedure that created a PROFESSOR object, which
is a kind of person (contrary to popular belief!).  In order for this
new type of object to interact properly with the other objects in the
world, it is important that it support the right messages.
The messages supported by an object can be separated into
mandatory and optional messages, depending on whether other objects
depend on that message.
For example, PLACE must support APPEAR, because
PERSON objects depend on APPEAR. However, a PERSON object does not have to
support LOOK-AROUND, because no other type of object depends on
LOOK-AROUND.

For each of the three types of objects, PERSON, PLACE and THING,
produce a table of the messages they support and the function of the
messages. For each type of object, say whether each of its messages is
optional or mandatory. 

@paragraph(Problem 5)
Let's add another character to our world -- an officious
DEAN who is paranoid on the subject of beer on campus. When he can no longer
control himself, the DEAN wanders about; any beer he finds, he smashes. 
A procedure MAKE-DEAN is included in your package. To complete it, you need
to write a simple procedure BEERS-AT-PLACE that returns
a list of the BEERS at a given place.  Note that the DEAN is so
paranoid, he doesn't notice beer that is not in someone's possession,
so your procedure should only return a list of the BEERS at a given
place that are actually owned by someone.
If there are no such BEERs, BEERS-AT-PLACE should return the empty list.
Note that there may be many different beers present in the world.
In our world, BEER is simply defined as a  THING which has the name
BEER, so that, for example,
@begin(programexample)
(define Molson (make-thing 'beer))
(define Labatts (make-thing 'beer))
(deflne Carling (make-thing 'beer))
@end(programexample)
is a permissible way of creating several different instances of beer.

Actually make the DEAN and install him in the DEAN-OFFICE, with a
OFFICIOUSNESS threshold of 3. Test your work by reloading
@a[ps7-mods.scm] and exercising it by creating some beer, having
one of your characters possess it and moving the dean around (by
sending him MOVE messages) to ensure that the right things happen when
he (or she) encounters someone possessing beer. Turn in a listing of
your modifications, definitions and new procedures.

@paragraph(Problem 6)
Let's add one more creature to our menagerie -- a TROLL, named GRENDEL, who
normally lives in a DUNGEON concealed under the EGG-ATRIUM. A  troll
is a creature with rather simple needs. After a certain number of clock
intervals, it gets hungry and leaves its DUNGEON to wander
around the world  seeking food.  It will eat the first person it runs
into, unless that person can offer it the one food it likes better --
a PIZZA. When it's finished eating, the troll returns to its DUNGEON.

Note that as in the case of BEER in the previous problem, a pizza is
defined as a THING that has the name PIZZA.

Although the code to create a troll is incomplete, we might envision
the following kind of interaction.   Suppose some poor soul JULIE is in
BLDG-10 when the hungry troll, GRENDEL, comes along:

@begin(programexample)
==> (julie 'current-position)
BLDG-10

==> (grendel 'move)
GRENDEL moved from EGG-ATRIUM to BLDG-10
GRENDEL says - Hssss--s! I'm going to eat you, JULIE!!
Aarrr--gh!
GRENDEL eats JULIE and belches.
GRENDEL moved from BLDG-10 to DUNGEON
()

==> (julie 'current-position)
HEAVEN
@end(programexample)
On the other hand if JULIE had been carrying a PIZZA, the incident above
would have had a happier ending:
@begin(programexample)
==> (julie 'current-position)
BLDG-10

==> (julie 'list-possessions)
PIZZA
()

==> (GRENDEL 'move)
GRENDEL moved from EGG-ATRIUM to BLDG-10
GRENDEL says - Hssss--s! I'm going to eat you, JULIE!!
JULIE says - Take this pizza instead, please!
GRENDEL says - OK, thanks!
GRENDEL moved from BLDG-10 to DUNGEON
()

==> (julie 'list-possessions)
()
@end(programexample)

An incomplete version of a procedure MAKE-TROLL is included in your
file.  Specifically, the procedure EAT-PERSON needs to be completed.
If the SELECTED-PERSON has a pizza among his or her possessions, then
the SELECTED-PERSON should lose the pizza (which should also be
removed from the list of objects at the current place). Otherwise, the
SELECTED-PERSON should be UNQUEUEd from the queue (which is the way
the CLOCK keeps track of who's alive in our world) and sent to HEAVEN.
In either case, the troll should then be removed from the current
place and reestablished in the DUNGEON with its hunger temporarily
satisfied by being reset to 0.  Along the way, add code to make the
TROLL and its victim engage in any dialogue you feel is appropriate.
Actually make a TROLL, whose name is GRENDEL, and install it in the
DUNGEON, with a HUNGER threshold of 3. Test your work by reloading
@a[ps7-mods.scm] and exercising it as above.  Turn in a listing
of your modifications, definitions and new procedures.


@paragraph(Problem 7)
As the code currently stands, the troll seems to have a distinct
advantage (rumors that the troll is a slightly demented former 6.001
instructor are apparently unfounded).  We can even things up a bit in
the following manner.  Using the procedures FORALL and DELETE, write a procedure called NEARBY, which takes a PLACE as an argument and returns a list 
of all other places in the world that can be reached in at most two steps
from the supplied argument.  Using NEARBY, modify the procedure EAT-PERSON so
that with probability 1 in 4, chanting magic spells in the presence of a troll
causes the selected victim to be magically transported to a nearby
place, selected at random from those specified by the procedure NEARBY.

In particular, implement the notion of "chanting magic spells" by modifying
MAKE-PERSON to support a new message, MAGIC, which causes the
appropriate things to happen.  Then include the necessary code in
EAT-PERSON needed to cause the MAGIC message to be passed to the selected
victim, thereby enabling him to escape the TROLL.
Turn in a listing of your modifications and new procedures.

@paragraph(Problem 8)
While the system we have developed so far provides a means for
simulating a Dungeons & Dragons type world, it is clearly still very
simplistic.  In particular, people in the world have a very limited
set of possible actions, mostly restricted to movement within the
world.  This is in part because THINGS in our world are very simple.
They are basically objects that can be possessed by people.  In this
problem,  you will design and implement a
modification to the system that increases the range of interactions
between objects in the system. 

In particular, you are going to create a new kind of THING that has
magical properties.  For instance, many Adventure games include rods,
staffs, and wands that have magical properties such as
teleportation.   You are to modify our game by defining a new
procedure, called MAKE-WAND, which creates a kind of THING with the
following additional properties.  Wands contain a certain number of
charges, which are expended when they are invoked, and which can be
regained under special circumstances.  Thus, MAKE-WAND will need to
have some way of preserving a local state variable detailing the
number of remaining charges in the wand, which we will define
initially to be 2 when the wand is created.

Remember from Problem 4 that
certain basic messages must be supported by WANDs, since they are a
kind of THING.  In addition, include code in MAKE-WAND to support
three additional messages.  The message CHARGES should cause the
wand to return the number of charges remaining.  The
message WAVE should do nothing if there are no charges left in the
wand or if no one is holding it.  Otherwise, it should reduce the number of charges left by 1,
then select a place at random (using the procedure NEARBY, which you
created in problem 7), and move the person wielding the wand to that
location.   You may find it useful to modify the procedure
MAKE-PERSON to support an additional message MOVE-TO that enables a
person to be moved to a specified location.  The message RECHARGE
should determine whether the wand is currently being held by someone and,
if so, whether the wielder is standing in the computer lab.  If both of
these conditions are true, then the number of charges in the wand
should be reset to 2, otherwise nothing should happen.  

Use the procedure MAKE-WAND to create a magic wand, and cause it to
appear in the COMPUTER-LAB.  Test out your code to make certain it
does what it is intended to.  Turn in a listing of your changes and
procedures. 

@paragraph(Problem 9)
Finally, there are many ways in which our world might become the scene for an 
interesting game. For example, add a new place SNACK-BAR to the set of places,
which one can get to from BLDG-10 by going EAST and from which one can
return to BLDG-36 by going WEST. (Due to a serious miscalculation by the
Admissions Office, MIT in our world 
has so many students that the Campus Patrol has
had to make some Institute corridors one-way.) Define things BEER and PIZZA
and cause them to APPEAR in the SNACK-BAR.  Also define a WAND, as in
Problem 8, and cause it to appear in the COMPUTER-LAB.  Modify the procedures
that make TROLLs and DEANs so that these creatures are added to the queue
that is MOVEd when CLOCK is invoked, and make a troll and a dean
as in problems 5 and 6.

Your goal is to get from the DORMITORY to the SNACK-BAR, pick up both BEER
and PIZZA, and get back to the DORMITORY for a party without losing your
possessions or being eaten by any trolls.  Do this without using the
message MOVE-TO, if you added such a message in problem 8.
You may stop at the computer lab first to get the magic wand, if you
wish.  Remember that in order to allow the other creatures in the
world to interact, you must alternate 
your moves with calls to CLOCK.   Turn in a listing
of your changes and definitions, and a "photo" copy (see the Scheme
Manual, p. 28) of one session of our game.
The difficulty of the
game can be altered by changing the HUNGER and OFFICIOUSNESS thresholds of the
TROLL and DEAN. Have fun!


As we noted at the beginning of the problems, many of them are
concerned with incremental changes to the procedures MAKE-PERSON,
MAKE-DEAN and MAKE-TROLL.  As a consequence, rather than turning in
several different versions of the same procedures, we suggest that
having finished all nine problems, you turn in one version of
each of the modified procedures, clearly marking all of your changes,
and indicating for each change, what problem the change was made in
response to.  Of course, remember to turn in any other things that
were specifically requested for individual problems.

@paragraph(Problem 10 -- Optional)

In problem 8, we introduced a modification to our system by creating
THINGS called WANDS that possessed certain unusual
properties.  This problem illustrated several important meta-level
aspects of message-passing systems.  In particular, it pointed out
several different issues about which one must worry when adding new
objects to the system, such as what extent procedures must be modified
to support the new objects, or what basic messages an object must
support, as well as general consistency issues between the new object
and previously created objects.

For this problem, design and implement another improvement to the
system, by adding either a new kind of PERSON or a new kind of
THING, with unusual properties.  Turn in a description (in English) of
the additions to the system, as well as listings of the procedures you
created and a sample of the program in action.

@b[CONTEST:] Prizes will be awarded for the cleverest programs turned
in for this exercise.


@newpage()
@begin(programexample)
@include(ps7-adv.SCM)
@end(programexample)
@newpage()
@begin(programexample)
@include(ps7-MODS.SCM)
@end(programexample)
