Programming Project 10

advertisement
CSE 231
Spring 2011
Programming Project 10
This assignment is worth 80 points (8.0% of the course grade) and must be completed and turned in
before 11:59 on Monday April 25, 2011.
Assignment Overview
This assignment will give you more experience with writing your own classes, as well as exception
handling.
You will write four classes that implement a simple text adventure game.
Background
Text adventure games have a long, storied history in computer science and were some of the first
computer games. They interface with the player using only text, describing locations and objects and
allowing the user to type a set of commands to interact with the game. The earliest text adventure
games were often written by students or programmers in their spare time, and generally featured
fantasy adventures full of puzzles and clever responses from the computer.
Project Description / Specification
You, on the other hand, will write a very simple text adventure game for credit. As designed, it
contains no puzzles, and your program’s responses are not required to be clever.
Your program must consist of four classes: TextAdventure, Room, Character, and an
Exception subclass. You must also have a main() function designed to run the game.
Character is a fairly simple class. A character knows the id of the room it is currently in, and has a
list of its inventory. It contains these methods:
__init__(self, inventory_list, room_id): This method initializes the
character with a room id and an inventory list. By default the inventory list is empty, and the room id
is -1.
You also need a method to return the character’s inventory as a string. You may choose to
implement this either as the special __str__() method or as a normal method with some other
name, but some such method is required. Don’t just print the inventory as a Python list.
Room is the class that represents a single room. Associated with each room is a unique id and an
adjective which describes it. It may also have one or more exits – links to other rooms – and one or
more items. It contains these methods:
__init__(self, text_desc): This method initializes the room from a text string which
describes it. The string contains, in order, the integer id of the room, the adjective that describes the
room, and a mix of strings which may describe exits or items in the room. Exit strings are always of
the form <capital letter><number>, where the capital letter gives the direction of the exit and the
number gives the id of the adjoining room. For example, the string ‘S13’ indicates that there is an exit
to the south and that it leads to a room with id 13. (Any string that is not an exit is an item; exits
always start with N, S, E, or W, and items are never capitalized.) See the provided .txt files for
example strings, and be sure to check the Notes and Hints section below for some advice on how to
store all this information. The default value of text_desc is “0 bare”.
You also need a method to return a description of the room as a string. You may choose to
implement this either as the special __str__() method or as a normal method with some other
name, but some such method is required. The description should include the room’s adjective, tell the
user about the direction of any exits, and list any items in the room. You are not required to exactly
match the grammatically-correct output in the examples; output like “You see 1 doors to the west.” is
okay. However, you must print sentences rather than just printing Python lists.
TextAdventure is the class that governs the game itself. It is responsible for interactions between
the user, the character, and the rooms. It has these methods:
__init__(self, filename): This method creates a default Character and reads a
file to create a set of Rooms. The character starts the game with nothing in the inventory and in the
room with the lowest id number.
prompt(self): This method prompts the user for a command, processes the command
(usually using one of the other TextAdventure methods below), and either carries it out (if it’s
valid) or prints an error message. No re-prompting for invalid commands is necessary. Here are the
valid commands:
L or look - print a description of the room you are in
I or inventory - print your inventory
P blah or pickup blah - pick up the item called blah
D blah or drop blah - drop the item called blah
N or north - go north
S or south - go south
E or east - go east
W or west - go west
Q or quit - quit
H or help - print this list of commands
Whenever the user moves (or tries to move), you should print the description of the current
room after the move is complete.
User input is notoriously evil. However, your program must be immune to such affronts.
Moreover, you must make use of Python’s Exception feature to make it so. When the user attempts
an invalid move (picking up something that doesn't exist, ...), your helper functions move, pickup,
and drop must raise an exception, and pass a message to be displayed that describes the error. The
prompt function will need to catch these exceptions and display the error message. You may also find
it useful to guard your command parsing code. Sometimes the user is forgetful and may not include all
the required arguments.
look(self): This method prints the description of the current room, using the method you
wrote for Room.
inventory(self): This method prints the character’s inventory, using the method you
wrote for Character.
pickup(self, item): This method coordinates the character with its current room to
remove the item from the room and add it to the character’s inventory. If the item is not present in the
room, it must not be added to the character’s inventory, and an exception must be raised. Either way, a
message must print.
drop(self, item): This method coordinates the character with its current room to remove
the item from the character’s inventory and add it to the room. If the item is not present in the
character’s inventory, it must not be added to the room, and an exception must be raised. Either way, a
message must print.
move(self, direction): This method moves the character in the specified direction if
the current room has an exit in that direction. If not, the move fails, and an exception must be raised.
Either way, a message must print.
help(self): This method prints a list of the valid commands.
Exception Subclass
The fourth class must be a subclass of the built-in Exception class. This new exception class indicates
an invalid game action. Creating your own exception class allows you to differentiate it from other
exceptions that could occur so you can handle it appropriately. (It also lets you specify information
that needs to be tracked with a particular error, e.g., a string that describes what illegal action the user
attempted to perform or a response to it. These Exception classes look and feel like your typical class.
They can contain a constructor, a string method, etc. They should be derived from the Exception class,
instead of the Object class. Additionally, to create one you issue a raise command.
For example, to create a new exception class, you would define it as follows.
class CustomError(Exception):
<class code>
When you wish to raise the error, you issue either of the following:
raise CustomError
raise CustomError, arg
The latter form is used to pass a single argument to the except block that handles the exception.
Remember, program execution will immediately jump to the closest enclosing try-except block
that defined an except for that error. The program will not return to the line that raised the exception
after handling has finished.
NOTE: You may include more methods than those described above in any class, but the methods
described must be present.
main(): This simple function runs the game. It prompts the user for a file name, and then uses that
file to create a TextAdventure. It then prints a short introductory message (including a list of
commands) and uses the TextAdventure’s prompt() method until the user quits. You do not
need to do error checking on the format of the input file, but if the user enters a bad file name, you
should recover and prompt the user for a good one (a file that can be opened for reading).
There should be nothing in your code outside of your classes and functions except a single call to
main(). Specifically, do not use global variables.
Each class, method, and function (including main()) must have a docstring. See the course coding
standards for more about docstrings.
Deliverables
Turn in proj10.py using the handin program.
Save a copy to your H drive.
Downloadables:
Sample .txt files: oneroom.txt, oneroomstuff.txt, tworooms.txt, textadventure.txt
Output examples: errors.txt, moves.txt, items.txt
Notes and Hints:
1. For big projects like this, frequent testing is an excellent idea. For example, you can write and
test the Character class without any of the other classes. You can also write and test the Room
class alone. Even the TextAdventure class can be broken up into pieces; write and test the
various command methods separately, then incorporate them into the prompt() method.
2. We have provided several different .txt documents describing various adventures. You should
test your code with each, from the most simple to the most complex. Don’t hardcode a
particular file name – your TA may also test with multiple different adventures.
3. You may find it helpful to write a few extra methods for Room and Character dealing with the
pickup and drop commands. For each class, add_item(self, item) and remove_item(self, item)
methods can be written very simply. For example, add_item(self, item) for the Character class
can simply add the item, not checking to see if it actually exists. The relevant TextAdventure
method (e.g., pickup()) handles the coordination, only calling add_item() for the Character if it
can also call remove_item() for the current Room.
4. Room ids are designed to allow the TextAdventure class to keep track of rooms – so use a
dictionary there with room ids as the keys and Rooms as the values. Room ids never overlap,
so there’s no need to worry about that.
5. Rooms don’t know what other rooms they link to, only the ids of those rooms. So it is the
responsibility of the TextAdventure class to do all id-to-Room translations, and hence to update
the Character’s current room id.
6. The TextAdventure class doesn’t really need to do much parsing of the file it reads – just create
a new Room from each non-blank line in the file by passing that line in to Room().
7. When creating a Room from a text string, the first word is the id and the second is the
adjective. After that, exits and items may come in any order. Design a loop to go through
these remaining strings, and remember exits start with N, S, E, or W, and items are never
capitalized. When you see an exit, you’ll need to associate the correct direction with the id
number of the linked room. A dictionary with directions as keys and ids as values is a good
idea here. Items are simple strings, and it’s probably best to store them in a list.
8. For the purpose of TextAdventure’s move() method, you may find it helpful to write a function
in Room which, given a direction, returns either the id of the attached room in that direction or
False, if there is no exit in that direction.
9. General advice: Start early. Save often, and submit to handin whenever you have a working
project, even if it’s not finished. Read over the Project Description carefully and double-check
you have met all the requirements. Don’t forget your docstrings.
Following is a sample interaction with our solution:
>>> ============================ RESTART ======================
>>>
Enter a text adventure filename:
Cannot open file:
Enter a text adventure filename: textadventure.txt
Welcome to this Generic Text Adventure!
You may explore and collect any items you find.
There's no winning, just exploration.
Valid commands are:
L or look - print a description of the room you are in
I or inventory - print your inventory
P blah or pickup blah - pick up the item called blah
D blah or drop blah - drop the item called blah
N or north - go north
S or south - go south
E or east - go east
W or west - go west
Q or quit - quit
H or help - print this list of commands
Capitalization doesn't matter.
You see a simple room. It has one exit, to the north.
Enter a command (H for help): l
You see a simple room. It has one exit, to the north.
Enter a command (H for help): i
Alas, your inventory is empty.
Enter a command (H for help): n
You move into the room to the north.
You see a leafy room. It contains a flower.
the west, east, and south.
Enter a command (H for help): p flower
It has exits to
You pick up the flower.
Enter a command (H for help): i
Your inventory contains these items:
- flower
Enter a command (H for help): h
Valid commands are:
L or look - print a description of the room you are in
I or inventory - print your inventory
P blah or pickup blah - pick up the item called blah
D
N
S
E
W
Q
H
blah or drop blah - drop the item called blah
or north - go north
or south - go south
or east - go east
or west - go west
or quit - quit
or help - print this list of commands
Capitalization doesn't matter.
Enter a command (H for help): l
You see a leafy room. It has exits to the west, east, and
south.
Enter a command (H for help): p flower
You attempt to pick up a flower, but cannot.
no such item to pick up.
Enter a command (H for help): l
Perhaps there is
You see a leafy room. It has exits to the west, east, and
south.
Enter a command (H for help): w
You move into the room to the west.
You see a dark room. Scattered about are a diamond and a
lantern. It has exits to the east and north.
Enter a command (H for help): d lamp
You attempt to drop the lamp, but discover you don't have one
to drop. Oh well.
Enter a command (H for help): d flower
You drop the flower.
Enter a command (H for help): p diamond
You pick up the diamond.
Enter a command (H for help): i
Your inventory contains these items:
- diamond
Enter a command (H for help): p flower
You pick up the flower.
Enter a command (H for help): i
Your inventory contains these items:
- diamond
- flower
Enter a command (H for help): l
You see a dark room. It contains a lantern.
the east and north.
Enter a command (H for help): e
It has exits to
You move into the room to the east.
You see a leafy room. It has exits to the west, east, and
south.
Enter a command (H for help): s
You move into the room to the south.
You see a simple room. It has one exit, to the north.
Enter a command (H for help): i
Your inventory contains these items:
- diamond
- flower
Enter a command (H for help): l
You see a simple room. It has one exit, to the north.
Enter a command (H for help): s
There is no room to the south.
Enter a command (H for help): w
There is no room to the west.
Enter a command (H for help): h
Valid commands are:
L or look - print a description of the room you are in
I or inventory - print your inventory
P blah or pickup blah - pick up the item called blah
D blah or drop blah - drop the item called blah
N or north - go north
S or south - go south
E or east - go east
W or west - go west
Q or quit - quit
H or help - print this list of commands
Capitalization doesn't matter.
Enter a command (H for help): d hammer
You attempt to drop the hammer, but discover you don't have one
to drop. Oh well.
Enter a command (H for help): q
Goodbye
>>>
Download