'How can I use a recursive loop to find the amount of times a value shows up between rolling any amount of dice with any amount of sides?
I am trying to write a function that prints out a dictionary that shows the specific amount of values a combination of same-sided dice can possibly roll.
Example output for three 6-sided dice
input: 6,3
Desired output: {3: 1, 4: 3, 5: 6, 6: 10, 7: 15, 8: 21, 9: 25, 10: 27, 11: 27, 12: 25, 13: 21, 14: 15, 15: 10, 16: 6, 17: 3, 18: 1}
Example output for four 8-sided dice
input: 8,4
desired output: {4: 1, 5: 4, 6: 10, 7: 20, 8: 35, 9: 56, 10: 84, 11: 120, 12: 161, 13: 204, 14: 246, 15: 284, 16: 315, 17: 336, 18: 344, 19: 336, 20: 315, 21: 284, 22: 246, 23: 204, 24: 161, 25: 120, 26: 84, 27: 56, 28: 35, 29: 20, 30: 10, 31: 4, 32: 1}
Here is my function that creates an empty dictionary for each combination:
def dice_range(dice_type,dice_count):
dice_dict = {i+1:0 for i in range(dice_type*dice_count) if i+1 >= dice_count}
return dice_dict
input: dice_range(8,3)
actual output: {3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0, 19: 0, 20: 0, 21: 0, 22: 0, 23: 0, 24: 0}
With that I am able to figure out how to solve for a specific number of dice_count of any dice_type(# of sides) Here is the solution for the first couple of examples:
dice_type = 6
dice_count = 3
temp = dice_range(dice_type,dice_count)
# for 3 dice of any number of sides
for x in range(1,dice_type+1):
for i in range(1,dice_type+1):
for j in range(1,dice_type+1):
for k,v in temp.items():
if x+i+j == k:
temp[k] +=1
dice_type = 8
dice_count = 4
temp = dice_range(dice_type,dice_count)
# for 4 dice of any number of sides
for y in range(1,dice_type+1):
for x in range(1,dice_type+1):
for i in range(1,dice_type+1):
for j in range(1,dice_type+1):
for k,v in temp.items():
if y+x+i+j == k:
temp[k] +=1
I hope that is enough context for the question.
Here is what I tried out, but for some reason the recursion is not working as I intended.
def dice_range(dice_type,dice_count):
dice_dict = {i+1:0 for i in range(dice_type*dice_count) if i+1 >= dice_count}
return dice_dict
def dice_value_calculator(dice_type,dice_count):
PREDICTION = dice_range(dice_type,dice_count)
# Tallies the number by 1 everytime it shows up in the loop.
def fill_dict(total):
for k in PREDICTION.keys():
if total == k:
PREDICTION[k] += 1
def loop(temp_dice_count,loop_total = 0):
for loop_i in range(1,(dice_type+1)):
# Base Case | if the number of dice(dice_count) reaches 0 that means it reached the end of the recursion
if temp_dice_count == 0:
fill_dict(loop_total)
print(PREDICTION)
loop_total = 0
# General Case / Recursive
else:
loop_total += loop_i
temp_dice_count -= 1
loop(temp_dice_count, loop_total)
loop(dice_count) # calls the loop function
return PREDICTION # returns the temp dictionary
print(dice_value_calculator(6,3))
This is the output I'm getting for three 6-sided dice
{3: 2, 4: 4, 5: 0, 6: 2, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 0, 18: 0}
Both the fill_dict() function and the dice_range() function work well on their own so it must be how I'm calling loop()
Any tips would be greatly appreciated. Please let me know if I need to clarify anything, this is my first time asking a question so I may have missed something.
Thanks in advance
Solution 1:[1]
You can use a mathematical formula for getting the count of such arrangements where lower bound, upper bound, and number of groups are described.
For the given case, we can take:
- Number of dice available = number of groups = k
- A die can have the least number as = 1
- A die can have the maximum number = Number of faces it has got = upper limit = m
Then, the dictionary needed can be obtained as:
from math import comb
def get_i(n,k,m):
for i in range(n+1):
if (n - k + i*m >= 0) and (n-k - i*m - m < 0):
return i
def s_nkm(n,k,m):
s=0
for r in range( get_i(n,k,m) + 1):
s+=(-1)**r * comb(k,r) * comb(n-r*m - 1, k-1)
return s
def get_dict(m,k):
d={}
for n in range(k, m*k + 1):
# n is total number of ones
d[n] = s_nkm(n,k,m)
return d
m,k = 8,4
print(get_dict(m,k))
Outputs:
{4: 1, 5: 4, 6: 10, 7: 20, 8: 35, 9: 56, 10: 84, 11: 120, 12: 161, 13: 204, 14: 246, 15: 284, 16: 315, 17: 336, 18: 344, 19: 336, 20: 315, 21: 284, 22: 246, 23: 204, 24: 161, 25: 120, 26: 84, 27: 56, 28: 35, 29: 20, 30: 10, 31: 4, 32: 1}
The mathematical equation is added below:

Here, grouping is done based on thinking that those indistinguishable items are ones(as we do in partitions)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
