[ 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 performs 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 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 ]