CPS 100E, Fall 1996 Lab 3
Bowling, More Observer Classes, Vectors, etc.
(You may find it
easier to read this lab using Netscape or another browser, the
URL is http://www.cs.duke.edu/~ola/courses/cps100e/lab/lab3.html)
The goals of this lab include doing the specific tasks outlined below
and understanding general concepts behind the tasks.
- Understand Vectors and How they can be used to declare a group of
objects.
- Understand how parameters are passed, when to pass by reference,
and when to pass by const reference.
- Understand how to access vector elements, particularly when
a vector stores instances of a class so that member functions must
be used with each vector element
- Understand how a program can be composed from multiple files linked
together (automatically using the program make with a Makefile.)
- Understand (in a general way) how the game of bowling works
In this lab, you'll investigate how vectors work and you'll use another
animation.
Before coming to lab you should read/review chapter 8
on vectors in Astrachan/Tapestry.
The lab uses vectors to implement an
automatic scoring program for a bowling alley.
In the last lab we were introduced to the basic concept of having an
object that did something (take a random walk), and had another object
(an observer) that reported something about the random walk. We used
samba to show the current location of the walker using animation. In
this lab, we will have multiple observers. The first class (the
Lane) is your bowling alley. The ball will roll down the lane
and hit some pins, etc. The second class (the Scorer) will
mark down your score on the score sheet.
[
Rules of Bowling |
The Program |
Animation |
Modifications |
Submit |
Extra Credit
]
In a bowling match each player takes a turn. The object of the game
is to knock down pins by throwing a bowling ball down a wooden alley;
there are 10 pins.
An individual game is divided into 10 frames. In each frame a player
rolls either one or two balls (there is a special case described later
in which tree balls are rolled).
If the first ball rolled knocks over all 10 pins, then only one ball
is rolled in the frame, this is called a strike. If
the first two balls are used to knock down all 10 pins this is
called a spare. A mark is a
frame in which either a strike or a spare is rolled.
Marks are good because they increase your score.
You don't need to know how to score bowling because the automatic scorer
takes care of this for you!
In the 10th and last frame, if you knock
down all 10 pins you get 3 rolls instead of 2. This can increase your
score.
If you fail to knock down any pins, you haven't rolled very well. If
your ball lands in a special part of the alley called a gutter, then
you've rolled a gutter ball. Not all zeros are gutter
balls, but all gutter balls are zeros.
back to lab contents
In this section of the lab you'll copy files, compile a basic simulation
of a bowling alley, and view the simulation using samba again.
First change into your cps100e subdirectory (type pwd
to verify where you are). Create a
lab3 subdirectory by typing mkdir lab3 and change
into this subdirectory (be sure to check that you're
in the lab3 subdirectory.) Now copy the files for the lab
(don't forget the . when copying).
cp ~ola/cps100e/lab3/* .
You should see the files listed below (these are links to the files in
case you use Netscape, and for users outside of Duke).
Be sure you're in the lab3 subdirectory, and check to see that
all files are there (type ls). Then, from an xterm window (at
the prompt [1] ola@teer8% or similar) compile the first version
of the program by typing: make bowl .
This should compile several files and link them together with the library
libtapestry.a. Now run the program by typing:
bowl at the prompt. Although the program may seem to do
nothing, it is creating a file to store information about a game of
bowling that was simulated. If you type ls after the
program runs, you should see a file called bowl.out which was
created by bowl. If you type ls -lt you'll see files
sorted by time of creation, so bowl.out should be first.
To see an animated re-play of the game you run samba using
the file you created when the bowling simulation was run. To run the
animator type:
samba bowl.out
( If you get a message samba: command not found,
then
you didn't change your path in lab1 and you should check with a TA.
)
To make samba work, you'll need to click on the start button in
the Polka Control Panel. You can
slow the animation down using the slide-bar. Because there are two
windows for this animation, you might want to move them around to make
it easier to see both the ball/pins and the auto scorer.
You can pause/start using
the pause/start button. To quit samba, use the quit button.
back to lab contents
In this part of the lab you'll change the Bowling program so that you
can input the number of bowlers, the
names of each bowler, and the skill level of each
bowler. The first bowling program scores a game for just
one person.
More Bowlers
- Run emacs, either by clicking on the emacs icon in the menubar (if
there is one) or typing emacs & at a prompt.
- Load (use the file menu or C-x C-f) the file main.cc.
- Add a prompt in the PlayGame function which asks the user to
input some number of players between 1 and 5. You should try
to use prompt.h for this.
- Change the definition of a single game (for the bowler
"Owen") to a vector of games, one for each player. Change:
Game game("Owen");
to
Vector players(numPlayers);
This will create a vector of Game objects that will have
a bowling match. Although the name of the class is Game, think of
each element of the vector players as a player.
You'll need to initialize each Game/Player by
setting the game's name and skill-level, this is described below.
- Add a loop (right after the Vector definition you just made)
which asks the user for each player's name and sets each player's name.
Hint: you will call the member function
Game::SetName() inside the loop, using a syntax similar
to players[k].SetName(...). Look at
the file game.h
to see what parameter(s) SetName takes.
-
In addition to setting each bowler's name, you should set each
bowler's skill level. Use the member function
Game::SetSkillLevel() to set the skill level of each player. You
should prompt the user for the skill level of the bowler. 0 is a
really bad bowler, 30+ is a professional bowler. The declaration for
the function SetSkillLevelis in
bowler.h
- In the loop, in addition to setting names and skill-levels, you'll
need to attach the observers lane and scorer to each
player. To do this you'll use a statement like:
players[k].AttachObserver(lane);
and you'll need to attach the scorer as well.
- Change the loop that calls game.TakeTurn() so that each
player takes a turn. To do this you'll use the loop already written
and shown below:
for (k=0; k < Game::MAX_FRAME; k++)
{
}
but you'll include a loop inside this loop so that every
game/player in the Vector players takes a turn. You'll need
a statement somthing like players[j].TakeTurn(), you'll need
to think about this. The key is that the outer loop executes 10 times,
once for each frame. The inner loop needs to execute once for each
player, so that each player will take a turn.
When your program compiles and executes, be sure to run Samba on the
output file to verify that all players are scored.
Adding Functions, Passing by Reference
For this part of lab, you'll add a new function
MatchStats that computes statistics for the match of several
players.
Since there are now several players instead of just one, you should
first change the name PlayGame to PlayMatch. To do
this
- Make sure that main.cc is the active buffer in your
emacs session. Type M-x replace-string, that's Escape-x,
followed (in the minibuffer) by "replace-string". You can hit the TAB
key after "repl" and the command will be completed (partially). If you
hit TAB again, the choices will appear and you can type "st" TAB to
complete the command, then hit return.
- At the prompt Replace string: type "PlayGame" and press
return.
- At the prompt Replace string PlayGame with: type
"PlayMatch" and press return. This should replace all occurrences of
PlayGame with PlayMatch. Emacs supports several
commands to search and replace, both from the Edit-menu, and with
keyboard shortcuts.
You'll now add a function MatchStats. Pass the vector of
players from PlayMatch to MatchStats. You should pass
the vector as a const reference parameter. The number of elements in
the vector is accessible as players.length() since the vector
was defined to hold exactly as many players as are in the match.
In the function MatchStats you should use the vector and
appropriate member functions to print the following statistics; these
should be printed using cout << ...; the output will
appear on the screen and you'll be able to run Samba on
bowl.out to verify if your stats are correct.
- Print the name and final score of each player. Names are
accessible using Game::GetName() and the final score is
accessible using Game::TallyScore where you'll need to pass
10 (or Game::MAX_FRAME) to get the complete score. These
member functions are described in game.h.
- Compute the number of marks each player has, and the number of
strikes. See rules of bowling above for the
definition of a mark.
-
To compute marks for a player you'll need to get
each frame in the player's game. The function Game::GetFrame()
returns a frame, so you can use the function (defined
in game.h) to retrieve each frame and store
the frame in a local variable, e.g., Frame f = ....
- You'll
then need to use the Frame member function Frame::GetScore()
(defined in frame.h) to get the score for the
frame. If the score is greater than or equal to
10, it's a mark. If the score on the first ball is a 10 it's a strike.
-
To find the score on the first ball you'll need to use the frame member
function Frame::GetPinCount() which returns the number of pins
knocked down with ball number 0, 1, or 2 (remember that there can be
up to three balls per frame). The GetPinCount function
is defined in frame.h.
back to lab contents
To submit assignments you'll run the command below, but substitute your
section number (1, 2, or 3) for N.
submit100e lab3.N README main.cc
You can enter the files in any order
(you don't need to submit observer.h, frame.h, frame.cc, scorer.h,
scorer.cc, lane.h, or lane.cc because they didn't change,
(but you can submit them.)
Remember that every assignment must have a README file submitted with it
(please use all capital letters). Include your name, the date, and an
estimate of how long you worked on the assignment in the README
file. You must also include a list of names of all those people with
whom you collaborated on the assignment.
You also must turn in the inlab
questions either by turning in the sheet during lab or
by submitting the answers with your README.
back to lab contents
For extra credit, you should print the names and scores of each bowler,
but the scores should be sorted from highest to lowest. You can read in
Chapter 10 of Astrachan/Tapestry about how to sort vectors.
If you do the extra credit you'll submit it separately. Use
(but substitute your
section number (1, 2, or 3) for N)
submit100e lab3.N.xtra README main.cc