Reputation: 11
In the board game Catan, you throw 2 six-sided dice every turn, the possible results go from 2 to 12 and the distribution of the sum should be something like this in 100,000 throws:
***CATAN DICE***
2 *****5998
3 ********8170
4 ********8170
5 **********10299
6 ************12283
7 **************14341
8 ************12331
9 **********10149
10 ********8090
11 ******6033
12 ****4068
However I only get this result when the dice is seven-sided from 0 to 6 using randint(0, 6)
.
When I use randint(1,6)
the distribution is the following:
***CATAN DICE***
2 **2771
3 *****5560
4 *****5560
5 ********8410
6 ***********11088
7 **************14132
8 ****************16491
9 *************13768
10 ***********11163
11 ********8220
12 *****5616
Which is wrong, the 8 is not more likely to occur in a pair of six sided dice.
¿Is something wrong in my code?, ¿could it be related to the way randint()
works?
This is my code:
from random import randint
print("***CATAN DICE***")
normal = [0,0,0,0,0,0,0,0,0,0,0]
for i in range(0, 100000):
a=randint(0, 6)
b=randint(0, 6)
throw = a+b
if throw == 2:
normal[0]+=1
if throw == 3:
normal[1]+=1
if throw == 3:
normal[2]+=1
if throw == 4:
normal[3]+=1
if throw == 5:
normal[4]+=1
if throw == 6:
normal[5]+=1
if throw == 7:
normal[6]+=1
if throw == 8:
normal[7]+=1
if throw == 9:
normal[8]+=1
if throw == 10:
normal[9]+=1
if throw == 11:
normal[10]+=1
i=0
j=0
for i in range(len(normal)):
print(i+2, end = " ")
for j in range(int(normal[i]/1000)):
print("*",end="")
print(f"{normal[i]}\n")
Upvotes: 1
Views: 232
Reputation: 19855
You made your code more complex than it need be, and in the process introduced some bugs. I eliminated the chain of if
statements by calculating the index to be updated directly from the outcome throw
. I eliminated looping to get the stars one-by-one, used rounding rather than integer truncation (floor) to get the number of stars, and right-justified the value of the sum. I also grouped the code into initialization, generation, and output stages to make it easy to read and easy to alter the number of trials being run. Without further ado, the code:
from random import randint
# initialize
n = 100000
count = [0 for _ in range(11)] # less prone to a manual miscount error
# generate : no need for if's, calculate index directly from throw outcome
for i in range(n):
throw = randint(1, 6) + randint(1, 6)
count[throw - 2] += 1
# output
print("***CATAN DICE***\n")
for i in range(len(count)):
stars = "" + "*" * round(count[i] / (n // 100))
print(f"{i + 2 :>2} " + stars + f"{count[i]}")
which produces output such as:
***CATAN DICE***
2 ***2741
3 ******5637
4 ********8210
5 ***********11099
6 **************14068
7 *****************16659
8 **************13821
9 ***********11074
10 ********8365
11 ******5500
12 ***2826
It's very easy to modify this if you want die outcomes from 0 to 6 rather than from 1 to 6.
Finally, just for fun, here's a more generalized implementation so you can play around with number of dice and ranges on the dice.
from random import randint
# initialize
n = 100000 # trials
num_dice = 2 # number of dice
# low and high values for a die
die_lo = 1
die_hi = 6
min_outcome = num_dice * die_lo
num_outcomes = num_dice * die_hi - min_outcome + 1
# generate : no need for if's, calculate index directly from throw outcome
count = [0 for _ in range(num_outcomes)]
for i in range(n):
throw = sum(randint(die_lo, die_hi) for _ in range(num_dice))
count[throw - min_outcome] += 1
# output
print("***CATAN DICE***\n")
for i in range(num_outcomes):
stars = "" + "*" * round(count[i] / (n // 100))
print(f"{i + min_outcome :>3} " + stars + f"{count[i]}")
I think this illustrates the benefit of not hardwiring a chain of if
statements.
Upvotes: 2