DAT 501
Hunt the Wumpus!
The exercise is to implement the classic computer game Wumpus Hunt!
The Game
The game takes place in a network of 20 caves connected by passages. There are three creatures in the caves: you and two terrible monsters, called Wumpuses. You and the Wumpuses move around in the caves. When a Wumpus enters your cave, or you enter a Wumpus’ cave, you die a terrible death and lose the game. You can shoot into neighbouring caves, which will kill the Wumpus if it is there. You have five arrows. A Wumpus is a very smelly creatures, so when you are in a neighbouring cave you will know that there is a Wumpus near you. You can also hear the Wumpus move around, no matter where in the maze it is. There are two types of Wumpus: one will simply sit around and never move, while the other sometimes moves randomly from cave to cave.
Wumpus was a popular game in the early Eighties, when computer games were still young. For inspirataion, there are a number of fancy web-based implementations available, which are indexed at the Yahoo! catalogue
Most of these implementations are similar to our Wumpus game, but it is imperative that you follow the guidelines below instead of imitating any of the games above.
My own solution, which of course follows the guidelines, is available at
on the student machines. Just enter that directory, and start it:/usr/kurs/dat401/vt01/wumpus
cd /usr/kurs/dat401/vt01/wumpus java Controller
Prepare for hours of fun with Hunt the Wumpus! (Health warning: Many hours of playing computer games without exercise can lead to headaches.)
Note that my solution is meant as an example (and as a minimally exciting one), you do not need to imitate it beyond the guidelines below.
Structure
The structure of this exercise is very rigid. You may not break any of the following constraints, even if you think that there is a nicer way to structure the code.
The Players
There are three classes for players: Human for the human player, Wumpus for the stationary wumpus, and MovingWumpus for the one that moves around. Human and MovingWumpus implement the Traveller interface (which basically states that somebody can enter new caves), and all three implement the CaveDweller interface (which basically states that somebody is alive and has a location).
Travellers can implement the performAction() method very differently.
The MovingWumpus must to the following: With a certain probability, choose a random neighbouring cave (otherwise do nothing). If it is occupied by another Wumpus, then stay where you are. It it is occupied by a Human, then kill him (the Human implements CaveDweller, so he has a kill() method).
The Human implements performAction() by asking the user for directions. A dialog windows pops up, and the user can ask the Human to move into an adjoining cave (which kills him if that cave contains a wumpus) or shoot an arrow (which kills the wumpus if it is there).
If you want, you can implement all kinds of other monsters in the caves, which implement performAction() quite differently. However, the MovingWumpus and the Human must do exaclty as described above.
Caves
The caves form a large maze. Every cave has a unique identifier
(which you can get with getId()) numbered 0,1,2,....
A Cave object's getOccupant() method returns the CaveDweller that occupies it (or null, if it is empty). Conversely, every CaveDweller's getLocation() method returns the Cave in which it resides.
Thus the following invariant (called the Cave invariant) must be maintained by every CaveDweller C:
C.getLocation().getOccupant() == C
Cave is a large object, and its method headers and documentation is already written to save you some typing, see below.
The View
The user views the maze through the eyes of the Human. He can see
- His own location
- Which caves are connected to his location
- How many arrows he has left
- If there is a wumpus in a neighbouring cave then he can smell him
Here is an example from the my own solution:
You are in cave 0. You have 5 arrows left. Passages lead to caves 1, 19, and 10. You smell a wumpus.
We assume that the view object (called writer) provides two methods, writeDescription(), which does the above, and write(String S) to write out other messages like "You just died".
Tips
- Ignore the MovingWumpus at first. It will behave as the (unmoving) Wumpus, since it extends that Class. When everything else works, turn your attention to MovingWumpus.
- Change the View object to tell you everything about the Maze while you write test the program. Especially, write out the location of the Wumpuses. This makes it much easier for you to find any mistakes.
- The fact that I’ve written some code and method headers for some of the classes (like Cave) f doesn’t mean that you cannot add more methods or fields. Add all the methods and fields you want!
Finished Files
Several of the files for this application are finished, you may not change them in any way. These are
- CaveDweller.java, the CaveDweller interface.
- Traveller.java, the Traveller interface.
- Controller.java, the Controller class.
- Maze.java, the Maze class.
Moreover, we provide two skeleton files with method headers and documentation, simply to make our life easier by enforcing a certain similarity between the different solutions to this exercise. It also saves you some typing.
- Writer.java, a skeleton for the view object. You may change this to extend another class if you want (JFrame, for example) and add all the fancy stuff you want (3D images of the caves, sounds, movie interludes, etc.).
- Cave.java, a skeleton for the cave object.
What remains (besides finishing Cave and Writer) is to implement the following classes according to the above description:
- Human
- Wumpus
- MovingWumpus