加速风险战争游戏骰子滚动模拟
我和朋友们在想,在桌游《风险》中,不同情况下胜利的概率有多大。这款游戏是围绕一个类似地球的棋盘进行的世界大战,棋盘被划分成不同的领土。
对于不熟悉《风险》的人来说:
在游戏的每一轮中,攻击者可以选择入侵防守者的国家。攻击者和防守者会选择使用多少个骰子来进行战斗。例如,攻击者在某些情况下可以选择用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.
在这种情况下,每一方都会损失1个军队。这个过程可以继续进行,直到攻击者停止攻击或者军队用完为止,但我现在只对单次掷骰子的胜率感兴趣。
所以我写了一个程序来模拟很多次,而不是进入那些让人困惑的概率世界。因为我对编程还比较陌生,所以我在寻找一些提高效率的建议。现在我还不太懂多进程的概念,所以暂时不考虑这个。
我很惊讶进行一百万次模拟竟然花了大约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 个回答
这是一个使用numpy库进行100万次掷骰子的实现的开头。
我把这个内容标记为社区维基,欢迎大家扩展和编辑。
有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
Awins1st
和Awins2nd
是各包含1000000个元素的真假数组,表示攻击者在比较3个攻击骰子和2个防御骰子时,是否赢得了第一次或第二次“战斗”。
这段话说得有点模糊,完全没有严谨的分析。
我对一百万次循环大约20秒的结果并不感到惊讶。我在Python中做过类似的实验/模拟,结果也是这样。其实,那些实验并不是特别需要快速完成,所以我没有进行优化。
而且,Python本身就不是以速度著称的。也许你习惯用一些底层语言。如果你在Java中做同样的实验,我会感到惊讶,如果它花的时间和Python一样。
(如果你真的想加快速度,或许在你的问题中提供一些背景信息会有帮助?看起来你的目的比较随意,所以除了做一些常量时间的加速和可能的一些微小优化,我觉得没什么太大的改变。)
因为你实际上是在对骰子列表进行排序,所以使用Python的排序功能会更好,这个功能很快。
生成随机数的速度也比较慢。如果只为所有骰子生成一个随机数,可以稍微加快这个过程。
在我的电脑上,如果attDice和defDice的数量比较少(小于等于5),进行一百万次掷骰子大约需要5秒钟。(如果用PyPy的话,只需要1秒。)
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
它会返回一个攻击者获胜的频率表。