6.8. Case Study: Game of Chance;
Introducing enum
One of the most popular games of chance is a dice game known
as "craps," which is played in casinos and back alleys worldwide. The rules of
the game are straightforward:
A player rolls
two dice. Each die has six faces. These faces contain 1, 2, 3, 4, 5 and 6 spots.
After the dice have come to rest, the sum of the spots on the two upward faces
is calculated. If the sum is 7 or 11 on the first roll, the player wins. If the
sum is 2, 3 or 12 on the first roll (called "craps"), the player loses (i.e.,
the "house" wins). If the sum is 4, 5, 6, 8, 9 or 10 on the first roll, then
that sum becomes the player's "point." To win, you must continue rolling the
dice until you "make your point." The player loses by rolling a 7 before making
the point.
The program in Fig. 6.10
simulates the game of craps.
Fig. 6.10. Craps simulation.
1 // Fig. 6.10: fig06_10.cpp
2 // Craps simulation.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 #include <cstdlib> // contains prototypes for functions srand and rand
8 using std::rand;
9 using std::srand;
10
11 #include <ctime> // contains prototype for function time
12 using std::time;
13
14 int rollDice(); // rolls dice, calculates amd displays sum
15
16 int main()
17 {
18 // enumeration with constants that represent the game status
19 enum Status { CONTINUE, WON, LOST }; // all caps in constants
20
21 int myPoint; // point if no win or loss on first roll
22 Status gameStatus; // can contain CONTINUE, WON or LOST
23
24 // randomize random number generator using current time
25 srand( time( 0 ) );
26
27 int sumOfDice = rollDice(); // first roll of the dice
28
29 // determine game status and point (if needed) based on first roll
30 switch ( sumOfDice )
31 {
32 case 7: // win with 7 on first roll
33 case 11: // win with 11 on first roll
34 gameStatus = WON;
35 break;
36 case 2: // lose with 2 on first roll
37 case 3: // lose with 3 on first roll
38 case 12: // lose with 12 on first roll
39 gameStatus = LOST;
40 break;
41 default: // did not win or lose, so remember point
42 gameStatus = CONTINUE; // game is not over
43 myPoint = sumOfDice; // remember the point
44 cout << "Point is " << myPoint << endl;
45 break; // optional at end of switch
46 } // end switch
47
48 // while game is not complete
49 while ( gameStatus == CONTINUE ) // not WON or LOST
50 {
51 sumOfDice = rollDice(); // roll dice again
52
53 // determine game status
54 if ( sumOfDice == myPoint ) // win by making point
55 gameStatus = WON;
56 else
57 if ( sumOfDice == 7 ) // lose by rolling 7 before point
58 gameStatus = LOST;
59 } // end while
60
61 // display won or lost message
62 if ( gameStatus == WON )
63 cout << "Player wins" << endl;
64 else
65 cout << "Player loses" << endl;
66
67 return 0; // indicates successful termination
68 } // end main
69
70 // roll dice, calculate sum and display results
71 int rollDice()
72 {
73 // pick random die values
74 int die1 = 1 + rand() % 6; // first die roll
75 int die2 = 1 + rand() % 6; // second die roll
76
77 int sum = die1 + die2; // compute sum of die values
78
79 // display results of this roll
80 cout << "Player rolled " << die1 << " + " << die2
81 << " = " << sum << endl;
82 return sum; // end function rollDice
83 } // end function rollDice
|
Player rolled 2 + 5 = 7
Player wins
|
| |
Player rolled 6 + 6 = 12
Player loses
|
| |
Player rolled 3 + 3 = 6
Point is 6
Player rolled 5 + 3 = 8
Player rolled 4 + 5 = 9
Player rolled 2 + 1 = 3
Player rolled 1 + 5 = 6
Player wins
|
| |
Player rolled 1 + 3 = 4
Point is 4
Player rolled 4 + 6 = 10
Player rolled 2 + 4 = 6
Player rolled 6 + 4 = 10
Player rolled 2 + 3 = 5
Player rolled 2 + 4 = 6
Player rolled 1 + 1 = 2
Player rolled 4 + 4 = 8
Player rolled 4 + 3 = 7
Player loses
|
In the rules of the game, notice that
the player must roll two dice on the first roll and on all subsequent rolls. We
define function rollDice (lines 71–83) to roll
the dice and compute and print their sum. Function rollDice is defined once, but it is called from two places (lines 27
and 51) in the program. Interestingly, rollDice takes no arguments, so we have indicated an empty
parameter list in the prototype (line 14) and in the function header (line 71).
Function rollDice does return the sum of the two
dice, so return type int is indicated in the function prototype and
function header.
The game is reasonably involved. The
player may win or lose on the first roll or on any subsequent roll. The program
uses variable gameStatus to keep track of this.
Variable gameStatus is declared to be of new type
Status. Line 19 declares a user-defined type
called an enumeration.
An enumeration, introduced by the keyword enum and
followed by a type name (in this case,
Status), is a set of integer constants
represented by identifiers. The values of these enumeration constants start at 0, unless
specified otherwise, and increment by 1. In the preceding enumeration,
the constant CONTINUE has the value 0, WON has the value 1 and
LOST has the value 2. The identifiers in an enum must be unique, but separate enumeration constants can have
the same integer value (we show how to accomplish this momentarily).
Good Programming Practice 6.1
|
Capitalize the
first letter of an identifier used as a user-defined type
name. |
Good Programming Practice 6.2
|
Use only
uppercase letters in the names of enumeration constants. This makes these
constants stand out in a program and reminds you that enumeration constants are
not variables. |
Variables of user-defined type Status can be assigned only one of the three values declared in
the enumeration. When the game is won, the program sets variable
gameStatus to WON (lines 34 and 55).
When the game is lost, the program sets variable gameStatus to
LOST (lines 39 and 58). Otherwise, the
program sets variable gameStatus to CONTINUE (line 42) to indicate that the dice must be rolled
again.
Another popular enumeration is
enum Months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG,
SEP, OCT, NOV, DEC };
which creates user-defined type Months with enumeration constants representing the months of the
year. The first value in the preceding enumeration is explicitly set to
1, so the remaining values increment from 1, resulting in the
values 1 through 12. Any
enumeration constant can be assigned an integer value in the enumeration
definition, and subsequent enumeration constants each have a value 1 higher than
the preceding constant in the list until the next explicit setting.
After the first roll, if the game is won
or lost, the program skips the body of the while statement (lines
49–59) because gameStatus is not equal to CONTINUE. The
program proceeds to the if...else statement in lines 62–65, which
prints "Player wins" if gameStatus is equal to WON
and "Player loses" if gameStatus is equal to
LOST.
After the first roll, if the game is
not over, the program saves the sum in myPoint (line 43). Execution proceeds with the
while statement, because gameStatus is equal to
CONTINUE. During each iteration of the
while, the program calls rollDice to produce a
new sum. If sum matches myPoint, the
program sets gameStatus to WON (line 55), the
while-test fails, the if...else statement prints "Player
wins" and execution terminates. If sum is equal to 7, the
program sets gameStatus to LOST (line 58), the
while-test fails, the if...else statement prints "Player
loses" and execution terminates.
Note the interesting use of the various
program control mechanisms we have discussed. The craps program uses two
functions—main and rollDice—and the switch,
while, if...else, nested if...else and nested
if statements.
Good Programming Practice 6.3
|
Using
enumerations rather than integer constants can make programs clearer and more
maintainable. You can set the value of an enumeration constant once in the
enumeration declaration. |
Common Programming Error 6.9
|
Assigning the
integer equivalent of an enumeration constant (rather than the enumeration
constant, itself) to a variable of the enumeration type is a compilation
error. |
Common Programming Error 6.10
|
After an
enumeration constant has been defined, attempting to assign another value to the
enumeration constant is a compilation
error. |