有没有更有效的方法来在列表矩阵中查找一行相同的项目?

Is there more efficient way to find a line of same items in a list matrix?

提问人:jand 提问时间:10/12/2023 更新时间:10/12/2023 访问量:62

问:

我正在用 python 制作一个“井字游戏”程序,并试图检查玩家是否获得了获胜的“连续三步”动作。我有方法,但我不知道它是否好或是否可以缩短。

这是我的代码:

board = [
    [0,0,0],
    [0,0,0],
    [0,0,0]]
winner = 0

def checkIfWon(player):
    #check rows
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] == player:
            winner = player
    #check columns
    for i in range(3):
        if board[0][i] == board[1][i] == board[2][i] == player:
            winner = player
    #check diagonals
    if board[0][0] == board[1][1] == board[2][2] == player:
        winner = player
    if board[0][2] == board[1][1] == board[2][0] == player:
        winner = player

runGame = True

while runGame:
    (Game Loop)
    checkIfWon(1)
    checkIfWon(2)
Python list 函数

评论

0赞 S3DEV 10/12/2023
沿每个轴测试总和 3 怎么样?
0赞 jand 10/12/2023
生病了。我会尝试 6 或 3 的总和,放入列表中,然后检查列表中是 3 还是列表中是 6。

答:

0赞 Maria K 10/12/2023 #1

如果您愿意使用而不是内置列表(我完全理解您可能不这样做),它可以写得很好。基本上通过使用矢量化和在两个轴上:numpy.arrayallany

import numpy as np

board = np.array([
    [1,1,2],
    [0,1,2],
    [2,1,1]
])
winner = 0

def checkIfWon(player):
    if np.any(np.all(board == player, axis=0)):
        return True
    return np.any(np.all(board == player, axis=1))


print(checkIfWon(1))
print(checkIfWon(2))

输出:

True
False

评论

2赞 Homer512 10/12/2023
你错过了对角线。检查并修复np.diag(board)np.diag(board[::-1])
1赞 Homer512 10/12/2023 #2

在您看来,您似乎希望像短代码一样“高效”,而不一定是针对性能进行微优化。因此,让我们继续这样做:

我们可以比较列表是否相等。因此,让我们从构建获胜模式开始;3 个条目列出播放器。

def checkIfWon(player):
    winning = [player] * 3

现在我们可以简单地比较每一行。但我们不能按列进行比较。但是,转置矩阵很简单。

    transposed = [list(col) for col in zip(*board)]

对角线有点乏味,但迭代模式和帮助。reversed

    diag1 = [row[col] for col, row in enumerate(board)]
    diag2 = [row[col] for col, row in enumerate(reversed(board))]

现在我们可以搜索一个匹配项:

    if winning in board or winning in transposed or winning in (diag1, diag2):
        winner = player

旁注: 您似乎想更改全局变量,但您没有在函数中将其声明为全局变量。要么做干净的事情,只返回获胜者,要么在函数中声明winnerglobal winner

1赞 ShadowRanger 10/12/2023 #3

你可以稍微简化它的某些部分,但总的来说这是一个丑陋的部分,所以改进是适度的。

一个变化是将 s 作为一个整体来比较行测试,更改:list

for i in range(3):
    if board[i][0] == board[i][1] == board[i][2] == player:

自:

if [player]*3 in board:

对于列,你不能把它简化那么多,但你仍然可以写一个稍微干净一点的测试,改变:

if board[0][i] == board[1][i] == board[2][i] == player:

自:

if [row[i] for row in board] == [player]*3:

对角线的改进更没有用处,但您可以稍微简化一下:

if board[0][0] == board[1][1] == board[2][2] == player:
    winner = player
if board[0][2] == board[1][1] == board[2][0] == player:
    winner = player

成为(可以说)改进的:

if board[1][1] == player and (board[0][0] == board[2][2] == player or board[0][2] == board[2][0] == player):

这仅在玩家不握住中心时短路(防止任一对角线工作)而得到改进。

这里会有所帮助的一件事是,如果您将电路板表示为单个连续的,而不是多维的,则允许切片执行更多工作,并使测试足够简单,以便将它们折叠为具有生成器表达式的测试,而不是带有测试的循环。如果板子是一个长度,测试可以简化为:listanyforif9list

threeinarow = [player]*3  # Make the three element list just once
# Row tests
if any(board[row*3:row*3+3] == threeinarow for row in range(3)):
    winner = player

if any(board[col::3] == threeinarow for col in range(3))
    winner = player

# Test top-left to bottom-right diagonal and top-right to bottom left diagonal
if board[::4] == threeinarow or board[2:8:2] == threeinarow:
    winner = player

但我必须承认,对角线测试中的神奇数字让我感到不安,所以这不是一个纯粹的改进。