Description
In this project you will write a Python program that simulates a dice game. The number of sides on each
die, the number of dice, and the number of simulations to perform will all be taken from user input. After
each simulation, your program will calculate the sum of the numbers on the dice. Then, after the specified
number of simulations, your program will produce an estimate of the probability of each possible sum. This
is a simple version of a well known computational technique known as Monte Carlo. Begin by carefully
studying the example DiceProbabilities.py posted on the class webpage. Your program will be a
direct generalization of that example, and will be called Probability.py.
The Monte Carlo method was invented by scientists working on the atomic bomb in the 1940s. They named
their technique for the city in Monaco famed for its casinos. The core idea is to use randomly chosen inputs
to explore the behavior of a complex dynamical system. These scientists faced difficult problems of
mathematical physics, such as neutron diffusion, that were too complex for a direct analytical solution, and
must therefore be evaluated numerically. They had access to one of the earliest computers (ENIAC), but
their models involved so many dimensions that exhaustive numerical evaluation was prohibitively
slow. Monte Carlo simulation proved to be surprisingly effective at finding solutions to these
problems. Since that time, Monte Carlo methods have been applied to an incredibly diverse range of
problems in science, engineering, and finance. In our case, a pure analytical solution is possible for the
probabilities that we seek, but since this is not a class in probability theory, we will take the
computational/experimental approach. You can find a very interesting history of early computing
machines, the Monte Carlo Method, and the development of the atomic bomb in the book Turing’s
Cathedral by George Dyson. Follow the link
https://en.wikipedia.org/wiki/Monte_Carlo_method
for an article on Monte Carlo methods.
A normal six-sided die is a symmetrical cube that, when thrown, is equally likely to land with any of it’s six
faces up (provided its mass distribution is uniform.) By labeling its faces with the numbers 1-6, we have a
physical device capable generating random numbers in the set {1, 2, 3, 4, 5, 6}. It is possible to make
perfectly symetrical dice in the shape of any of the so-called Platonic Solids, whose number of sides are 4
(Tetrahedron), 6 (Cube), 8 (Octahedron), 12 (dodecahedron), and 20 (Icosahedron).
2
See https://www.mathsisfun.com/geometry/platonic-solids-why-five.html for a nice explanation as to why
these are the only perfectly symmetrical shapes possible for dice. For purposes of this project however, we
shall assume it is possible to make dice with any number of faces in such a way that each face is equally
likely to land in the up position. To simulate a throw of an k-sided die in Python, use the randrange()
function belonging to the random module, which was discussed in class and illustrated in the example
DiceProbability.py.
Your program will include a function called throwDice() with heading
def throwDice(m, k):
that simulates a throw of m independent and symmetrical k-sided dice, and returns the result in a m-tuple.
The main section of your program will prompt for, and read three quantities: the number of dice, the number
of sides on each die, and the number of simulations (or throws) to perform. These prompts will be robust,
in that, if the user enters an integer less than 1 for the number of dice, or an integer less than 2 for the
number of sides on each die, or an integer less than 1 for the number of simulations, then your program will
continue to prompt until adequate values are entered. Your program is not required to handle non-integer
input like floats or general strings.
Once these values have been entered by the user, your program will perform the specified number of
simulations, recording the frequency of each possible sum as it goes. To do this you must first calculate
the range of possible sums, and create a list of appropriate length. If you call this list frequency[], for
instance, then by the time the simulations are complete, frequency[i] will be the number of simulations
in which the sum of the dice was i. Again, emulate the example DiceProbability.py to accomplish
this. Calculate the relative frequency for each possible sum (the number of simulations resulting in that
sum, divided by the total number of simulations). Also calculate the experimental probability for each sum
(the relative frequency expressed as a percent.) Print out these quantities in a table formatted as in the
sample runs below.
$ python Probability.py
Enter the number of dice: 3
Enter the number of sides on each die: 6
Enter the number of trials to perform: 10000
Sum Frequency Relative Frequency Experimental Probability
———————————————————————-
3 45 0.00450 0.45 %
4 126 0.01260 1.26 %
5 281 0.02810 2.81 %
6 494 0.04940 4.94 %
7 677 0.06770 6.77 %
8 968 0.09680 9.68 %
9 1191 0.11910 11.91 %
10 1257 0.12570 12.57 %
11 1257 0.12570 12.57 %
12 1164 0.11640 11.64 %
13 932 0.09320 9.32 %
14 683 0.06830 6.83 %
15 469 0.04690 4.69 %
16 282 0.02820 2.82 %
17 122 0.01220 1.22 %
18 52 0.00520 0.52 %
$
3
The $ here represents the Unix (or other) command line prompt. Note the blank lines before, after and
within program output. The following sample run shows what happens when the user enters invalid
parameters.
$ python Probability.py
Enter the number of dice: -1
The number of dice must be at least 1
Please enter the number of dice: 4
Enter the number of sides on each die: 1
The number of sides on each die must be at least 2
Please enter the number of sides on each die: 7
Enter the number of trials to perform: -1
The number of trials must be at least 1
Please enter the number of trials to perform: 10000
Sum Frequency Relative Frequency Experimental Probability
———————————————————————-
4 6 0.00060 0.06 %
5 18 0.00180 0.18 %
6 52 0.00520 0.52 %
7 83 0.00830 0.83 %
8 166 0.01660 1.66 %
9 273 0.02730 2.73 %
10 346 0.03460 3.46 %
11 469 0.04690 4.69 %
12 630 0.06300 6.30 %
13 738 0.07380 7.38 %
14 836 0.08360 8.36 %
15 930 0.09300 9.30 %
16 930 0.09300 9.30 %
17 985 0.09850 9.85 %
18 844 0.08440 8.44 %
19 737 0.07370 7.37 %
20 589 0.05890 5.89 %
21 526 0.05260 5.26 %
22 326 0.03260 3.26 %
23 238 0.02380 2.38 %
24 124 0.01240 1.24 %
25 86 0.00860 0.86 %
26 49 0.00490 0.49 %
27 13 0.00130 0.13 %
28 6 0.00060 0.06 %
$
To get full credit, your output must be formatted exactly as above. See the example FormatNumbers.py
on the class webpage to see how this might be accomplished. If you seed your random number generator
with the integer 237, then your numbers should match mine exactly. You should experiment with other
seeds, and with no seed, but when you submit your program, use the seed 237. This will facilitate automated
grading of the project.
What to turn in
Submit the file Probability.py to the assignment name pa6 in the usual way. As always, start early and
ask questions if anything is not clear.