TEACH ADVENT_OBJECTCLASS Aaron Sloman and Luc Beaudoin Nov 1992 Updated Aaron Sloman Nov 1993 CONTENTS - (Use 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 (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. ------