TEACH ADVENT_OBJECTCLASS          Aaron Sloman and Luc Beaudoin Nov 1992
                                           Updated Aaron Sloman Nov 1993

         CONTENTS - (Use <ENTER> g to access required sections)

 -- INTRODUCTION
 -- Pre-requisites for this teach file
 -- Making LIB ADVENT_OBJECTCLASS available
 -- The adventure world
 -- -- Running the program
 -- -- A note on nomenclature
 -- -- Matching slot names and corresponding class names
 -- Things to do
 -- -- Introduce a "brave" subclass of players
 -- -- Give players an energy level, and introduce a Food class.
 -- -- Introduce nice and helpful players
 -- -- Make the program pause occasionally
 -- -- Make the strategies richer
 -- -- Allow the "user" at the terminal to be a player
 -- -- Allow several human players to interact with the system
 -- A possible student assignment
 -- Object oriented programming principles
 -- WARNING:

-- INTRODUCTION -------------------------------------------------------

This file describes LIB ADVENT_OBJECTCLASS -- a sample adventure game
implemented using object oriented programming techniques provided by
the Pop-11 Objectclass facilities. The library file gives only a
primitive skeleton for such a game. Various possible extensions are
outlined as exercises for the reader.

-- Pre-requisites for this teach file ---------------------------------

You should be familiar with all the Pop-11 constructs in
    TEACH * POPCORE

including the use of variable declarations, assignments, conditionals,
the matcher, procedure definitions, and the construction of lists
using "^", "^^" and "% ... %" inside list brackets.

You will need to be able to interrupt a looping program using CTRL C

It is assumed that you have read through TEACH * OBJECTCLASS_EXAMPLE
and understand the main concepts of Object Oriented
Programming explained there, especially
    a. the concept of a hierarchy of classes,
    b. the notion of a subclass inheriting features from
       its superclasses,
    c. the notion of a class having instances (objects) as
       well as subclasses, and
    d. the use of methods that behave differently for instances of
       different classes.
    e. the use of "slots" to store information relating to objects.


You may find it useful to read the first three sections of
TEACH * FLAVOURS (which introduce concepts of object-oriented
programming), and then  TEACH * INHERITANCE and TEACH * SLOTS.


-- Making LIB ADVENT_OBJECTCLASS available ----------------------------

First you need to ensure that the Objectclass library has been loaded.

Mark and load the following line to make the objectclass system and its
Teach, Help and Ref files available.

    uses objectclass

The demonstration program LIB * ADVENT_OBJECTCLASS.P makes available a
simulated "adventure world" using Object Oriented programming techniques
based on LIB OBJECTCLASS.

You can get the program into VED either by doing

    ENTER showlib advent_objectclass.p

or by putting the VED cursor on the asterisk below and typing ESC h
    LIB * ADVENT_OBJECTCLASS.P

Then you can rename it to be your own file, using the ENTER name
VED command. E.g. if you wish to call the file 'advent.p' do:

    ENTER name advent.p

This file has several class definitions, method definitions, and
definitions of a small number of utility procedures. There is a
plentiful supply of comments which should help to make clear what
is going on. You should not find it too difficult to extend the
classes and methods to make it more interesting.


-- The adventure world ------------------------------------------------

The adventure world contains different kinds of players (normal players,
vicious players, and greedy players) which act in a house made of rooms
which can be connected to each other in different directions (north,
south, east, and west).

Players have a degree of health, some goods, and a location. All of
these can vary.

The behaviour of the players is determined by methods applied to them.
E.g., greedy players tend to steal the goods of others, and vicious
players tend to hit others and thereby decrease their health. (These
special actions are defined in the STRATEGY methods.)

One way to get an idea of what the program does is to run it, and
then examine the printout produced, as described below.

-- -- Running the program

First load the program. If you have it in a VED file, go to the file and
do ENTER l1

Otherwise this should work:

    lib advent_objectclass

Make it run by marking and loading the following lines. Be prepared
to interrupt the procedure aoPlay using CTRL-C, or it will go on
indefinitely.

          vars ao_house = newAoHouse(); ;;; Creates a new house
          aoSetup(ao_house); ;;; Sets up the house, and lists players
          aoPlay(ao_house);   ;;; Starts the simulation.


Having seen the program work, you should look at the code and try to
understand it.

Warning: the program has bugs and limitations. It's a tutorial example
not a real adventure game. You should identify the bugs and try to fix
them. E.g. it does not handle dead players in such a way as to prevent
their being killed more than once!

-- -- A note on nomenclature

If you look at the library, you will notice that all of the method names
and slot names are prefixed by the two characters 'ao', and all the
class names by 'Ao'. This stands for AdventObjectclass. Using a unique
prefix is one way to prevent definitions in this library clashing with
others. (Another is to use sections, as described in HELP SECTIONS, but
that can be more complicated.)

You will also notice that many of the names include upper case letters
in the middle, e.g. the class names AoHouse, AoPhysicalObject, and
method and slot names aoEnters, aoStartloc.

This makes the code more legible, once you get used to the convention.
(Remember that Pop11 code is case sensitive.)

An alternative strategy would be to use underscores to separate parts of
long identifiers. This would make them longer than the mixed case names,
e.g. ao_house, ao_physical_object. Which method you use is a matter of
taste, as long as you take precautions (a) to reduce the risk of
identifiers from one package clashing with identifiers from another,
and (b) to make the code readable.

Note that the local variables in methods will not clash with local
variables used elsewhere, so they do not need to be unique. By
default they are all lexically scoped (a concept that is explained in
HELP LEXICAL and HELP LVARS)

-- -- Matching slot names and corresponding class names

The convention of using "Ao" for class names and "ao" for slot and
method names allows you to have slot names that are the same as class
names, except for differences in the case of the initial letter. This is
often convenient because you will often want to name a slot after the
kind of object it will "hold". (For instance, notice that the class
called "AoRoom" has a slot called "aoHouse", which corresponds to the
class called "AoHouse".

Some people would prefer instead to append "_of" to the slot-name, e.g.
The slot-name would be AoHouse_of, so that you could write

    AoHouse_of(thing) -> house;

instead of

    aoHouse(thing) -> house

Again, this is a matter of personal preference, as long as you use a
consistent and clear naming strategy.


-- Things to do -------------------------------------------------------

Look through the program and try to understand how it works. You may
find it useful to draw a diagram showing the class hierarchy, and
indicating which slots and which methods are associated with which
classes.

Try to extend the game by inventing new kinds of objects and adding new
methods. there are many ways in which the program can be extended.


-- -- Introduce a "brave" subclass of players

For example, you could introduce a new class of players called AoBrave,
who occasionally hit back when hit by an AoVicious player.

-- -- Give players an energy level, and introduce a Food class.

You could give each player an energy level which decreases every time
they move, pick up something, or hit something, and then introduce a new
kind of AoFood object which when eaten raises the energy level. Make the
players unable to move if their energy level gets too low.

-- -- Introduce nice and helpful players

Then you can introduce a new method which enables a nice agent to give
another one some food to help revive him/her.

-- -- Make the program pause occasionally

At present the program just runs on with players performing actions at
random till you interrupt or everyone dies.

You could make the program pause from time to time, e.g. if you define
the following procedure:

    define pause(message);
        ;;; Print out message (e.g. a string or list) then
        ;;; Pause till user presses return.
        lvars message;
        message =>
        ;;; call readline to make the program pause till the user
        ;;; types RETURN, but ignore the result produced.
        readline() ->;
    enddefine;

Note that the assignment to nothing just removes the result of readline
from the stack and discards it. If you just press return without typing
anything, the result of readline will just be the empty list [].

You could call this procedure just before "endfor" inside method aoPlay,
or in some other places.


-- -- Make the strategies richer

Players can be given richer strategies, and can build up their own
internal models of the world. Physical objects and rooms can exist in
various subclasses. Particular rooms and objects can have special
properties or can cause special events to take place.

E.g. some foods may not agree with some players.


-- -- Allow the "user" at the terminal to be a player

A version of the pause procedure described above, called something like
"get_user_move" could print out a message asking for a move, and
then use the result of readline to determine the move, which might
be something like

    [move north]
    [eat fish]
    [stand still]

or whatever.

A procedure something like pause could provide a mode of interaction
which allows you to type in a question asking for information about
the state of the house and its occupants, as well as giving
instructions.

Techniques for doing this sort of thing are illustrated in TEACH RESPOND
and TEACH RIVERCHAT.

A still more ambitious development would be to introduce a "natural
language" interface. This could use the techniques defined in
LIB * MSBLOCKS, described in TEACH * MSBLOCKS

Another exercise would be to convert LIB * MSBLOCKS to use objectclass.


-- -- Allow several human players to interact with the system

Design an objectclass called user_object, and allow as many instances
of it as there are to be "players". For each one the move method
would print out the name and then call the get_user_move procedure
to read in the move and take appropriate action.

If there are several players they should be able to ask each other
questions and give one another instructions. At present this will
have to be rather artificial because they will have to take it in
turns typing at the same keyboard.


-- A possible student assignment --------------------------------------

Choose some extension of LIB ADVENT_OBJECTCLASS, design it, implement
it, and document it.

When you have decided on the type of "adventure game" that you wish
to implement, read TEACH * PROPOSALS. Then write a short description of
your plans in the form described in that teach file, and show it to your
tutor for comment. When you have finally implemented the system, your
report (which could be based on TEACH * REPORTS modified as appropriate)
should include your proposal as an appendix, or as part of the report.
Decide which is more appropriate. Comment on aspects of the proposal
that you were unable to implement.

NB Make sure that your report has a section labelled

    How to run the program

Then give instructions and check (using a fellow student) that someone
who is not logged in as you can run it. This will require making sure
that your top level directory, and any relevant sub-directories, are not
protected against being read by other people.


-- Object oriented programming principles -----------------------------

In order to make this a good exercise in object-oriented programming,
try to keep to the following principles in mind.

1. Wherever possible, use the method syntax for defining procedures,
i.e.

    define :method <name>(obj1 :type1, obj2 :type2, obj3 :type3...)

so that it is clear to which objects the methods apply. Methods are
particularly useful when you want to have the same method name for
procedures that do slightly different things for different combinations
of types of objects. The alternative would be to write one big procedure
with a long multi-branch conditional statement testing for different
combinations of types of the arguments. Then whenever a new combination
was to be dealt with the procedure definition would need to be edited.

By allowing the code for different combinations to be in separate method
definitions, Objectclass allows you to keep code concerned with similar
types of objects in the same place, making some programs easier to
maintain and extend.

This is sometimes referred to as POLYMORPHISM: i.e. the fact that the
same method can have different definitions, applying to different types
of arguments (or types of arguments which are ordered differently). For
instance, notice that there are different definitions of the "aoEnters"
method. (Which definition of this method applies will depend on the
classes of the objects to which it is applied.)
    See TEACH * INHERITANCE

2. Take advantage of the ability to introduce hierarchical relations
between classes: create superclasses and subclasses. You can then define
slot names and methods for the superclasses that will be available for
all the subclasses, and can define special versions of those methods for
special subclasses. In this way code can be "re-used" between different
classes.

Also keep in mind that objectclass supports multiple inheritance: a
class can inherit from more than one class. Use this facility when it is
applicable. In particular the use of "mixins" can extend the
capabilities of a class with additional forms of behaviour specified by
extra methods and extra slots.

3. Write appropriate object initialisation instructions. Objectclass
supports several different types of initialisation of newly created
objects.

 o  Slot initialisation can be defined in two different ways when an
    objectclass is created using the DEFINE :CLASS syntax (See
    TEACH * SLOT_DEFAULTS).

 o  Wrappers can be used to define actions to be performed when
    specific sorts of events occur, such as construction of a new
    instance.

    See REF * OBJECTCLASS/Wrappers


4. It is sometimes useful to distinguish between private and non private
methods. The distinction is meant to prevent certain information from
being available outside of certain contexts.  In Smalltalk, for
instance, if a method, M, defined for a class, C, is private (to C) then
M can only be accessed by methods defined for C.  Privatisation of
methods for Objectclass is slightly different. Objectclass allows
lexical scoping to be used to ensure that certain methods and procedures
are "private" in the sense that they are accessible only to the other
methods and procedures defined in in the same file (or the same
compilation stream). In addition, the section mechanism of Pop-11,
supports other forms of "privacy".

    See HELP * OBJECTCLASS/'Private Methods'
        HELP * SECTIONS
        HELP * LEXICAL, * LVARS

6. A feature of object oriented programming is the encapsulation of
data. That is to say objects have information which is represented in a
manner that you don't need to know about in order to access it. That is
because methods are available to provide the means of access, and as
long as the methods are used as defined, users need not know whether the
internal represention of the data has been changed by the developers of
the program.

This feature is often touted as the major benefit of object oriented
programming. However anyone who has learnt to use a well structured
programming language in a disciplined way will find it familiar. It is
simply good programming practice to use "data abstraction" rather than
anything special to do with object oriented programming. However, some
people who have not been properly trained in good software engineering
techniques first encounter encapsulation when they meet an object
oriented language, and they then wrongly draw the conclusion that is
specific to OOP.


-- WARNING: -----------------------------------------------------------

In an exercise like this it is possible to go on adding new
features ad inifinitum. It is more important to produce a small
demonstration program and describe it well than to produce a huge system
and not have time to write it up.

--- $poplocal/local/teach/advent_objectclass
--- Copyright University of Birmingham 1995. All rights reserved. ------
