如何找到二维数组满足某些条件的位置?

2024-10-17 08:22:45 发布

您现在位置:Python中文网/ 问答频道 /正文

背景

如果你曾经玩过冒险游戏,你很熟悉掷骰子来决定战斗的结果。如果没有,这里有一个简短的概要:

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

  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卷,如何将该方法扩展到更高维的数组?你知道吗


Tags: in数量规则np数组国家骰子array
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阵列,因为样本空间是四维的。你知道吗

当有人掷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)

相关问题 更多 >