### 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
]