# Compute the probabilities of getting each of the possible sums when throwing 2 dice, n times

I'm struggling with some coding-inexperience. The code I've written below, is extremely inconvenient and ugly to look at.

My question to you is: How can this be done more efficiently? The way I've chosen to do it, is rather inefficient. Pay attention to the def freq_2dice(n, N): section of the code, as well as the print statements. Those are the areas in which I need more efficiency as well as just nicer looking code.

The assignment is to create a function which records and stores each of the probabilities of getting each of the possible sums when throwing 2 dice, n times.

The rest of the code is comparing those probabilities to the exact probabilities.

from random import randint
import sys

def freq_2dice(n, N):
M, A, E, R, T, Y, U, I, O, P, D = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
for reps in xrange(N):
s = 0
for dice in xrange(n):
outcome = randint(1, 6)
s += outcome
if s==2:
M += 1
if s==3:
A += 1
if s==4:
E += 1
if s==5:
R += 1
if s==6:
T += 1
if s==7:
Y += 1
if s==8:
U += 1
if s==9:
I += 1
if s==10:
O += 1
if s==11:
P += 1
if s==12:
D += 1
return N*(float(M)/N), N*(float(A)/N), N*(float(E)/N), N*(float(R)/N), N*(float(T)/N), N*(float(Y)/N), N*(float(U)/N), N*(float(I)/N), N*(float(O)/N), N*(float(P)/N), N*(float(D)/N)

def chance_die():
frequencies = {}
for s in range(2, 13):
frequency = 0
for die1 in range(1, 7):
for die2 in range(1, 7):
if die1 + die2 == s:
frequency += 1
frequencies[s] = frequency
return frequencies

n = int(sys.argv[1])
N = int(sys.argv[2])

print 'No. of twos: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[0], freq_2dice(n, N)[0]/(N/100), chance_die()[2]/.36)
print 'No. of threes: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[1], freq_2dice(n, N)[0]/(N/100), chance_die()[3]/.36)
print 'No. of fours: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[2], freq_2dice(n, N)[0]/(N/100), chance_die()[4]/.36)
print 'No. of fives: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[3], freq_2dice(n, N)[0]/(N/100), chance_die()[5]/.36)
print 'No. of sixes: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[4], freq_2dice(n, N)[0]/(N/100), chance_die()[6]/.36)
print 'No. of sevens: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[5], freq_2dice(n, N)[0]/(N/100), chance_die()[7]/.36)
print 'No. of eights: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[6], freq_2dice(n, N)[0]/(N/100), chance_die()[8]/.36)
print 'No. of nines: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[7], freq_2dice(n, N)[0]/(N/100), chance_die()[9]/.36)
print 'No. of tens: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[8], freq_2dice(n, N)[0]/(N/100), chance_die()[10]/.36)
print 'No. of elevens: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[9], freq_2dice(n, N)[0]/(N/100), chance_die()[11]/.36)
print 'No. of twelves: %d, probability: %.2f, expected: %.2f' % (freq_2dice(n, N)[10], freq_2dice(n, N)[0]/(N/100), chance_die()[12]/.36)

MacBook-Air:python Leroy\$ python freq_2dice.py 2 100000
No. of twos: 2680, probability: 2.80, expected: 2.78
No. of threes: 5612, probability: 5.51, expected: 5.56
No. of fours: 8169, probability: 8.43, expected: 8.33
No. of fives: 11099, probability: 10.96, expected: 11.11
No. of sixes: 13827, probability: 13.91, expected: 13.89
No. of sevens: 16610, probability: 16.51, expected: 16.67
No. of eights: 13808, probability: 13.72, expected: 13.89
No. of nines: 10947, probability: 11.22, expected: 11.11
No. of tens: 8249, probability: 8.35, expected: 8.33
No. of elevens: 5540, probability: 5.59, expected: 5.56
No. of twelves: 2805, probability: 2.74, expected: 2.78

'''


First thing to note is that since you only check up to s=12, your code won't work for more than 2 dice. What you really need is a list so how high you go can be a variable. Also N*(float(M)/N) seems the same as float(M), so I'm not sure what you're trying to do there.

def freq_2dice(n, N):
dice_list = [0] * (n*6+1)
for reps in xrange(N):
s = 0
for dice in xrange(n):
outcome = randint(1, 6)
s += outcome
dice_list[s] += 1
return dice_list


I rewrote your freq_2dice using an list. My version is a little different because it'll return 0 through 6*n instead of 2 through 12. dice_list = [0] * (n*6+1) lets me start with a list populated with all zeroes that is n*6+1 long (since it starts with 0 but I still want to include 6*n in the list)

Next, you're running the really expensive part of your program (freq_2dice) 22 times! You're actually running it twice every line, so that the number of 2's won't match the corresponding probability because those are two different runs. Running it the first time provides all of the information you need.

Instead of all your print statements, a loop would be good there too. So first, I'm going to run each function just ONCE instead of repeatedly and I'll store the results. Then I'll use a loop for the print statement (which could let you make the print range dynamic for more than 2 dice as well, but I'll just keep it simple here)

freq_2_dice_results = freq_2dice(n, N)
dice_chance_results = chance_die()
for dice_value in range(2, 13):
print 'No. of %d: %d, probability: %.2f, expected: %.2f' % (
dice_value,
freq_2_dice_results[dice_value],
float(freq_2_dice_results[dice_value])/(N/100),
dice_chance_results[dice_value]/.36)


I hope that gives you a good place to start.

• Thanks a lot! You really helped me out. One question: I'm guessing that if I wanted to do it for any number of dice thrown, I would only need to change the segments with range(2, 13)? Am I right? (this is with the code segments you provided, not with my flawed code) – FrenziedMango Nov 20 '16 at 15:35
• Yup, you'd want to replace 2 and 13 with equations based on n. You'd also need to setup chance_dice to take a variable number of dice too. – Dan Nov 21 '16 at 22:31