\input 6001mac

\begin{document}

\psetheader{Fall Semester, 1995}{Problem Set 6}

\medskip

\begin{flushleft}
Issued:  Tuesday, October 24, 1995 \\
\smallskip
Written solutions due: in recitation on Wednesday, November 1, 1995\\
\smallskip
Tutorial preparation for: week of October 30, 1995 \\
\smallskip
Reading: Section 3.1, 3.2 and 3.3 of the notes, plus attached code.
\smallskip
\end{flushleft}

The programming assignment for this week explores two ideas: the
simulation of a world in which objects are characterized by
collections of state variables, and the use of {\em object-oriented
programming} as a technique for modularizing worlds in which objects
interact.  These ideas are presented in the context of a simple
simulation game like the ones available on many computers.  Such games
have provided an interesting waste of time for many computer lovers.
In order not to waste too much of your own time, it is important to
study the system and plan your work before coming to the lab.

This problem set begins by describing the overall structure of the
simulation.  The tutorial exercises in part 2 will help you to master
the ideas involved.  Part 3 contains the lab assignment itself.

The overall object-oriented programming framework will be discussed in
lecture during the week of October 24.

\section{Part 1: The 6.001 Adventure Game}

The basic idea of simulation games is that the user plays a character
in an imaginary world inhabited by other characters. The user plays
the game by issuing commands to the computer that have the effect of
moving the character about and performing acts in the imaginary world,
such as picking up objects.  The computer simulates the legal moves
and rejects illegal ones.  For example, it is illegal to move between
places that are not connected (unless you have special powers).  If a
move is legal, the computer updates its model of the world and allows
the next move to be considered.

Our game takes place in a strange, imaginary world called MIT, with
imaginary places such as a computer lab, Building 36, and Tech Square.
In order to get going, we need to establish the structure of this
imaginary world: the objects that exist and the ways in which they
relate to each other.

Initially, there are three procedures for creating objects:

\begin{lisp}
  (make-thing  name)
  (make-place  name)
  (make-person name birthplace restlessness)
\end{lisp}

In addition, there are procedures that make people and things and
procedures that install them in the simulated world.  The reason that
we need to be able to create people and things separately from
installing them will be discussed in one of the exercises later.  For
now, we note the existence of the procedures

\begin{lisp}
  (make\&install-thing  name birthplace)
  (make\&install-person name birthplace restlessness)
\end{lisp}

Each time we make or make and install a person or a thing, we give it
a name.  People and things also are created at some initial place.  In
addition, a person has a restlessness factor that determines how often
the person moves. For example, the procedure {\cf
make\&install-person} may be used to create the two imaginary
characters, {\cf eric} and {\cf ta}, and put them in their
places, as it were.

\begin{lisp}
  (define eric-office (make-place 'eric-office))
  (define ta-office  (make-place 'ta-office))
\null
  (define eric (make\&install-person 'eric eric-office 3))
  (define ta  (make\&install-person 'ta  ta-office  2))
\end{lisp}

All objects in the system are implemented as message-accepting
procedures, as described in lecture on October 26.

Once you load the system in the laboratory, you will be able to
control {\cf eric} and {\cf ta} by sending them appropriate messages.
As you enter each command, the computer reports what happens and where
it is happening. For instance, imagine we had interconnected a few
places so that the following scenario is feasible:

\begin{lisp}
(ask eric 'look-around)
At eric-office : eric says -- I see nothing 
;Value: \#f
\null
(ask (ask eric 'place) 'exits)
;Value: (west down)
\null
(ask eric 'go 'down)
eric moves from eric-office to tech-square 
;Value: \#t
\null
(ask eric 'go 'south)
eric moves from tech-square to building-36 
;Value: \#t
\null
(ask eric 'go 'up)
eric moves from building-36 to computer-lab 
;Value: \#t
\null
(ask ta 'look-around)
at ta-office : ta says -- I see nothing 
;Value: \#f
\null
(ask (ask ta 'place) 'exits)
;Value: (down)
\end{lisp}

\begin{lisp}
(ask ta 'go 'down)
ta moves from ta-office to eric-office
;Value: \#t
\null
(ask ta 'go 'down)
ta moves from eric-office to tech-square
;Value: \#t
\null
(ask ta 'go 'south)
ta moves from tech-square to building-36 
;Value: \#t
\end{lisp}

\begin{lisp}
(ask ta 'go 'up)
ta moves from building-36 to computer-lab 
At computer-lab : ta says -- hi eric 
;Value: \#t
\end{lisp}

In principle, you could run the system by issuing specific commands to
each of the creatures in the world, but this defeats the intent of the
game since that would give you explicit control over all the
characters.  Instead, we will structure our system so that any
character can be manipulated automatically in some fashion by the
computer.  We do this by creating a list of all the characters to be
moved by the computer and by simulating the passage of time by a
special procedure, {\cf clock}, that sends a {\cf move} message to
each creature in the list.  A {\cf move} message does not
automatically imply that the creature receiving it will perform an
action.  Rather, like all of us, a creature hangs about idly until he
or she (or it) gets bored enough to do something.  To account for
this, the third argument to {\cf make-person} specifies the average number of
clock intervals that the person will wait before doing something (the
restlessness factor).

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 {\cf computer-manual} and place it in the {\cf
computer-lab} (where {\cf eric} and {\cf ta} now are).

\begin{lisp}
(define computer-manual (make\&install-thing 'computer-manual computer-lab))
\end{lisp}

Next, we'll have {\cf eric} look around.  He sees the manual and {\cf
ta}.  The manual looks useful, so we have {\cf eric} take it and leave.

\begin{lisp}
(ask eric 'look-around)
At computer-lab : eric says -- I see computer-manual ta 
;Value: (computer-manual ta)
\null
(ask eric 'take computer-manual)
At computer-lab : eric says -- I take computer-manual 
;Value: \#t
\null
(ask eric 'go 'down)
eric moves from computer-lab to building-36 
;Value: \#t
\end{lisp}

{\cf Ta} had also noticed the manual; he follows {\cf eric} and
snatches the manual away.  Angrily, {\cf eric} sulks off to the
EGG-Atrium:

\begin{lisp}
(ask ta 'go 'down)
ta moves from computer-lab to building-36 
At building-36 : ta says -- Hi eric 
;Value: \#t
\null
(ask ta 'take computer-manual)
At building-36 : eric says -- I lose computer-manual 
At building-36 : eric says -- yaaaah! I am upset! 
At building-36 : ta says -- I take computer-manual 
;Value: \#t
\null
(ask eric 'go 'west)
eric moves from building-36 to egg-atrium
;Value: \#t
\end{lisp}
 
Unfortunately for {\cf eric}, beneath the EGG-Atrium is an inaccessible
dungeon, inhabited by a troll named {\cf grendel}.\footnote{Rumors
that Grendel is a former MIT associate dean of student affairs
are wholly unfounded!}  A troll is a
kind of person; it can move around, take 
things, and so on.  When a troll gets a {\cf  move} message from the clock,
it acts just like an ordinary person---unless someone else is in the
room.  When {\cf grendel} decides to {\cf act}, it's game over for {\cf eric}:

\begin{lisp}
(ask grendel 'move)
grendel moves from dungeon to egg-atrium 
At egg-atrium : grendel says -- Hi eric
;Value: \#t
\end{lisp} 

After a few more moves, {\cf grendel} acts again:

\begin{lisp}
(ask grendel 'move)
At egg-atrium : grendel says -- Growl.... I'm going to eat you, eric 
At egg-atrium : eric says -- 
                   Dulce et decorum est 
                   pro computatore mori! 
eric moves from egg-atrium to heaven 
At egg-atrium : grendel says -- Chomp chomp. eric tastes yummy! 
;Value: *burp*
\end{lisp}

\paragraph{Implementation}

The simulator for the world is contained in two files, which are
attached to the end of the problem set. The first file, {\cf
game.scm}, contains the basic object system, procedures to create
people, places, things and trolls, together with various other useful
procedures.  The second file, {\cf world.scm}, contains code that
initializes our particular imaginary world and installs {\cf eric},
{\cf ta}, and {\cf grendel}.

\section{Part 2: Tutorial exercises}

\paragraph{Tutorial exercise 1:}

(a) Define a procedure {\cf flip} (with no parameters) that returns 1
the first time it is called, 0 the second time it is called, 1 the
third time, 0 the fourth time, and so on.  (b) Define a procedure {\cf
make-flip} that can be used to generate {\cf flip} procedures.  That
is, we should be able to write {\cf (define flip (make-flip))}.  (c)
Draw an environment diagram to illustrate the result of evaluating the
following sequence of expressions:

\begin{lisp}
(define (make-flip) \ldots{})
(define flip1 (make-flip))
(define flip2 (make-flip))
\null
(flip1) --> {\em value?}
(flip2) --> {\em value?}
\end{lisp}

\paragraph{Tutorial exercise 2:}

Assume that the following definitions are evaluated, using
the procedure {\tt make-flip} from the previous exercise:

\begin{lisp}
(define flip (make-flip))
(define flap1 (flip))
(define (flap2) (flip))
(define flap3 flip)
(define (flap4) flip)
\end{lisp}

\noindent What is the value of each of the following expressions (evaluated
in the order shown)?

\begin{lisp}
flap1
\null
flap2
\null
flap3
\null
flap4
\null
(flap1)
\null
(flap2)
\null
(flap3)
\null
(flap4)
\null
flap1
\null
(flap3)
\null
(flap2)
\end{lisp}

\paragraph{Tutorial exercise 3:} Draw a simple inheritance diagram
showing all the kinds of objects (classes) defined in the adventure
game system, the inheritance relations between them, and the methods
defined for each class.

\paragraph{Tutorial exercise 4:} Draw a simple map showing all the
places created by evaluating {\cf world.scm}, and how they
interconnect.  You will probably find this map useful in dealing with
the rest of the problem set.

\paragraph{Tutorial exercise 5:} Suppose we evaluate the following
expressions:

\begin{lisp}
(define ice-cream (make-thing 'ice-cream dormitory))
(ask ice-cream 'set-owner ta)
\end{lisp}

\noindent
At some point in the evaluation of the second expression, the expression

\begin{lisp}
(set! owner new-owner)
\end{lisp}

\noindent 
will be evaluated in some environment.  Draw an environment
diagram, showing the full structure of {\cf ice-cream} at the point where
this expression is evaluated.  Don't show the details of {\cf ta}
or {\cf dormitory}---just assume that {\cf ta} and {\cf dormitory}
are names defined in the global environment that point off to some
objects that you draw as blobs.

\paragraph{Tutorial exercise 6:} Suppose that, in addition to {\cf
ice-cream} in exercise  5, we define

\begin{lisp}
(define tosci-rum-and-raisin (make-named-object 'ice-cream))
\end{lisp}

\noindent

Are {\cf ice-cream} and {\cf tosci-rum-and-raisin} the same object
(i.e., are they {\cf eq?})?  If {\cf ta} wanders to a place where
they both are and looks around, what message will he print?


\section{Part 3: Lab exercises}

The first exercise here should be written up and turned in at
recitation, but we suggest that you do it {\em before} coming to the
lab, because it illustrates a bug that is easy to fall into when
working with the adventure game.

\paragraph{(Pre-)Lab exercise 1:}

Note how {\cf install} is implemented as a method defined as part of
both {\cf mobile-object} and {\cf person}. Notice that the {\cf
person} version puts the person on the clock list (this makes them
``animated'') then invokes the {\cf mobile-object} version on {\cf
self}, which makes the {\cf birthplace} where {\cf self} is being
installed aware that {\cf self} thinks it is in that place. That is,
it makes the {\cf self} and {\cf birthplace} consistent in their
belief of where {\cf self} is. The relevant details of this situation
are outlined in the code excerpts below:

\begin{lisp}
(define (make-person name birthplace threshold)
  (let ((mobile-obj (make-mobile-object name birthplace))
        \vdots)
    (lambda (message)
      (cond \ldots
            \vdots
            ((eq? message 'install)
             (lambda (self)
               (add-to-clock-list self)
               ((get-method mobile-obj 'install) self) ))   ; **
            \vdots))))
\null
(define (make-mobile-object name place)
  (let ((named-obj (make-named-object name)))
    (lambda (message)
      (cond \ldots
            \vdots
            ((eq? message 'install)
             (lambda (self)
               (ask place 'add-thing self)))
            \vdots))))
\end{lisp}
      
Louis Reasoner suggests that it would be simpler if we change the
last line of the {\cf make-person} version of the {\cf install} method to read:

\begin{lisp}
               (ask mobile-obj 'install) ))   ; **
\end{lisp}

Alyssa~P.\ Hacker points out that this would be a bug.  ``If you did
that,'' she says, ``then when you {\cf make\&install-person} {\cf ta}
and {\cf ta} moves to a new place, he'll thereafter be in two places
at once!  The new place will claim that {\cf ta} is there, and {\cf
ta}'s place of birth will also claim that {\cf ta} is there.''

What does Alyssa mean?  Specifically, what goes wrong? You will likely
need to draw an appropriate environment diagram to explain carefully.

\subsection{In the lab}

When you load the code for problem set 6, the system will load {\cf
game.scm}.  We do not expect you to have to make significant
changes in this code, though you may do so if you want to.

The system will also set up a buffer with {\cf world.scm} and
load it into {\sc Scheme}.  Since the simulation model works by data
mutation, it is possible to get your {\sc Scheme}-simulated world into
an inconsistent state while debugging.  To help you avoid this
problem, we suggest the following discipline: any procedures you
change or define should be placed in your answer file; any new
characters or objects you make and install should be added to {\cf
world.scm}.  This way whenever you change some procedure you can make
sure your world reflects these changes by simply re-evaluating the
entire {\cf world.scm} file.  Finally, to save you from retyping the
same scenarios repeatedly---for example, when debugging you may want
to create a new character, move it to some interesting place, then ask
it to act---we suggest you define little test ``script'' procedures at
the end of {\cf world.scm} which you can invoke to act out the
scenarios when testing your code.  See the comments in {\cf world.scm}
for details.

\paragraph{Lab exercise 2:}

After loading the system, make {\cf eric} and {\cf ta} move around by
repeatedly calling {\cf clock} (with no arguments).  (a) Which person is
more restless?  (b) How often do both of them move at the same time?

\paragraph{Lab exercise 3:}

Make and install a new character, yourself, with a high enough
threshold (say, 100) so that you have ``free will'' and are not likely
to be moved by the clock.  Place yourself initially in the {\cf
dormitory}.  Also make and install a thing called {\cf late-homework},
so that it starts in the {\cf dormitory}.  Pick up the {\cf
late-homework}, find out where {\cf eric} is, go there, and try to
get {\cf eric} to take the homework even though he is notoriously
adamant in his stand against accepting tardy problem sets.  Can you
find a way to do this that does not leave {\em you} upset?  Turn in a
list of your definitions and actions.  If you wish, you can
intersperse your moves with calls to the clock to make things more
interesting.  (Watch out for {\cf grendel}!)


\paragraph{Lab exercise 4: Meta-adventure}

You can inspect an environment structure using the {\cf show}
procedure from {\cf game.scm}.  {\cf Show} is a bit like the {\cf pp}
procedure you should have used in problem set 1 for printing out
procedures, but it prints things out so that they look more like parts
of an environment diagram.  It can be used like this:

\begin{lisp}
(show ta)
\#[compound-procedure 48]
Frame:
  \#[environment 49]
Body:
  (lambda (message)
    (cond ((eq? message 'person?) (lambda ... true))
          ((eq? message 'possessions) (lambda ... possessions))
          ((eq? message 'list-possessions) (lambda ... ... possessions))
          ...))
\null
\end{lisp}

\noindent Now you can inspect the environment of the procedure by
calling {\cf show} with the `hash number' of the environment.  The
hash number is the number after `{\cf compound-procedure}' or `{\cf
environment}' in the usual printed representations of these objects.
The system guarantees that all different (i.e.\ non-{\cf eq?}) objects
have different hash numbers so you can tell if you get back to the
same place.

\begin{lisp}
(show 49)
\#[environment 49]
Parent frame: \#[environment 50]
possessions:  ()
mobile-obj:   \#[compound-procedure 52]
\null
\end{lisp}

This exercise is called meta-adventure because you are going to use
the {\cf show} procedure to explore and `map' the environment
structure for {\cf eric} and produce an environment diagram.

Start with {\cf eric} and follow all the hash numbers {\em except}
those associated with direction names.  There should be between 10 and
20 things to show.  Print out the results and cut out the individual
results.  Arrange the pieces on a large blank piece of paper so that
they are in the correct positions to make an environment diagram.
Glue the pieces in place and draw in the arrows to make a complete
environment diagram.  Turn in your diagram.

{\bf Warning:}  The environment in this game can get very large in a
hurry.  Thus we strongly suggest that you start with a clean Scheme
system, and just load {\tt game.scm} and {\tt world.scm}, then answer
this question.


\subsection{Student Disservice Cards}

The MIT Office against Student Affairs has asked us for help in
expanding the features offered by the MIT ``Student Disservice Card''
system.  Luckily, our object-oriented simulation is just what's needed
for trying out new ideas.

To model a student disservice card, we can make a new kind of object,
called an {\cf sd-card}, which is a special kind of thing.  Besides
inheriting the standard properties of a thing, each sd-card has some
local state: an {\cf id}, which identifies the person to whom the card
was issued.  An sd-card supports a message {\cf sd-card?}, indicating
that it is an sd-card.  The card also accepts message that returns the
{\cf id}.

The procedure {\cf make\&install-sd-card} (shown below) can be used to
make a card and install it.  It uses the procedure {\cf make-sd-card}
to actually create the card.  Note that both procedures take a name,
an initial place and an id (which should be a symbol).

\begin{lisp}
\null
(define (make\&install-sd-card name birthplace id)
  (let ((card (make-sd-card name birthplace id)))
    (ask card 'install)
    card))
\null
(define (make-sd-card name birthplace idnumber)
  (let ((id idnumber)
        (thing (make-thing name birthplace))
        (value 100))
    (lambda (message)
      (cond ((eq? message 'sd-card?) (lambda (self) true))
            ((eq? message 'id) (lambda (self) id))
            ((eq? message 'current-value) (lambda (self) value))
            ((eq? message 'buy)
             ; be sure there is a vending machine and that the card is in it
             (lambda (self)
               (let ((machines (filter (lambda (p) (is-a p 'vending?))
                                       (ask (ask self 'place) 'things))))
                 (map (lambda (p) (cond ((ask p 'card-inside?)
                                         (set! value (- value 1))
                                         (ask p 'dispense))))
                      machines))))
            (else (get-method thing message))))))
\null
\end{lisp}

Note the presence of the {\cf sd-card?} method, which identifies the
object as an sd-card.  In general, our system is structured so that a
recognizable {\cf foo} must have a {\cf foo?} method that answers {\cf
true}.  Objects that aren't {\cf foo}s don't have a {\cf foo?} method.
We've supplied a procedure called {\cf is-a} that can be used to test
whether an object is of some particular type.  {\cf Is-a} works like
{\cf ask} except that if the message doesn't correspond to a method it
returns {\cf false} rather than causing an error.  For example, you
can test whether an object is an sd-card by evaluating {\cf (is-a
object 'sd-card?)}.

\paragraph{Lab exercise 5:}
Modify the code for {\cf make-sd-card} so that it also accepts a
message {\tt current-value} and returns information  indicating the
current value of the card.  Create a card and demonstrate that your
addition works correctly.

Turn in a listing of your new definition and a transcript of your
demonstration.

\vskip 30pt

We will also create a new kind of object, called a {\cf
vending-machine}, which is a special kind of thing.  Besides
inheriting the standard properties of things, each vending-machine
also has some local state,  and some methods for accepting and
ejecting Student Disservice cards.

\begin{lisp}
(define (make-vending-machine name birthplace type)
  (let ((thing (make-thing name birthplace))
        (inserted-card '())
        (card-owner '())
        (contents 10))
    (lambda (message)
      (cond ((eq? message 'vending?) (lambda (self) true))
            ((eq? message 'accept-card)
             (lambda (self card)
               (cond ((and (let ((things-at-place (ask (ask self 'place) 'things)))
                             (memq card things-at-place))
                           (is-a card 'sd-card?))
                      (cond ((ask card 'owned?)
                             (set! card-owner (ask card 'owner))
                             (ask card-owner 'lose card)
                             (ask card 'set-owner self)
                             (set! inserted-card card)
                             true)
                            (else
                             (display-message (list "you cannot insert a card you don't own"))
                             false))))))
            ((eq? message 'eject-card)
             (lambda (self)
               (ask inserted-card 'set-owner 'nobody)
               ;; need to remove card from cards
               (set! inserted-card '())
               true))
            ((eq? message 'card-inside?)
             (lambda (self)
               (if inserted-card true false)))
            ((eq? message 'dispense)
             (lambda (self)
               (let ((thing (make\&install-thing type (ask self 'place))))
                 (set! contents (- contents 1))
                 (ask card-owner 'take thing))))
            ((eq? message 'type)
             (lambda (self) type))
            (else (get-method thing message))))))
\null
(define (make\&install-vending-machine name birthplace type)
  (let ((machine (make-vending-machine name birthplace type)))
    (ask machine 'install)
    machine))
\end{lisp}

Note that the argument {\cf type} here is used to refer to the type of
thing that the machine holds (e.g.\ a coke machine should have the
type {\tt coke}), {\cf contents} is used to indicate the
number of units of that type of thing still inside the machine, and
{\cf inserted-card} and {\cf card-owner} are internal state variables
used to indicate the status of the machine.

\paragraph{Lab exercise 6:}
Make and install some vending machines in different locations in the
world.  Demonstrate what you must do in order to buy something from
the machine.

Turn in a transcript of the expressions you evaluated to accomplish this.

\paragraph{Lab exercise 7:}
We obviously don't want the vending machines to be depleted.  Create a
new class of  person, a {\cf vendor-man}, with the following behavior.
Each vendor specializes in a particular type of thing (e.g. {\cf coke}).
When asked to act, this person should pick a random direction in which
to move, and do so.  If there is a machine of the corresponding type
in that place, the vendor should fill the machine by adding an
additional 10 units to the contents of the machine.  To do this, you
many need to add a new method to the code that creates vending
machines.

Turn in a listing of your procedure(s).  To demonstrate that your
implementation works, create two different types of vending machines
and two corresponding vendors.  Have the vendors move until they find
and fill their machines.  You may want to add a new method to the
vending machine that will allow it to display the number of units
inside, so that you can demonstrate your filling operation was successful.

\paragraph{Lab exercise 8:}

The Director of Housing's office has decided that students are not getting enough
good food because they are overloading on junk food.  To put a curb on
such ``nutritionally challenged'' behavior, they decide to take
drastic action.  Create a new kind of person called a {\cf food-demon},
which is like a troll but only eats people who are carrying a
particular type of junk food.  You can use {\cf grendel} as an
example of a being that does special things when asked to act.  To
make the food-demons especially effective they should have a low
restlessness factor.

Write a procedure {\cf (unleash-demon type)} which creates and
dispatches a new food-demon to hunt down possessors of a particular
type of food.
Naturally, the demon should start its hunt from the dungeon.
Turn in a listing of your code with a demonstration that it works.

\paragraph{Lab exercise 9:}

The Director of Housing is still not happy with the overuse of junk
food, and has to monitor the use of cards.  If a card is used to buy
junk food, he wants to know about it.

Implement a new object, {\cf big-brother}, which accepts a message
{\cf inform\ } which takes a vending machine as argument.  {\cf Big-brother}
should monitor all the activity in vending machines, and unleash a new
demon whenever a particular type of vending machine is used for the
first time.  You may need to modify some of the existing code to
accomplish this.

Turn in a listing of your new and modified code, with a transcript
showing it in action.

Note that there are several ways to accomplish this. One is to have
vending machines inform big brother when they are installed, a second
would be to have the machines inform big brother whenever a card is inserted.

\paragraph{Lab exercise 10:}

Now you have the elements of a simple game that you play by
interspersing your own moves with calls to the clock.  Your goal is to
leave your residence, get as many different types of junk food as you
can, and return, without being eaten.  Note that you can use the
procedure {\tt run-clock} to run the game for any chosen number of steps.

To make the game more interesting, you should also create some
student(s) besides yourself and set up the student {\cf act} method so
that a student will try to move around campus, collecting food and
other interesting things that they find and occasionally leaving some
of their possessions behind when they move on.

Turn in your new student {\cf act} method and a demonstration that it
works.

\paragraph{Lab exercise 11:}

Design and implement some new student behaviors. Turn in a description
(in English) of your ideas, the code you wrote to implement them, and
a demonstration scenario.

{\em This problem is not meant to be a major project.  Don't feel that
you have to do something elaborate.}

\subsection{Contest}

Prizes will be awarded for the cleverest ideas turned in for this
problem set.

\bigskip

\paragraph{(Post-)Lab exercise 11:} (Humanities extra credit.)
When our characters go to heaven, they make a brief proclamation.
Who is the source of these (misquoted) last words, what is the actual
quotation, and what is the English translation?

\end{document}
