当前位置: 首页 > 知识库问答 >
问题:

如何计算n个滚动的m面骰子之和为某一值或更大的概率

后化
2023-03-14

我正试图编写一些Python代码来计算n个滚动的m边公平骰子之和成为某个值或更大值的概率。输入是所有骰子卷的总和、所做的卷数和骰子上的边数。输出是掷骰子总数达到或超过该值的概率百分比。

我的计算基于我在这篇论文中找到的方程,并对任何被轧制多次的单面模具进行缩放:https://digitalscholarship.unlv.edu/cgi/viewcontent.cgi?article=1025

我做了一些“有效”的代码,但是当骰子有很多面时速度非常慢,所以只对20面或更少的骰子有用。

import numpy as np

def probability_calculator(roll_total, num_of_rolls, dice_faces):       

    if num_of_rolls == 0:
        probability = 100    
    elif num_of_rolls == 1:
        probability = (dice_faces + 1 - roll_total) * 100/dice_faces    
    else:
        inverse = (dice_faces ** num_of_rolls) ** -1
        side_list = np.linspace(1, dice_faces, dice_faces)
        expanded_list = np.zeros(dice_faces * num_of_rolls)         
        stacked_side_list = side_list   

        for i in range(num_of_rolls - 1):
            stacked_side_list = np.vstack((stacked_side_list, side_list))
            
        index_array = np.zeros(num_of_rolls, dtype=int)
            
        while True:                
            value = 0

            for i in range(num_of_rolls):                    
                value = value + stacked_side_list[i][index_array[i]]
                
           expanded_list[int(value) - 1] += 1

           if sum(index_array) == (dice_faces - 1) * num_of_rolls:
               break

           for i in range(num_of_rolls):  
               if index_array[i] == dice_faces - 1:
                   index_array[i] = 0          
               else:
                    index_array[i] += 1                        
                    break

       probability = inverse * sum(expanded_list[roll_total - 1:]) * 100
  
   return probability

如你所见,这是非常低效的代码,如果你只滚动四个100面的模具,你将不得不迭代100^4 = 100,000,000次......

我很确定有一些数学公式可以简化这段代码,使其运行速度快很多个数量级,但数学不是我最喜欢的科目,我不知道有任何公式或Python函数可以提供帮助。

共有1个答案

宇文鸿畴
2023-03-14

快速看了一眼纸,被公式吓了一跳。以一种可能不同的方式实施,只需计算达到不同总数的频率:

from functools import lru_cache

@lru_cache(None)
def sum_freq(total, rolls, faces):
        if not rolls:
            return not total
        return sum(sum_freq(total - die, rolls - 1, faces)
                   for die in range(1, faces + 1))

def probability_calculator(roll_total, num_of_rolls, dice_faces):
    return sum_freq(roll_total, num_of_rolls, dice_faces) / dice_faces**num_of_rolls

您的“四个100面模具”演示:

prob_314 = probability_calculator(314, 4, 100)
prob_any = sum(probability_calculator(total, 4, 100)
               for total in range(1, 401))
print(f'{prob_314:%}')
print(f'{prob_any:%}')

输出:

0.113564%
100.000000%

10个100面骰子的输出:

0.050065%
100.000000%

42个这样的100面骰子的输出:

0.000000%
100.000000%

在线试试吧!

 类似资料:
  • 我试图创建一个程序,掷2个骰子,给出和的数量,然后将它们相加。我得到了骰子的随机数,但是当它们相加(总和)时,总数是不正确的。 我尝试过更改,,我已经将总和更改为,但总和总是出错。如果有人可以查看代码,看看我是否将其他所有内容放在正确的位置。提前感谢。 这应该是掷骰子1,给我骰子1的面值,然后给我骰子2的面值,然后给我两个骰子的总数。

  • 每次我运行程序,相同的数字为骰子出现。此外,我的while语句最终显示用户和计算机都赢了。我也只想有回合上升到五,然后程序显示游戏的获胜者。我如何获得它,以便只有数字较高的玩家赢得这一轮。

  • 题目链接 Lintcode 题目描述 把 n 个骰子扔在地上,求点数和为 s 的概率。 解题思路 动态规划 使用一个二维数组 dp 存储点数出现的次数,其中 dp[i][j] 表示前 i 个骰子产生点数 j 的次数。 空间复杂度:O(N2) // java public List<map.entry> dicesSum(int n) { final int face = 6; fi

  • 问题内容: 我需要一种方法来计算Python中长整数的第n个根。 我试过了,但是不起作用: OverflowError:long int太大,无法转换为float 有任何想法吗? 长整数是指真正的长整数,例如: 11968003966030964356885611480383408833172346450467339251 1960931441410456834630852911156774884

  • 一、题目 把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s 的所有可能的值出现的概率。 二、解题思路 解法一:基于通归求解,时间效率不够高。 先把n个骰子分为两堆:第一堆只有一个,另一个有n- 1 个。单独的那一个有可能出现从1 到6 的点数。我们需要计算从1 到6 的每一种点数和剩下的n-1 个骰子来计算点数和。接下来把剩下的n-1个骰子还是分成两堆,第一堆只有一个, 第二堆

  • 买支笔 示例输入 5d10 7 10d6*1d3 所以我试着跟着 但显然,这只适用于单输入,如5d7。我做错了什么