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.