> ### Solution for
> Programming Exercise 5.3

> THIS PAGE DISCUSSES ONE POSSIBLE SOLUTION to the following exercise from this on-line Java textbook.

> Exercise 5.3: This problem uses the `PairOfDice` class from Exercise 5.1 and the `StatCalc` class from Exercise 5.2.

> The program in Exercise 4.4 performs the experiment of counting how many times a pair of dice is rolled before a given total comes up. It repeats this experiment 10000 times and then reports the average number of rolls. It does this whole process for each possible total (2, 3, ..., 12).

> Redo that exercise. But instead of just reporting the average number of rolls, you should also report the standard deviation and the maximum number of rolls. Use a `PairOfDice` object to represent the dice. Use a `StatCalc` object to compute the statistics. (You'll need a new `StatCalc` object for each possible total, 2, 3, ..., 12. You can use a new pair of dice if you want, but it's not necessary.)

> Discussion

> The program from Exercise 4.4 defines a function, `rollFor(N)`, that performs the basic experiment once. It rolls the dice until the total on the dice is `N`, and it returns the number of rolls. Using a `PairOfDice` object, `dice`, the body of this subroutine becomes

>                 int rollCt = 0;  // Number of rolls made.
>                 do {
>                    dice.roll();
>                    rollCt++;
>                 } while ( dice.getTotal() != N );
>                 return rollCt;

> This is significantly simpler than the original version. But where does the dice object come from? One possibility is to create a new `PairOfDice` object at the beginning of the function. This will work, but then a new object is created each time the function is called. In the program we are writing, the function is called 110,000 times. It seems a waste to manufacture 110,000 pairs of dice when one would do. To avoid this, I create the dice as a static member variable:

>             private static PairOfDice dice = new PairOfDice();

> The variable must be `static` since it is used in the `static` function, `rollFor`. Since `dice` is a static member variable, it is created and initialized when the class is first loaded and it exists as long as the program is running. The `rollFor()` method always uses this one pair of dice. (Some people might prefer to create the dice as a local variable in the `main()` routine. The dice could be passed as a parameter to the `rollFor()` method. Then, `rollFor(N,dice)` would mean "roll for a total of `N` using this pair of dice.")

> The original program also had a method called `getAverageRollCount()` to find the average number of rolls, when the basic experiment is repeated 10000 times. We could rename this to `getRollCountStats` and use it to compute all the statistics, not just the average. The actual computation is to be done by a `StatCalc` object. Let `stats` be a variable that refers to that object. The results of each experiment will be fed into this object, something like this:

>                for ( int i = 0;  i < 10000;  i++ ) {
>                      // Assume "total" is the number we are rolling for.
>                    rollCountThisExperiment = rollFor( total );
>                    stats.enter( rollCountThisExperiment );
>                }

> At the end of this process, `stats` is ready to report the statistics. All you have to do is call its functions, such as `stats.getMean()`.

> In my program, I use the named constant `NUMBER_OF_EXPERIMENTS` instead of the literal number, 10000. I abbreviate the for loop to

>                for ( int i = 0;  i < NUMBER_OF_EXPERIMENTS;  i++ )
>                    stats.enter( rollFor(total) );

> and, since it has become so short, I deleted the subroutine and moved the `for` loop into the `main()` routine. The `main()` routine prints the output in neat columns, using the version of `TextIO.put()` that has a column-width specification. For example, "`TextIO.put(total,6);`" prints the value of `total` in a column of width 6. (The hardest part was figuring out how wide to make the columns!). After printing out some headings for the columns, the `main()` routine says

>                 for ( int total = 2;  total <= 12;  total++ ) {
>                    StatCalc stats;  // An object that will compute the statistics.
>                    stats = new StatCalc();
>                    for ( int i = 0; i < NUMBER_OF_EXPERIMENTS; i++ ) {
>                          // Do the experiment of counting the number of rolls
>                          // required to roll the desired total, and enter the
>                          // number of rolls into stats' dataset.
>                       stats.enter( rollFor(total) );
>                    }
>                    TextIO.put(total, 6);
>                    TextIO.put(stats.getMean(), 18);
>                    TextIO.put(stats.getStandardDeviation(), 19);
>                    TextIO.put(stats.getMax(), 14);
>                    TextIO.putln();
>                 }

> The body of the `for` loop processes one of the possible totals on a pair of dice, and it produces one line of output with the statistics for that total. A new `StatCalc` object is created for each execution of the `for` loop. This is necessary because we want separate statistics for each total. A single `StatCalc` object would just accumulate all the data into a single dataset.

> By the way, you might wonder what would happen if I had not eliminated the `getRollCountStats()` subroutine? In that case, the statistics data is generated in the subroutine and is used in the `main()` routine. So, the same `StatCalc` object has to be used in both routines. There are several ways to handle this. The variable, `stats`, could be a static member variable. Then it could simply be used in both routines. Alternatively, the `StatCalc` object could be passed as a parameter to the subroutine. Or, as a final alternative, the object could be created in the subroutine and sent back to the `main()` routine as a return value. Let's look at this last possibility. The subroutine would be:

>            static StatCalc getRollCountStats( int total ) {
>                StatCalc calc;         // An object to compute the statistics.
>                calc = new StatCalc();
>                for ( int i = 0; i < NUMBER_OF_EXPERIMENTS; i++ )
>                    calc.enter( rollFor(total) );
>                return calc;  // Send back the object, with the statistics.
>            }

> In the main program, this would be used as follows:

>            for ( int total = 2; total <= 12; total++ ) {
>               StatCalc stats;  // The stats for this total
>               stats = getRollCountStats( total ); // Get stats from subroutine.
>               TextIO.put(total, 6);
>               TextIO.put(stats.getMean(), 18);
>               TextIO.put(stats.getStandardDeviation(), 19);
>               TextIO.put(stats.getMax(), 14);
>               TextIO.putln();
>            }

> Note in particular that not every object variable needs to be initialized with a new object. In this case, an object is computed elsewhere. The variable, `stats`, is set to refer to that existing object.

> The Solution

>          public class DiceRollStats2 {

>              /*
>                  This program preforms the following type of experiment:
>                  Given a desired total roll, such as 7, roll a pair of
>                  dice until th given total comes up, and count how many
>                  rolls are necessary.  Now do the over and over, and
>                  find the average number of rolls.  The number of times
>                  the experiment is repeated is given by the constant,
>                  NUMBER_OF_EXPERIMENTS.  Several statistics are computed and
>                  printed out for each possible roll = 2, 3, ..., 12:
>                  the average number of rolls, the standard deviation,
>                  and the maximum number of rolls.
>              */

>             static final int NUMBER_OF_EXPERIMENTS = 10000;

>             private static PairOfDice dice = new PairOfDice();
>                      // A single pair of dice, which will be used for all
>                      // the experiments.

>             public static void main(String[] args) {

>                 TextIO.putln("Dice Total   Avg # of Rolls   Stand. Deviation   Max # of Rolls");
>                 TextIO.putln("----------   --------------   ----------------   --------------");

>                 for ( int total = 2;  total <= 12;  total++ ) {
>                    StatCalc stats;  // An object that will compute the statistics.
>                    stats = new StatCalc();
>                    for ( int i = 0; i < NUMBER_OF_EXPERIMENTS; i++ ) {
>                          // Do the experiment of counting the number of rolls
>                          // required to roll the desired total, and enter the
>                          // number of rolls into stats' dataset.
>                       stats.enter( rollFor(total) );
>                    }
>                    TextIO.put(total, 6);
>                    TextIO.put(stats.getMean(), 18);
>                    TextIO.put(stats.getStandardDeviation(), 19);
>                    TextIO.put(stats.getMax(), 14);
>                    TextIO.putln();
>                 }

>             } // end main

>             static int rollFor( int N ) {
>                      // Roll the dice repeatedly until the total on the
>                      // two dice comes up to be N.  N MUST be one of the numbers
>                      // 2, 3, ..., 12.  (If not, this routine will go into an
>                      // infinite loop!).  The number of rolls is returned.
>                 int rollCt = 0;  // Number of rolls made.
>                 do {
>                    dice.roll();
>                    rollCt++;
>                 } while ( dice.getTotal() != N );
>                 return rollCt;
>             }

>          }  // end class DiceRollStats2

> [ Exercises | Chapter Index | Main Index ]