Solution for Programming 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
. .
. .
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:
public 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;
}
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:
public 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;
}
/**
* 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 that 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,
*/
public 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 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
*/
public 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
*/
public 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