【问题标题】:Issue with numpy logical operationsnumpy 逻辑运算的问题
【发布时间】:2018-06-23 22:33:56
【问题描述】:

我正在创建一个游戏。在游戏中,我有一个以 0 开头的 numpy 数组(正方形)。玩家通过将分配的整数添加到某个位置来填充数组。玩家用自己的号码填满整行、整列、对角线或反对角线 (?) 即可赢得游戏。目前这是我检查游戏成功的函数。

我有两个问题: 1. 我希望该函数检查所有玩家是否成功并返回一个元组(即,如果玩家 2 获胜,则返回一个元组(即 (True,2))而不是一次返回一个。游戏的运作方式,永远不会有两个玩家获胜,所以这不是问题。我将有一个可以传递给函数的所有玩家的列表(即 4 个玩家的 [1,2,3,4])。 2. 我不想要一个“for”循环,因为我想多次迭代。

我一直在努力使用 numpy 中的逻辑运算符,但我不想将其更改为列表或其他任何内容。

def check_success(gm,player): #gm is game array
            for i in range(len(gm)):
                if (not any(gm[i]-player)) or (not any(gm[:,i]-player)):
                    return True
            if (not any(np.diag(gm)-player)) or (not any(np.diag(np.fliplr(gm))-player)):
                return True
            return False

注意:我怀疑如果没有 for 循环,问题 #1 就无法解决。如果是这样的话,我更喜欢解决问题 #2。我总是可以多次运行这个函数,因为玩家的数量肯定会比gm的大小少很多。

【问题讨论】:

  • 在描述中你提到了非对角线,但你的代码似乎只解决了两个主要的对角线。你能澄清一下吗?
  • 抱歉,我错误地使用了非对角线这个词。我想我的意思是对角线和对角线。代码是正确的,不是解释。
  • 感谢您的澄清。在那种情况下,我的回答应该没问题。让我知道它是否适合您。

标签: python list numpy integer logic


【解决方案1】:

更新:优化的代码和基准:

时间

>>> stress_test(4, 1000, 2, 0, 0)
OP  : 0.322599 ms
pp0 : 0.451822 ms
pp1 : 0.140838 ms
>>> 
>>> stress_test(10, 1000, 4)
OP  : 1.051070 ms
pp0 : 0.425230 ms
pp1 : 0.166876 ms

代码

import numpy as np

def f_OP(board, p):
    for cp in range(1, p+1):
        if check_success(board, cp):
            return True, cp
    else:
        return False, 0

def check_success(gm,player): #gm is game array
            for i in range(len(gm)):
                if (not any(gm[i]-player)) or (not any(gm[:,i]-player)):
                    return True
            if (not any(np.diag(gm)-player)) or (not any(np.diag(np.fliplr(gm))-player)):
                return True
            return False

def f_pp0(board, dummy=None):
    for b in (board, board.T, np.einsum('ii->i', board)[:, None],
              np.einsum('ii->i', board[::-1])[:, None]):
        L = np.diff(b, axis=0).any(axis=0) | (b[0] == 0)
        ind = L.argmin()
        if not L[ind]:
            return True, b[0, ind]
    return False, 0

def f_pp1(board, dummy=None):
    D = np.einsum('ii->i', board)
    DP = D != 0
    if DP[0] and (D[0] == D).all():
        return True, D[0]
    L = DP & (D == board).all(0)
    I = L.argmax()
    if L[I]:
        return True, D[I]
    L = DP & (D == board.T).all(0)
    I = L.argmax()
    if L[I]:
        return True, D[I]
    D = np.einsum('ii->i', board[::-1])
    if D[0] and (D[0] == D).all():
        return True, D[0]
    return False, 0

def stress_test(n, k, p, wr=0.1, fr=0.4):
    from timeit import timeit
    data = np.random.randint(1, p+1, (k, n, n))
    data *= np.random.random((k, n, n)) < fr
    w = np.where(np.random.random((k,)) < wr)[0][:, None]
    pw = np.random.randint(1, p+1, w.shape)
    wp = np.random.randint(-2, 2*n, w.shape)
    i = np.where(wp < n, np.arange(n), wp-n)
    j = np.where((wp >= n) | (wp < 0), np.arange(n), wp)
    j[wp.ravel()==-1, :] == np.arange(n)[::-1]
    data[w, i, j] = pw
    glb = dict(data=data, p=p)
    kwds = dict(number=10, globals=glb)
    ref = None
    for f, glb['f'] in globals().items():
        if f.startswith('f_'):
            print('{:<4s}: {:8.6f} ms'.format(f[2:], timeit("for d in data: f(d, p)", **kwds) * 1000 / k))
            if ref is None:
                ref = np.array([glb['f'](d, p) for d in data])
                print(np.count_nonzero(ref))
            else:
                assert (ref == np.array([glb['f'](d, p) for d in data])).all()

【讨论】:

  • 感谢您的解决方案。现实情况是,我可能不需要很多玩家(通常只有 2 个)。如果是这种情况,快速测试让我的功能运行得更快(迭代超过 2 个玩家)。我可以将您的实现用于许多不同的玩家,但更重要的是,我正在寻找一种无需显式迭代即可同时检查列和行的方法。
  • 例如,如果我可以使用 any()/all() 来分解游戏板的行/列,并为每一行/列提供一个布尔值的一维数组,那么我可以结合所有数组(按行、按列、对角线(元素)、对角线(元素))并将其全部放在 if 语句中。我不介意循环播放玩家的数量。
  • @JamesCarter Strange,我对 2 个玩家和几个 10x10 随机填充的板进行了快速测试,我的运行速度比你的快 5 倍。也许这取决于参数。能否请您大方指出您期望的参数(尺寸、填充百分比、# 玩家)?
  • 这是我运行的测试:fill%:0(实际测试整个迭代,因为函数在 return 语句处停止执行),2 个玩家,4x4。请再试一次。我会喜欢工作速度快 5 倍的东西!注意:游戏很可能不会以比该测试更大的规模运行。这就是我在该参数范围内寻找效率的原因。
  • @JamesCarter 没关系,我搞砸了,当我测试 10 个 100x100 的板时,我以为我正在测试 100 个 10x10 的板。对于 4x4,你的确实更快。但是我制作了一个优化版本,即使在这么小的尺寸下,它的速度也快了一倍多。请查看更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-25
  • 2021-12-21
  • 2013-11-01
  • 2023-02-16
  • 1970-01-01
相关资源
最近更新 更多