3

The following code computes the probability distribution of outcomes of rolling two dice with a variable number of equal sides:

def compute_probability_distribution(sides):
  dist = {x+y: 0 for x in range(1, sides+1) for y in range(1, sides+1)}
  for die_1 in range(1, sides+1):
    for die_2 in range(1, sides+1):
      dist[die_1+die_2] = dist[die_1+die_2] + 1
  probs = dist.items()
  print "Prob dist: ", probs

E.g., for ordinary 6-sided dice the prob dist is [(2,6),(3,2),(4,3),(5,4),(6,5),(7,6),(8,5),)(9,4),(10,3),(11,2),(12,1)], where the first element of each tuple is the sum of the 2 dice, and the second element is the number of ways it can occur on one roll. Can anyone tell me how to sort the above prob dist list by the second element of each tuple so I can output the top (1 or 3) most likely occurrences? I am thinking of using the built-in list sort with some sort of comparison function.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
CElliott
  • 151
  • 4

3 Answers3

2
probs = [(2,6),(3,2),(4,3),(5,4),(6,5),(7,6),(8,5),(9,4),(10,3),(11,2),(12,1)]

>>> sorted(probs, key=lambda x: x[1])  # x[1] is second element of tuple pair.
[(12, 1),
 (3, 2),
 (11, 2),
 (4, 3),
 (10, 3),
 (5, 4),
 (9, 4),
 (6, 5),
 (8, 5),
 (2, 6),
 (7, 6)]
Alexander
  • 105,104
  • 32
  • 201
  • 196
2

You can do it with a nested comprehensions but you can also compute the most common values by hand if you know the number of sides.

In order of increasing probability:

  • 2 and sides+sides which only have one "chance".
  • Then 3 and sides+nsides-1 which have 2.
  • 4 and sides+nsides-2 have 3
  • ...
  • Finally sides+1 has the highest probability which is just sides.

If you don't trust me look at the probability distribution for different numbers of sides.

So to get the 3 most common values, you can simply calculate them based on the number of sides:

def compute_probability_distribution(sides):
    print([(sides+1, sides), (sides, sides-1), (sides+2, sides-1)])

However, that only works for dices with at least 2 sides. For a single side dice the result will be weird with this function.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • 1
    Your right; the probabilities form Pascal's triangle, which has the apex in the middle. I saw that, but did not think of using it since I wanted to see how sort (or sorted) worked. Totally brilliant solution, though. – CElliott Aug 06 '17 at 20:17
1

I would simply use the data structure that is designed for this: a Counter:

from collections import Counter

def compute_probability_distribution(sides):
  dist = Counter(die_1 + die_2 for die_1 in range(1, sides+1)
                               for die_2 in range(1, sides+1))
  probs = dist.most_common(3)
  print "Prob dist: ", probs

For two 6-dices, this then will produce:

>>> compute_probability_distribution(6)
Prob dist:  [(7, 6), (6, 5), (8, 5)]

So we obtained six times a sum of seven; five times a sum of six; and five times a sum of eight.

In case you want to make the number of dices arbitrary, you can use:

from collections import Counter
from itertools import product

def compute_probability_distribution(sides,ndices=2,common=3):
  dist = Counter(sum(d) for d in product(range(1,sides+1),repeat=ndices))
  probs = dist.most_common(common)
  print "Prob dist: ", probs

So now we can calculate the 10 most common sums when we roll three 5-dices:

>>> compute_probability_distribution(5,3,10)
Prob dist:  [(9, 19), (8, 18), (10, 18), (7, 15), (11, 15), (6, 10), (12, 10), (5, 6), (13, 6), (4, 3)]
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Your solution using Counter is interesting, but it misses the fact that 2 and 6 are equiprobable. – CElliott Aug 06 '17 at 20:20
  • @CElliott: mind that we here use *three* dices, not two. How can you generate 2 with three 5-dices? – Willem Van Onsem Aug 06 '17 at 20:21
  • In the original stmt of the problem probs was given as [(2,6),(3,2),(4,3), ...] . The (2,6) was a typo; my bad, sorry. Hence, your answer for a 6-sided die was correct. The world makes sense after all. – CElliott Aug 08 '17 at 13:27