打Risk时,攻守的输赢概率

2023/01/19

https://storage.googleapis.com/xuehuichao-share/farming/risk_game.jpg

Risk里面打仗的规则很有意思:攻守双方靠掷骰子比大小来决定各死几个人。攻 方最多出三个人;守方最多出两个人。打的时候双方都可能会死人,而就用点数 的大小来决定死几个人。比较时,把攻方掷出的骰子排序,守方也排序,再一一 比最高的几个。每次比较时,决定死的这个人来自哪方:只有攻方的点数严格大 于守方的,才算攻方胜(不用死人);否则攻方就输,需要死一个人。

举个例子:假设攻方要出三个人,守方出两个人。攻方掷出了3、4、5,守方是3, 和5。这样各方排序之后,经过比较,双方各死一个人。

5 5 守方胜
4 3 攻方胜
3

这种游戏规则和平时见到的比大小很不一样,因为攻守优劣势很不明显。一方面, 守方的优势在于点数天然就会更大一号;但另外一方面,攻方如果人多的时候就 更容易出现大的点数。那这样一来,到底谁更占优?

心算不出来,写个程序模拟一下,试试攻守双方不同人数的组合:

  1. 双方大概每次打仗会死多少人(期望)

  2. 打仗时双方各自获胜的概率

import random
import numpy
import tabulate

def ComputeWinningStats(off_size, def_size, N_sim=100000):
  """Compute the winning stats by simulation.
  """
  rand = random.Random()
  my_losses = []
  opp_losses = []
  wins = []

  for _ in range(N_sim):
    we_win = False

    my_rolls = sorted([rand.choice(range(6)) for i in range(off_size)], reverse=True)
    opp_rolls = sorted([rand.choice(range(6)) for i in range(def_size)], reverse=True)

    my_loss, opp_loss = 0, 0
    for my, opp in zip(my_rolls, opp_rolls):
      if my > opp:
        opp_loss += 1
      else:
        my_loss += 1

    if opp_loss == def_size:
      we_win = True
    my_losses.append(my_loss)
    opp_losses.append(opp_loss)
    wins.append(we_win)

  return {
      "off_size": off_size,
      "def_size": def_size,
      "off_losses": numpy.mean(my_losses),
      "def_losses": numpy.mean(opp_losses),
      "win_rate": numpy.mean(wins)
  }

results = []
for off_size in range(1, 4):
  for def_size in range(1, 3):
    results.append(ComputeWinningStats(off_size, def_size))

print(tabulate.tabulate(results, headers="keys"))

运行结果如下:

  off_size    def_size    off_losses    def_losses    win_rate
----------  ----------  ------------  ------------  ----------
         1           1       0.58313       0.41687     0.41687
         1           2       0.74467       0.25533     0
         2           1       0.41997       0.58003     0.58003
         2           2       1.21831       0.78169     0.2298
         3           1       0.33808       0.66192     0.66192
         3           2       0.91986       1.08014     0.37183

表中每行能看出进攻方和防守方的人数(off_size, def_size),以及各方死亡人 数(off_losses, def_losses),还有进攻方获胜的概率。

我看到这个表对于打法的指导意义:

  1. 如果我是防守方,有两个子,就一定要拿这两个子做防御。这样相比两次拿 一个子做防御,死的人会少20%左右。

  2. 如果我是进攻方,每次进攻时应该尽量拿更多的子进攻。这样在消耗敌方同 样的子的情况下,我方伤亡最小。

  3. 在进攻时,如果我方的人和对方差不多多,都大于3个,那我可以不停去攻, 因为平均每局我的伤亡要小一点点(0.92 v.s. 1.08)。