我正在编写一个 Connect 4 游戏,您可以在其中选择棋盘的大小。该游戏适用于大多数棋盘尺寸,但当棋盘比宽高时就会出现问题。我不断收到索引超出范围的错误,我不确定我做错了什么。
这就是我现在的检查功能,因为它是唯一给我带来问题的部分。
def checkOWin(board):
boardHeight = len(board)
boardWidth = len(board[0])
tile = 'O'
# check horizontal spaces
for y in range(boardHeight):
for x in range(boardWidth - 3):
if board[x][y] == tile and board[x+1][y] == tile and board[x+2][y] == tile and board[x+3][y] == tile:
return True
# check vertical spaces
for x in range(boardWidth):
for y in range(boardHeight - 3):
if board[x][y] == tile and board[x][y+1] == tile and board[x][y+2] == tile and board[x][y+3] == tile:
return True
# check / diagonal spaces
for x in range(boardWidth - 3):
for y in range(3, boardHeight):
if board[x][y] == tile and board[x+1][y-1] == tile and board[x+2][y-2] == tile and board[x+3][y-3] == tile:
return True
# check \ diagonal spaces
for x in range(boardWidth - 3):
for y in range(boardHeight - 3):
if board[x][y] == tile and board[x+1][y+1] == tile and board[x+2][y+2] == tile and board[x+3][y+3] == tile:
return True
return False
任何帮助或建议将不胜感激。
虽然连续嵌套的 for 循环是胜利检测的明显解决方案,但在 Python 等语言中,这是一种相当慢的方法。这个问题实际上可以类比为 Connect 4 板二维上的卷积运算,卷积核设计用于匹配 4 个图块的水平、垂直和对角线。
因此,更快的方法是:
创建用于水平、垂直和对角线胜利检测的内核。
horizontal_kernel = np.array([[ 1, 1, 1, 1]])
vertical_kernel = np.transpose(horizontal_kernel)
diag1_kernel = np.eye(4, dtype=np.uint8)
diag2_kernel = np.fliplr(diag1_kernel)
detection_kernels = [horizontal_kernel, vertical_kernel, diag1_kernel, diag2_kernel]
从您的棋盘创建一个 2D 数组,其中玩家的所有图块都设置为 1,所有空/对手图块都设置为 0。
使用 SciPy 高度优化的 convolve2d 函数通过卷积运算运行电路板。
在卷积输出形成的数组中,任何“4”都表示棋盘中有4个相连的图块。
from scipy.signal import convolve2d
def winning_move(board, player):
for kernel in detection_kernels:
if (convolve2d(board == player, kernel, mode="valid") == 4).any():
return True
return False
这可以大大加快获胜条件的检测速度,这在游戏树上实现类似树搜索的算法时至关重要。我还发现这个解决方案更加优雅和可读。
您刚刚混淆了尺寸,您应该这样设置它们:
def checkOWin(board):
boardHeight = len(board[0])
boardWidth = len(board)
因为当你引用 board[x] 时,它是在计算板中列表的数量,而当你引用 board[x][y] 时 那只是指板中某一特定行的长度。
if board[x][y] == tile and board[x+1][y] == tile and board[x+2][y] == tile and board[x+3][y] == tile:
当我翻转这些值时,函数运行没有错误。
这是一个示例输入,应该与 OP 使用的类似:
board = [['_','_','_','_','_','_','_'],
['_','_','_','_','_','_','_'],
['_','_','_','X','_','_','_'],
['_','_','_','O','_','_','_'],
['_','X','X','O','O','O','O'],
['X','X','X','O','O','X','O']]
我将条件重新修改为:
for x in range(boardWidth):
for y in range(boardHeight):
try:
if board[y][x] == tile and board[y][x+1] == tile and board[y][x+2] == tile and board[y][x+3] == tile:
return True
except IndexError:
next
我们在看板列表中存储了 6 个不同的列表。访问面板时,y 首先出现,因为它首先告诉我们需要使用这 6 个列表中的哪一个列表,从而在面板列表中向上或向下移动。现在 x 索引将我们移动到我们访问过的任何 y 列表中。尝试和例外允许您删除
for x in range(boardWidth - 3)
,因为如果收到索引错误,我们就知道我们已经到达游戏板的边缘并且无法满足获胜条件。所以我们继续进行下一点测试。