我如何找到二维阵列满足有条件的地方



背景

如果您曾经玩过风险,那么您熟悉滚动骰子以确定战斗的结果。如果没有,这是一个简短的摘要:

确定玩家可能会摇动多少骰子的规则如下:

  1. 攻击者可能比他的国家的军队数量少摇一击,最多三个。
  2. 辩护人可能会像他所在国家/地区的军队数量一样多,最多有两个。

决定特定掷骰子的结果的规则如下:

  1. 将最高的攻击者模具与最高的防守者死亡进行了比较。谁拥有较低的人失去一支军队。纽带是辩护人。
  2. 第二高骰子重复该过程。

如果攻击者或防守者只会掷出一个死亡的情况,则总共只有一支军队丢失;在所有其他情况下,总共将丢失两支军队。

我想分析每对模具卷的获胜频率。我可以通过所有可能性进行循环,但是我有兴趣使用ndarrays并切片进行计算。

例如,考虑攻击者滚动一个死亡的场景,而后卫则滚动一个死亡。我们可以在ndarray中安排所有可能的结果。

In [1]: import numpy as np
In [2]: x = np.tile(np.arange(1,7),(6,1))
In [3]: x
Out[3]: 
array([[1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6]])

如果防御者掷骰是列,而攻击者掷骰是行,则防守者获胜的区域是此数组的上部三角形部分

defence_win_region= array([[1, 1, 1, 1, 1, 1],
                           [0, 1, 1, 1, 1, 1],
                           [0, 0, 1, 1, 1, 1],
                           [0, 0, 0, 1, 1, 1],
                           [0, 0, 0, 0, 1, 1],
                           [0, 0, 0, 0, 0, 1]])

问题

如何从 x等数组中获得像 defence_win_region这样的数组?如何将该方法扩展到更高维数的阵列以分析2-1,3-1,3-2,1-2卷?

import numpy as np
import scipy
import itertools
def riskRoll(ad,dd):  #Never gonna give you up . . . 
    minD=min(ad,dd)
    a=np.array(list(itertools.combinations_with_replacement(
        np.arange(6,0,-1),ad)))
    d=np.array(list(itertools.combinations_with_replacement(
        np.arange(6,0,-1),dd)))
    na=np.array([scipy.misc.factorial(ad)/np.prod(
        scipy.misc.factorial(np.unique(roll,return_counts=True)[1])) for roll in a])
    nd=np.array([scipy.misc.factorial(dd)/np.prod(
        scipy.misc.factorial(np.unique(roll,return_counts=True)[1])) for roll in d])
    a_wins= np.sum(p.where(a[None,:,0:minD]>d[:,None,0:minD],1,-1), axis=-1)+ad-dd
    nd_count=na[:,None]*nd[None,:]
    return a_wins*nd_count

如何工作:

  1. 输出是尺寸C((6,ad)) x C((6,dd))的矩阵,所有组合都以降序为单位
  2. 矩阵a_wins中的值是攻击者获胜的数量,负数是防御性的胜利。这包括无备用骰子。
  3. nd_count中的值是加权因素,等于6**ad x 6**dd组合矩阵中组合存在的次数
  4. 最终输出是两者的乘积,显示出胜利的加权。总和除以6 **(ad dd)以获得预期的获胜/损失

对您有关2D数组的特定问题的简短答案是:

np.where(x >= np.transpose(x), 1, 0)

,为了进一步推动,您需要tile以外的其他工具。准备样品空间的自然方法是meshgrid

die = np.arange(1, 7)
a, d = np.meshgrid(die, die)

现在ad是2D数组,保持攻击者和后卫的得分。和以前一样,np.where(a <= d, 1, 0)产生了1-0表(前一个表的转置,但这就是选择问题)。

让我们看看每个掷出两个骰子时会发生什么:

a1, a2, d1, d2 = np.meshgrid(die, die, die, die)

这是防守者赢得第一轮的地方(比较最高得分):

np.where(np.maximum(a1, a2) <= np.maximum(d1, d2), 1, 0)

这是最小值的比较,是第二高分:

np.where(np.minimum(a1, a2) <= np.minimum(d1, d2), 1, 0)

两个都是4D阵列,因为样品空间是4维的。

当某人投掷3个或更多骰子时,事情变得更加复杂,因为"第二高"的选择不是最大的直接操作。可以通过堆叠玩家的骰子并沿着新轴进行排序来完成:

a1, a2, a3, d1, d2 = np.meshgrid(die, die, die, die, die)  # 3-2 roll 
attack = np.stack([a1,a2,a3])       # stack attacker into a 6D array
attack.sort(axis=0)                 # sort their scores
attack_max = attack[-1,:,:,:,:,:]   # maximum score
attack_2nd = attack[-2,:,:,:,:,:]   # 2nd highest attack score

现在我们像以前一样比较:

defender_wins_1 = np.where(attack_max <= np.maximum(d1, d2), 1, 0)
defender_wins_2 = np.where(attack_2nd <= np.minimum(d1, d2), 1, 0)

最新更新