Case Study: Game of Chance and Introducing enum
Case Study Game of Chance and 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.11 simulates the game of craps.
Figure 6.11. Craps simulation.
(This item is displayed on pages 259 - 261 in the print version)
1 // Fig. 6.11: fig06_11.cpp 2 // Craps simulation. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include // contains prototypes for functions srand and rand 8 using std::rand; 9 using std::srand; 10 11 #include // 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
|
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 7183) 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 the programmer 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 4959) because gameStatus is not equal to CONTINUE. The program proceeds to the if...else statement at lines 6265, 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 functionsmain and rollDiceand the switch, while, if...else, nested if...else and nested if statements. In the exercises, we investigate various interesting characteristics of the game of craps.
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 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. |