Python 角色扮演笔中骰子概率的动态规划;纸牌游戏

Python 角色扮演笔中骰子概率的动态规划;纸牌游戏,python,algorithm,Python,Algorithm,黑暗之眼是一款流行的幻想角色扮演游戏,在德国相当于龙与地下城。在这个系统中,角色具有许多属性和才能。每个天赋都有几个相关属性,为了进行天赋检查,玩家为每个相关属性掷d20(20面骰子)。每次掷骰结果超过属性得分时,掷骰和属性之间的差值相加。如果此差值总和(超出部分)大于天赋值,则检查失败 本教程的第一项任务是编写一个函数,该函数将与人才以及人才排名相关联的属性分数列表作为输入,并返回测试成功的概率。您的算法必须能有效地处理任意长度的列表。 提示:首先编写一个函数,计算超出部分的概率分布。使用动态

黑暗之眼是一款流行的幻想角色扮演游戏,在德国相当于龙与地下城。在这个系统中,角色具有许多属性和才能。每个天赋都有几个相关属性,为了进行天赋检查,玩家为每个相关属性掷d20(20面骰子)。每次掷骰结果超过属性得分时,掷骰和属性之间的差值相加。如果此差值总和(超出部分)大于天赋值,则检查失败

本教程的第一项任务是编写一个函数,该函数将与人才以及人才排名相关联的属性分数列表作为输入,并返回测试成功的概率。您的算法必须能有效地处理任意长度的列表。

提示:首先编写一个函数,计算超出部分的概率分布。使用动态规划可以有效地实现这一点


这是什么意思?我解决了背包问题,没有任何重大问题(0/1和无界),但我不知道该怎么办

首先要解决的最小问题是排名1,单个属性为12(使用上面的示例)-通过概率为12/20,对吗?那么排名2是13/20,排名3是14/20


我走对了吗?我觉得我可能误解了实际的游戏规则

这里有一点涉及概率和多项式的数学知识。例如,滚动d6可以用多项式表示

x + x^2 + x^3 + x^4 + x^5 + x^6
-------------------------------
               6                ,
由于滚动A1的概率为1/6(x/6项),滚动A2的概率为1/6(x^2/6项),等等。滚动d20并计算超出13的部分将是

13 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7
------------------------------------------
                    20                     .
这种表示法的要点是,如果Y是多项式为p(x)的随机变量,Z是多项式为q(x)的随机变量,那么Y+Z的多项式就是p(x)q(x)的乘积。例如,将d6多项式自身相乘,我们得到2d6多项式

x^2 + 2 x^3 + 3 x^4 + 4 x^5 + 5 x^6 + 6 x^7 + 5 x^8 + 4 x^9 + 3 x^10 + 2 x^11 + x^12
------------------------------------------------------------------------------------
                                         36                                          ,
这应该是正确的分配

这里的蛮力算法对应于将两个线性多项式相乘的firsts-outers-inners-lasts(FOIL)规则的广义版本,其中,对于每个多项式因子的一个项的每个可能选择,我们将乘积添加到最终和中。这是低效的,因为,例如,如果我们试图通过检查((1+x)/2)^n来计算n枚硬币的人头分布,我们最终将求和2^n项


所提到的动态规划算法是计算部分积的更合理的方法。例如,我们计算((1+x)/2)^2=(1+2x+x2)/4,然后(1+2x+x2)/4(1+x)/2=(1+3x+3x^2+1)/8,等等。所以问题是:你有多少种方法可以使用属性12、13和12以及天赋7。假设你知道第一个骰子的结果,假设是11。然后问题就归结为属性13和12以及天赋7的掷骰方式。现在用不同的第一卷试试,假设你第一次卷了14卷。你已经超过了2,所以现在的问题是你可以用属性13和12以及天赋5掷多少骰子。现在试试第一卷20。现在的问题是,使用属性13和12以及天赋-1(在最后一种情况下,显然是0)可以使用多少种方式进行掷骰。

对值为k的属性进行单个掷骰是一个随机变量,它取值0,1,2,3,…,20-k,概率为k/20,1/20,1/20

您可以将其表示为大小为21-k的数组,概率作为数组中的值

如果有两个(独立)随机变量X1和X2,则表示其和的随机变量为:

P(X1+X2=n) = sum(i=0 to n)P(X1=i)*P(X2=n-i)
您可以迭代地使用它来计算所有属性卷之和的分布。然后,您可以通过将最终分布中的概率相加到值S(保存卷值)来找到保存卷的概率

你可以做的一个巧妙的优化就是不要存储任何高于S值的概率,因为它们从未被使用过。这仅仅意味着将数组的大小限制为S+1并进行边界检查

把所有这些放在一起就得到了这段代码。
multiply
函数的复杂度为O(len(a1)*len(a2)),但由于a1的长度始终为S+1,a2的长度最多为21,因此它的复杂度为O(S)。总的来说,这使代码的复杂性为O(nS),其中n是您拥有的属性数。我已经包含了一些针对属性[5,10]的测试运行代码

def attribute_dist(k):
    return [k/20.0] + [1/20.0] * (20-k)

def multiply(a1, a2):
    result = [0] * len(a1)
    for n in xrange(len(a1)):
        for i in xrange(len(a2)):
            if 0 <= n - i < len(a1):
                result[n] += a1[n-i] * a2[i]
    return result

def saving_throw_probability(attributes, S):
    d = [1.0] + [0] * S
    for a in attributes:
        d = multiply(d, attribute_dist(a))
    return sum(d)

for i in xrange(30):
    print i, saving_throw_probability([5, 10], i)
def属性_dist(k):
返回[k/20.0]+[1/20.0]*(20-k)
def倍增(a1、a2):
结果=[0]*len(a1)
对于x范围内的n(len(a1)):
对于x范围内的i(len(a2)):

如果为0,则想象只有1个属性。超出部分为0的概率是多少?1.2.3? … 现在假设还有第二个属性。给定第一个属性的概率,两次测试后超出的概率是多少?1.2.3? …通过一个属性(12)且等级为1的概率为13/20:对于13的骰子掷骰,超出的概率为1;我理解逻辑,但不知道如何用动态规划来计算概率。我可以做第一行(即,排名1是13/20,排名2是14/20,排名7是19/20),但当我添加另一个模具时,我如何计算它。我在电子表格上做了这项工作,发现在等级7时,技能等级12和13的两个属性的通过概率为88%,但我找不到任何动态规划网格的公式来解决每个步骤。>一个属性(12)和等级1的通过概率为13/20:掷骰子13,超出的概率为1;它也必须被计算在内。你的意思是我需要数一数多余的,所以在那个地方保留一个元组