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