> ### 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 are rolled before a given total comes up. It repeats this experiment 10000 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 ]