[ Exercises | Chapter Index | Main Index ]

## Solution for Programmming Exercise 4.4

This page contains a sample solution to one of the exercises from Introduction to Programming Using Java.

### Exercise 4.4:

This exercise builds on Exercise 4.3. Every time you roll the dice repeatedly, trying to get a given total, the number of rolls it takes can be different. The question naturally arises, what's the average number of rolls to get a given total? Write a function that performs the experiment of rolling to get a given total 10000 times. The desired total is a parameter to the subroutine. The average number of rolls is the return value. Each individual experiment should be done by calling the function you wrote for Exercise 4.3. Now, write a main program that will call your function once for each of the possible totals (2, 3, ..., 12). It should make a table of the results, something like:

    Total On Dice     Average Number of Rolls
    -------------     -----------------------
           2               35.8382
           3               18.0607
           .                .
           .                .

Discussion

The solution uses the subroutine, rollFor, from Exercise 4.3. That subroutine will throw an exception if its parameter is not valid. However, in my program, I know that the values that I pass to the rollFor subroutine are valid and that no exception will occur. So, there is no need to use a try..catch statement to handle the exception.

The main() program simply prints a heading for the output, then uses a for loop to compute and print the data for each of the possible rolls from 2 to 12. It is not difficult to write it, with a little care to get the formatting right (using formatted output).

The only thing left is to write a function to find the average number of rolls to get a given total on the dice. The average will be a real number, so the return type of the function is double. The subroutine has a parameter of type int that specifies the number we are rolling for. I'll call the parameter "roll". An algorithm for the subroutine is

    Let totalRolls = 0
    Repeat 10000 times:
       Call rollFor(roll) to run the experiment once
       Add the returned value to totalRolls
    Compute the average by dividing totalRolls by 10000
    Return the average

In my program, I use a named constant, NUMBER_OF_EXPERIMENTS, to specify the number of experiments to be performed. This constant replaces the value 10000, making it easier to read the program and easier to change the number of experiments if I decide I want to do more experiments or fewer. This gives the subroutine:

    static double getAverageRollCount( int roll ) {
        int rollCountThisExperiment;  // Number of rolls in one experiment.
        int rollTotal;  // Total number of rolls in all the experiments.
        double averageRollCount;  // Average number of rolls per experiment.
        rollTotal = 0;
        for ( int i = 0;  i < NUMBER_OF_EXPERIMENTS;  i++ ) {
           rollCountThisExperiment = rollFor( roll );
           rollTotal += rollCountThisExperiment;
        }
        averageRollCount = ((double)rollTotal) / NUMBER_OF_EXPERIMENTS;
        return averageRollCount;
    }

It is important that roll be in the range of possible totals on a pair of dice. If it is not, the program will enter an infinite loop in the rollFor() subroutine. In this case, I have chosen not to throw an exception if the parameter is invalid, since I know that the actual parameter is valid in this program.

Note that when the average is computed, a type-cast is used to convert rollTotal to type double. This is necessary since rollCount and NUMBER_OF_EXPERIMENTS are integers, and the computer would evaluate the quotient rollCount / NUMBER_OF_EXPERIMENTS as an integer.

By the way, this subroutine could be substantially abbreviated at the expense of being somewhat less easy to understand:

    static double getAverageRollCount( int roll ) {
        int rollTotal = 0;  // Total number of rolls in all the experiments.
        for ( int i = 0;  i < NUMBER_OF_EXPERIMENTS;  i++ )
           rollTotal += rollFor( roll );
        return ((double)rollTotal) / NUMBER_OF_EXPERIMENTS;
    }

The Solution

    /**
     * This program preforms the following type of experiment:  Given a desired
     * total roll, such as 7, roll a pair of dice until the 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.  The average is
     * computed and printed out for each possible roll = 2, 3, ..., 12.
     */

    public class DiceRollStats {

       /**
        * The number of times that the the experiment "roll for a given total"
        * is to be repeated.  The program performs this many experiments, and
        * prints the average of the result, for each possible roll value,
        */
       static final int NUMBER_OF_EXPERIMENTS = 10000;

       public static void main(String[] args) {
           double average;  // The average number of rolls to get a given total.
           System.out.println("Total On Dice     Average Number of Rolls");
           System.out.println("-------------     -----------------------");
           for ( int dice = 2;  dice <= 12;  dice++ ) {
              average = getAverageRollCount( dice );
              System.out.printf("%10d%22.4f\n", dice, average);
                 // Use 10 spaces to output dice, and use 22 spaces to output
                 // average, with 4 digits after the decimal.
           }
       }

       /**
        * Find the average number of times a pair of dice must be rolled to get
        * a given total.  The experiment of rolling for the given total is
        * repeated NUMBER_OF_EXPERIMENTS times and the average number of rolls
        * over all the experiments is computed.
        * Precondition:  The given total must be be between 2
        * and 12, inclusive.
        * @param roll the total that we want to get on the dice
        * @return the average number of rolls that it takes to get the specified
        *    total
        */
       static double getAverageRollCount( int roll ) {
           int rollCountThisExperiment;  // Number of rolls in one experiment.
           int rollTotal;  // Total number of rolls in all the experiments.
           double averageRollCount;  // Average number of rolls per experiment.
           rollTotal = 0;
           for ( int i = 0;  i < NUMBER_OF_EXPERIMENTS;  i++ ) {
              rollCountThisExperiment = rollFor( roll );
              rollTotal += rollCountThisExperiment;
           }
           averageRollCount = ((double)rollTotal) / NUMBER_OF_EXPERIMENTS;
           return averageRollCount;
       }

       /**
        * Simulates rolling a pair of dice until a given total comes up.
        * Precondition:  The desired total is between 2 and 12, inclusive.
        * @param N the total that we want to get on the dice
        * @return the number of times the dice are rolled before the
        *    desired total occurs
        * @throws IllegalArgumentException if the parameter, N, is not a number
        *    that could possibly come up on a pair of dice
        */
       static int rollFor( int N ) {
           if ( N < 2 || N > 12 )
              throw new IllegalArgumentException("Impossible total for a pair of dice.");
           int die1, die2;  // Numbers between 1 and 6 representing the dice.
           int roll;        // Total showing on dice.
           int rollCt;      // Number of rolls made.
           rollCt = 0;
           do {
              die1 = (int)(Math.random()*6) + 1;
              die2 = (int)(Math.random()*6) + 1;
              roll = die1 + die2;
              rollCt++;
           } while ( roll != N );
           return rollCt;
       }

    }  // end DiceRollStats

[ Exercises | Chapter Index | Main Index ]