Overview
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:
- Part A: design and core implementation
- Part B: full implementation
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 this
has far more features than we want you to try to implement. A simpler
version that is closer to what you should implement is available
here. However, your
solution must be character based. For example, your program might
look like
Action: N)orth, S)outh, E)ast, W)est, shoot A)rrow, H)elp, Q)uit: e
You hear flapping. You smell something bad.
Action: N)orth, S)outh, E)ast, W)est, shoot A)rrow, H)elp, Q)uit: s
You find an arrow. You smell something bad.
Action: N)orth, S)outh, E)ast, W)est, shoot A)rrow, H)elp, Q)uit: n
You hear flapping. You smell something bad.
Action: N)orth, S)outh, E)ast, W)est, shoot A)rrow, 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 A)rrow, H)elp, Q)uit: e
You feel a breeze. You smell something bad.
Action: N)orth, S)outh, E)ast, W)est, shoot A)rrow, H)elp, Q)uit: s
You were eaten by a wumpus!
You will work in groups of 2 or 3 on this assignment. You will design your
own version of the game and implement it in C++. One of your early tasks
will be to document the rules of your game and to construct a class
model. Part of your grade will be based on how unique your solution is;
you might hunt moldy food in your fridge, chase Roscoe Raider through the
science building, or be hunted by a large cockroach. Be creative with
behaviors as well: alternative traps and new ways to move about the caves
are also appropriate. Note that just substituting (say) marshmallows for
arrows is not an example of creativity.
The Game
- 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: give adequate clues to the user that they 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 have a reasonable size, at least 25 rooms but no more
than 60. 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 for instructors
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.
- 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
wouldn't 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.
Design Constraints
- 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.
- 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.
- All group members must contribute to the solution. You will use
GitHub (or a similar site) for your project repository; see below.
- It is expected that all team members will contribute to at
least a third of the classes related to the minimal requirements listed
above (in the paragraph starting with "at a minimum"). The goal
is to learn about interfaces between classes in C++, and having each team
member implement a substantial portion is important to that.
Features beyond the minimums are not considered when checking this
requirement.
Hints
- 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.
Part A
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.
- The text to be written to the user when the user presses the help
key. This must give the game goal, describe the hazards, describe the
hints to the user for the hazards, how the weapons work, and anything
else relevant. The intent is that this text will be copied into an
output statement in your program.
- A drawing of the map you will implement. Note placement of objects on
the map will vary each time the user play's the game, but the
arrangement of rooms should not change.
- A high level, UML class diagram capturing your intended design.
The diagram must include the following:
- Classes for each of the game elements such as a class for each type
of weapon. Show generalization where appropriate.
- Include only important attributes and methods; you do not need to
document constructors, getters/setters, constants, and other details that
can be assumed.
- Include types for attributes and methods only if they are not
obvious from context.
- Capture associations and multiplicities, but do not distinguish
between composition and aggregation.
The diagram can be hand-drawn as long as it's 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.
- A short sentence or two discussing what you believe to be unique
about your solution.
In addition, check in an initial version of the project that builds on all
machines. This should print the primary menu, print the help text when the
user enters 'h', generate the collection of rooms and print the map of the
rooms when the user enters 'm', and exits when the user enters 'q'. Also
write preliminary versions of all class definitions (just the interfaces,
not the implementations).
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. If it takes more than a couple hours to create an initial version of
the project, get help from your instructor. It should be as simple as
creating a "hello world" program and editing it to prompt the user until
the user enters 'q'.
Part B
Part B is finishing and delivering the full solution. This includes the
following:
- Have a friend play the game and confirm it is winnable with minimal
help from you.
- Ensure all code meets the published coding standard and has been
pushed. All source (.h, .cpp files) must be in a folder
called src in the top level of your repository.
- Remember that the standard mandates lower case filenames.
- There should not be any subdirectories in src.
Multi-folder C++ projects do not make sense for the small projects
you create in academics.
- You must have fewer files than classes to ensure you
understand that one file per class is not a requirement in C++.
- The submitted code must be on the main branch. You are
discouraged from using branches for short assignments such as this.
- The 15-line length limit does not apply in this
assignment.
- Ensure the project build files have been checked in to your repository.
- In the top level of your repository, create a file README.TXT
(or README.md, etc.) which gives the names of all people on your team
and build directions that indicate the version of C++ you used, the
build tool you used, the steps someone goes
through to use that tool to build an executable, and where the
executable can be found once it is built. Anyone who knows C++ and has
your build system installed should be able to reproduce those steps.
- Document how to enter debug mode in the game.
- Include any changes to your game (from your stated design) in this
document.
- Use the output of 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.
- Double-check that your instructor has access to your repository.
- Capture a sample run of your program showing that it works. You do
not have to capture every movement, but it should be clear how the player
won the game through the moves they made and hints they got. This will
likely use debug output to show what is happening. Be sure each screen
shot is readable with a minimal amount of additional information. (In
particular, you don't want to include code windows or lots of blank space
in the screen shots).
- In addition to your screenshots, use
these directions
to create a reverse-engineered (UML) class diagram of your system, export
it as a .png, and include that image in sample-run.pdf. Note
only one student needs to construct this diagram.
- At the top of this PDF, list the assignment name and the names of all
group members.
- Submit sample-run.pdf to Canvas to signal that you are
finished.
- See the submission requirements on Canvas. You may need to
demonstrate your solution to your instructor, but this depends on how
your instructor grades the assignment.
Common Issues
- A challenge with group projects is that sometimes partners don't get
their work done on time. If they are just a day or two late on something,
it's a 2-4% penalty. That's 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.)
That brings up the question of 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're 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 wouldn't 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's
where class declarations come in: since you're using pointers, you only
need class A;
in front of B
(and vice versa).