提问人:jand 提问时间:10/12/2023 更新时间:10/12/2023 访问量:62
有没有更有效的方法来在列表矩阵中查找一行相同的项目?
Is there more efficient way to find a line of same items in a list matrix?
问:
我正在用 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)
答:
如果您愿意使用而不是内置列表(我完全理解您可能不这样做),它可以写得很好。基本上通过使用矢量化和在两个轴上:numpy.array
all
any
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
评论
np.diag(board)
np.diag(board[::-1])
在您看来,您似乎希望像短代码一样“高效”,而不一定是针对性能进行微优化。因此,让我们继续这样做:
我们可以比较列表是否相等。因此,让我们从构建获胜模式开始;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
旁注:
您似乎想更改全局变量,但您没有在函数中将其声明为全局变量。要么做干净的事情,只返回获胜者,要么在函数中声明winner
global winner
你可以稍微简化它的某些部分,但总的来说这是一个丑陋的部分,所以改进是适度的。
一个变化是将 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):
这仅在玩家不握住中心时短路(防止任一对角线工作)而得到改进。
这里会有所帮助的一件事是,如果您将电路板表示为单个连续的,而不是多维的,则允许切片执行更多工作,并使测试足够简单,以便将它们折叠为具有生成器表达式的测试,而不是带有测试的循环。如果板子是一个长度,测试可以简化为:list
any
for
if
9
list
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
但我必须承认,对角线测试中的神奇数字让我感到不安,所以这不是一个纯粹的改进。
评论