加快风险战争骰子滚动模拟

时间:2014-05-27 09:25:15

标签: python performance dice

朋友和我想知道在棋盘游戏风险中各种情况下获胜的几率是多少,其中包括对分为地区的类似地球的董事会的世界大战。

对于那些不熟悉风险的人:

在游戏的每个回合中,攻击者都可以决定在棋盘上入侵防守者的国家。攻击者和后卫选择用于战斗的骰子数量。例如,攻击者可以在某些情况下决定用3个骰子进行攻击,而后卫可能会选择用2个骰子进行防御。

Attacker rolls 3 dice and gets 6,4,1
Defender rolls 2 dice and gets 6,3

If the same number is rolled, defender always wins, so in this situation,
 we compare the attacker's two highest rolls against the defender's.
The defender's 6 beats the attacker's 6 and
 the attacker's 4 beats the defender's 3.

在这种情况下,每一方都会失去一支军队。这可以继续更多骰子滚动,直到攻击者停止攻击或用尽军队,但此时我只对骰子单掷的胜利频率感兴趣。

所以我写了一批来模拟很多次而不是进入违反直觉的概率世界。我对编码很新,所以我正在寻找有关效率的提示。我还没有理解多处理,所以如果可以的话,我们现在就把它留下来。

我很惊讶花了一百万次模拟(大约20秒)花了多长时间,并且想知道是否有我做错的事情,或者这是你可能期望的那种时间这样的例行公事。

这是模拟部分:

from random import randint

  # Pass in number of each dice and number of sim's
def simulate(attDice,defDice,rolls):
    attLosses = 0
    defLosses = 0
    for roll in rolls:               # Number of simulations
        attRolls = []                # List holding attack dice 'scores'
        for die in range(attDice):   # Number of attack dice rolled
            attRolls.append(randint(1,6))
        defRolls = []                #  List holding defence dice 'scores'
        for die in range(defDice):   # Number of defence dice rolled
            defRolls.append(randint(1,6))
        while len(attRolls) and len(defRolls): # For each 
            if max(attRolls) > max(defRolls):  # Att's must beat def's
                defLosses += 1
            else:
                attLosses += 1
            # Delete the highest number from each list
            del(attRolls[attRolls.index(max(attRolls))])  # This seems clumsy
            del(defRolls[defRolls.index(max(defRolls))])  # which is what makes me
                                                      # think there's a better way
    return attLosses,defLosses
# We then go and work out percentages etc.

3 个答案:

答案 0 :(得分:1)

很多苦差事,完全不可回答的答案。

对于100万回合,我对20秒左右并不感到惊讶。我在Python中用相同的经验完成了类似的实验/模拟。当然,这些实验并不是真正重要的时间,所以我没有进行优化。

Python并不以速度着称。也许你习惯了低级语言。如果您在Java中进行了相同的实验,那么如果花费您的时间,我会感到很惊讶。

(如果你真的想加快速度,你的问题可能会有一些上下文有帮助吗?你的目的似乎是随意的,除了一些恒定时间的加速,也许还有一些微观优化,我觉得很难改变。)

答案 1 :(得分:0)

由于您实际上对骰子列表进行了排序,因此最好使用快速的python排序功能。

生成随机数也相对较慢。通过仅为所有骰子生成一个数字,您可以稍微加速它。

如果attDice和defDice很小(<= 5),这在我的计算机上运行大约5秒就可以运行一百万卷。 (使用PyPy,它以1s运行。)

def freqs(attDice, defDice, rolls):
    m = min(attDice, defDice)
    freq = [0]*(m+1)
    for i in range(rolls):
        ar = random.randrange(6**attDice)
        dr = random.randrange(6**defDice)
        ad = [(ar / 6**j) % 6 for j in range(attDice)]
        ad.sort(reverse=True)
        dd = [(dr / 6**j) % 6 for j in range(defDice)]
        dd.sort(reverse=True)
        aws = sum(j > k for j, k in zip(ad, dd))
        freq[aws] += 1
    return freq

它返回攻击者获胜的频率表。

答案 2 :(得分:0)

这是1,000,000卷的numpy实现的开始。

我已经标记了这个社区维基,如果有人想扩展它,请编辑。

3攻击骰子,2防守骰子

import numpy
A = numpy.random.randint(1,6,size=(1000000,3)).sort()
D = numpy.random.randint(1,6,size=(1000000,2)).sort()
Ahigh = A[:,2]
Dhigh = D[:,2]
Awins1st = (Ahigh > Dhigh)
A2nd = A[:,1]
D2nd = D[:,1]
Awins2nd = (A2nd > D2nd)
# needed: tabulate results, remove smelly repeating code, generalize

Awins1stAwins2nd是1000000个元素的真/假数组,表示攻击者是否通过比较3 A骰子和2 D骰子赢得了第1次或第2次“战斗”。