Main Routine Pseudocode
Let's use the class, attribute and method names we've identified so far and try to write the main routine of our program. Doing so should reveal any missing objects, or missing attributes or methods of objects. First we'll say what we want to do as plainly as we can in English.
While the game isn't over
Display the game state
Display the menu of possible actions
Get the user's choice of action
If the action is move
Display the choices (connected rooms)
Get the user's choice
Move the player
If the room has a bat
Have the bat snatch the player
Otherwise if the room has a pit
Have the pit swallow the player
Otherwise if the room has a Wumpus
Wake the Wumpus up
Otherwise if the action is shoot
Get the path for the arrow to follow from the user
Tell the arrow to fly that path
Otherwise if the action is quit
Quit the game
There's one subtlety here that may escape your notice at first glance and that is the significance of the ordering of the three possibilities in reaction to a movement. This pseudocode says that if there is both a bat and a pit in the room the player moves to, the bat will snatch the player before they can fall into the pit, making a bat snatch a good thing in this circumstance! Likewise if there is a pit and a Wumpus the player will fall into the pit before the Wumpus is woken up. The instructions we are basing this on do not say what should happen in these cases, so I have made some arbitrary but reasonable (I think!) decisions.
Now let's try to match these English phrases with our object methods and attributes, and introduce some Python where the equivalent Python commands are obvious (e.g. the main while loop control is something we've seen before):
1 while not game_over:
2 print(cave_system)
3 print(player.location)
4 action = input('Shoot, move or quit (s/m/q)? ')
5 if action == 'm':
6 print('Choose from: ', cave_system.rooms[player.location].tunnels)
7 room_choice = int(input('Your choice? '))
8 player.move(room_choice)
9 new_room = cave_system.rooms[player.location] # Note simplifying alias.
10 if new_room.has_bat():
11 new_room.bat.snatch()
12 elif new_room.has_pit():
13 new_room.pit.swallow()
14 game_over = True
15 elif new_room.has_wumpus():
16 game_over = room.wumpus.wake_up()
17 elif action == 's':
18 player.shoot()
19 elif action == 'q':
20 game_over = True
Take some time to study this code. There are numerous things to note:
- β line 3
- Displaying the player's
location
attribute (see the dot notation?) - β line 6
cave_system.rooms[player.location]
.tunnels is a relatively complex expression for us, so let's deconstruct it carefully. - cave_system.rooms is the rooms attribute ofcave_system
- the square brackets ofcave_system.rooms[]
indicate that therooms
attribute is a list ofroom
s - we use the player'slocation
attribute,player.location
, to access the current room - we display the tunnels leading from the currentroom
by printing thetunnels
attribute of the current room- β line 8
player.move(room_choice)
calls the player'smove
method withroom_choice
as a parameter (or equivalently, sends theplayer
object the message tomove
toroom_choice
)- β line 9
- the player is now in
room
cave_systems.rooms[player.location]
but that is a mouthful to say or type so we will introduce a simplifying alias for it and refer to it asnew_room
. Note thatnew_room
isΒ exactlycave_systems.rooms[player.location]
because it is a reference to that object. - β line 10
- we call
new_room
'shas_bat
method to find out if the room contains abat
. - β line 11
- we call the
bat
innew_room
'ssnatch
method (or equivalently, send thebat
object innew_room
the message tosnatch
). - β line 12-15
- similarly to lines 10 and 11
- β line 16
- we don't just tell the Wumpus to
wake_up
, we ask it to report back to us if the game is over. We need to do this because the game may or may not end depending on what the wumpus does, whereas in line 13 we know the game ends when the player falls in a pit. This is why theswallow
method does not report back: its outcome is a foregone conclusion. - β line 18
- to keep things short I just called the player's
shoot
method here. It may in fact be better to get the arrow's desired path here, like we did for the movement destination, than inside theshoot
method.
That didn't reveal any objects, attributes or methods we had missed, which gives me enough confidence that we have a reasonable object model to continue developing our objects. Next we'll flesh out the class definitions and then return to our main line code.