This assignment will give you experience with working in teams to write a larger, object-oriented C++ program involving pointers and inheritance. It is in two parts:
Hunt the Wumpus was an early computer game. The basic goal of the game is to kill a wumpus in a cave without entering the chamber the wumpus is in, using your senses to detect when it is close by. Along the way you can fall into pits, be picked up by bats, and discover objects such as arrows and treasure. Atari had a full version of this that you can play online, but you will implement a much smaller game for this assignment. A simpler version that is closer to what you should implement is available here, though your version will use input and output through the console rather than graphics.
You will work in groups of 2 or 3 on this assignment. You will design your own variant on the game and then implement that in C++. Variants could include such ideas as hunting moldy food in the fridge, escaping from a cockroach in a garbage bin, or capturing Roscoe Raider in the science building. In addition to having a different setting, you must design your own traps and weapons. Part of your grade on the assignment will be based on your creativity.
When you are finished, you must have a game that interacts through the console. For example, if you implemented a story based on pirates, your program might have a dialog like
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: e
You smell stew. You hear a belch.
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: s
You find an cannon ball. You hear a belch.
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: n
You smell stew. You hear a belch.
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: n
You are in a maze of twisty passages, all alike.
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: e
You smell gunpowder. You hear a belch.
Action: N)orth, S)outh, E)ast, W)est, shoot C)annon, H)elp, Q)uit: s
You were shot!
You must have a help option describing how to play the game. Ensure this describes all of the rules.
The game must be solvable through logic. Winning cannot depend largely on chance or exploring the whole game space. That is, it must be a puzzle game: it must give adequate clues that the game player can use deduction to win. Depending on luck will cost points.
At a minimum, you must have equivalents for the wumpus, the pits, the bats, and the arrows (something to pick up). Since you must use inheritance in the implementation (see below), you will need at least two types of hazards and two types of weapons.
No graphics. All user input and output to your program must be through
cin and cout using the standard ASCII character set.
The map must be rectangular and have a reasonable size, at least 25 rooms but no more than 49. Larger maps will not be allowed because they make grading too difficult.
The map must be bounded; you must have edge rooms that allow a player to know when they have explored as far as possible in one direction. The directions must always be east/west/south/north, and if the player enters a room where one of the directions is blocked then you must tell them so.
You must provide clues to the player when they approach the various hazards. Since the gamer cannot see the map contents, they need clues to tell them when they approach hazards and the wumpus. For instance, the original game says "you smell something bad" if the player is in a room adjacent to the wumpus, "you feel a breeze" if the player is in a room adjacent to a pit, and "you hear flapping" if the player is close to a room with a bat. In the original, "adjacent" means either sharing a wall or a corner, and "close to" a bat is up to 2 rooms away. Arrows are not hazards, so there are no clues for those. You will need to define your own rules for clues (that must be documented). The key is that the clues must be strong enough that a player can deduce the location of the target (such as the wumpus) but still requiring logic to work out that location.
You do not have to tell the player what room they are in. In the original game, forming a mental map of the dungeon and navigating that in your head was an important game element. But feel free to identify rooms (in whatever way you think is appropriate - maybe there are colored gems on the walls?) if you want.
Stick to one level. Multi-level dungeons are too hard to test.
Use e/w/n/s to move in the specified directions. Entering an "e" should move east; do not have the user enter more complex commands such as "m" for move followed by an "e"; the "e" is enough by itself. Uniformity is critical for grading. Upper case commands must be treated the same as lower case commands (case in-sensitive). Do not implement the common "wasd" directions - this game is intended for casual gamers.
The program cannot quit because of an invalid command. Print an error and continue.
Your game must exhibit random behavior. Randomly place items on the map
so the user has to solve a different map each time. You can use
rand to
generate the random numbers. If your room arrangement is random, that
must also be randomly generated for each game. There
Along with the e/w/n/s, actions to pick up weapons, etc., have "m"
display the full map with hazards and other elements. This will help with
debugging and grading. Use the following key for this map: a period for
an empty room, an > for a weapon (such as an arrow), + for the
player, ! for a bat, @ for a hazard (such as a pit), ? for
treasure, and # for the monster. As an example, your map would look
like
. . > + .
. ! @ . >
. ? . > !
. @ # . .
@ . . > @
Follow this notation for your own game. Having uniform notation on this output will help tremendously in grading. If useful, you can also create a debug mode that displays the map on each move, but make sure this mode is disabled by default.
While displaying the map is important to verify game play is working, it must be possible to win the game without resorting to viewing the map. This means you must implement clues similar to the "you smell something bad" clue of the classical game. In addition, the monster and other items must not move during game play unless there is a specific rule such as "the wumpus moves when shot at".
Any hints you give the player must be based on being in a neighboring room. For example, feeling a breeze when the player is next to a pit or hearing the wumpus start to move if it is disturbed by shooting an arrow. This is a large part of what makes hunt-the-wumpus a winnable puzzle game. You should be able to find corresponding clues for any variant of the game. Do not make the player purchase hints (say, trading gold or experience points) because this will make the game too hard to grade. The "neighborhood" for a room is something you can determine, but do not allow clues to travel too far or the game will be too hard to play.
Whenever the bat (or its equivalent) moves the player in the dungeon, provide a hint saying the player moved. Note the original game does not say where the player moved to, just that the player was moved.
Whenever the player is killed, say by falling into a trap or being eaten by a monster, say what killed the player so the user can learn to play the game better in the future.
Your implementation must be unique, even if your rules are very close to the original. If your implementation looks like one of the hundreds of versions of the game that are available online, you will be penalized. Ignore the online code and you will be fine.
You must use inheritance in an important way as part of your solution. You are required to use inheritance for the hazards (either through the hazards themselves or by having different classes for different types of rooms) and you are required to use inheritance to support multiple types of weapons with different behaviors.
You must make heavy use of classes (have a number of them). This actually helps distinguish your solution from most of the ones online. Start with the obvious (domain) classes: maps, rooms, the item being hunted, hazards, etc. These are the objects in the problem that a non-programmer would recognize, and using them as the basis of a design makes your program easier to write and maintain.
Use pointers for game elements like the map, locations, weapons, etc. In particular, each room needs to have pointers to the adjacent rooms so that moving through the map is a matter following a pointer (as opposed to incrementing or decrementing an index in an array).
Each class must have clear, documented responsibilities. This
documentation must be in the .h files. That is, describe each
class from the perspective of what other classes can rely on.
Be sure your use of inheritance follows good use of "is-a". For example, a Wumpus is not a type of room. If your design is leading you down a path of violating common sense, talk to your instructor for ideas about how to fix the problem. It can often be as simple as renaming a class so that the "is-a" relationship does make intuitive sense.
Avoid storing indices in objects. If the player is in a room, you should use a pointer to track which room the player is in rather than simply record the coordinates of that room. This makes your code more direct.
Whenever you create an instance of a class your group writes, or whenever
you pass an instance as a parameter, use pointers. This is especially
important for inheritance, but it is also necessary to give your team
more experience with pointers. Be sure to use delete to return all
allocated memory to the heap. This would not be strictly necessary for a
small project like this, but it is good practice. There must be exactly
one delete executed for each new executed. You will likely want to
implement destructors to ensure this happens.
All group members must contribute to the solution. You will use GitHub (or a similar site) for your project repository; see below. On two-member teams, each member must contribute at least a third of the classes. On a three-member team, each must contribute at least a quarter. The goal is to learn about interfaces between classes in C++, and having each team member implement a substantial portion is important to that. Each team member must commit their own code to the repository. Features beyond the minimums are not considered when checking this requirement.
Use rand to
generate random numbers.
Use srand to
seed your random number generator; see the line "srand(time(NULL))"
in the example.
You might prompt the user about using debug mode and then call the
srand function only in regular mode. You can also set up debug mode
to run when the user specifies a command-line argument. Be sure to
document entering debug mode in the readme file (see below).
If you are interested in using the C++ <random> library instead of
rand and srand, talk to your instructor.
As long as other constraints are satisfied, it is fine to use the
standard template library (STL) classes like vector, map, and
list in this assignment.
This project is broken into two parts. The first is about specifying the problem, the second about completing the implementation.
For part A, submit a (single) PDF containing all of the following:
The names of the people in the group.
The URL of your git repository. See Canvas for instructions on creating this repository. The repository name must be all lower case with no spaces. If you named your repository incorrectly, talk to your instructor.
An initial implementation of your system that builds using C++ version 17 or later and which contains help text that captures your game rules. Rules include describing hazards, hints, weapons, and other relevant issues. You can modify the code we give you as you see fit, but do not introduce subfolders for the project. That is, the project make file must be at the top level as you received it.
A high level, UML class diagram capturing your intended design. The diagram must include the following:
The diagram can be hand-drawn as long as it is reasonably neat, but you can also use a tool like Enterprise Architect. See the train example for a sample diagram.
A description of which part of the system each team member will implement.
Some students are tempted use use the code generation feature of Enterprise Architect to create the initial code. Do not; it adds a lot of unnecessary artifacts and means you will not get sufficient practice writing C++ code.
Part B is finishing and delivering the full solution. This includes the following:
src
in the top level of your repository.
src. Multi-folder C++
projects do not make sense for the small projects you create in
academics.g++ --version to determine the version of the
tool used to build the system. It is very helpful to be able to
identify this when trying to get a system to build years after it
was written..png, and include that image in sample-run.pdf. Note only one
student needs to construct this diagram.sample-run.pdf to Canvas to signal that you are finished.A challenge with group projects is that sometimes partners fail to complete their work done on time. If they are just a day or two late on something, it is a 2–4% penalty. That is unlikely to affect anyone's grade, but if it does then bring it to my attention at the end of the year and I will adjust. But if they are going to miss by more than that, submit what you have done so I can adjust any late penalties appropriately. (This is especially true if the partner fills out the "need more time" form and has to take an extra week. If the partner does nothing, you then have something submitted that I can grade.)
If your partner fails to complete their portion, what should you submit? You are NOT responsible for doing the work your partner is supposed to do. But do show something. For example, if you are responsible for movement and hints, maybe you can create a fixed, dummy grid with (say) 4 by 4 cells and so you can show that you can move around in the dungeon and get appropriate hints. That would not meet the definition of a game, but would be sufficient to show that your code is basically working even if your partner's code is not. Another, though less preferred way to show you have completed something is to set breakpoints in the debugger and show how your code changes internal state. Feel free to contact me if you have more detailed questions about what to do or how much to implement.
You will likely have circular references in this SPA. That is, class
A will depend on B and B will depend on A. You cannot define
class A in front of B and B in front of A. That is where class
declarations come in: since you're using pointers, you only need
class A; in front of B (and vice versa).