井字棋Minimax算法故障排查:AI仅落子于下一个空位
问题根源与修复方案
核心问题:Minimax依赖实例状态而非传入的棋盘状态
你的minimax函数修改的是传入的grid参数,但checkWinner和checkDraw却依赖实例的Xsum、Osum变量——这两个变量在Minimax递归模拟落子时从未更新,导致永远触发不了基准条件(胜负/平局),最终所有模拟落子的得分都返回初始值(极大化时-1000,极小化时1000),AI只能选择第一个遍历到的可用格子。
具体修复步骤
1. 重构胜负与平局判断函数,基于传入的棋盘
将checkWinner和checkDraw改为接收grid参数,直接从棋盘判断状态,不再依赖实例的Xsum/Osum:
def checkWinner(self, grid, player): # 检查行、列、对角线 # 行 for row in grid: if all(cell == player for cell in row): return True # 列 for col in range(3): if all(grid[row][col] == player for row in range(3)): return True # 对角线 if all(grid[i][i] == player for i in range(3)) or all(grid[i][2-i] == player for i in range(3)): return True return False def checkDraw(self, grid): return all(cell != "-" for row in grid for cell in row)
2. 修改Minimax函数,完全基于传入的棋盘
更新minimax,调用上面重构后的判断函数,不再依赖实例状态,同时加入depth调整得分,让AI优先选择最快获胜/最慢失败的路径:
def minimax(self, grid, depth, isMaximising): if self.checkWinner(grid, "O"): return 10 - depth elif self.checkWinner(grid, "X"): return depth - 10 elif self.checkDraw(grid): return 0 if isMaximising: bestScore = -float('inf') for r in range(3): for c in range(3): if grid[r][c] == "-": grid[r][c] = 'O' score = self.minimax(grid, depth + 1, False) grid[r][c] = "-" bestScore = max(score, bestScore) return bestScore else: bestScore = float('inf') for r in range(3): for c in range(3): if grid[r][c] == "-": grid[r][c] = 'X' score = self.minimax(grid, depth + 1, True) grid[r][c] = "-" bestScore = min(score, bestScore) return bestScore
3. 修复makeMove的逻辑顺序
原代码中X落子后先调用bestMove再更新Xsum,导致状态不同步,同时注释了回合切换,修复后:
def makeMove(self, row, col): if self.grid[row][col] == "-" and not self.gameOver: if self.XtoMove: # X落子,更新棋盘和Xsum self.grid[row][col] = 'X' self.Xsum.append(self.MagicSquare[row][col]) # 检查X是否获胜或平局 if self.checkWinner(self.grid, "X"): self.gameOver = True self.Xwins = True elif self.checkDraw(self.grid): self.gameOver = True self.draw = True else: # 切换回合,触发AI落子 self.XtoMove = False self.bestMove()
4. 修复bestMove的胜负判断与回合切换
让bestMove使用重构后的判断函数,落子后切换回玩家回合:
def bestMove(self): if self.gameOver: return bestScore = -float('inf') move = (-1, -1) # 遍历所有可用格子寻找最优解 for r in range(3): for c in range(3): if self.grid[r][c] == "-": # 模拟落子并计算得分 self.grid[r][c] = 'O' score = self.minimax(self.grid, 0, False) self.grid[r][c] = "-" if score > bestScore: bestScore = score move = (r, c) # 执行最佳落子 if move != (-1, -1): self.grid[move[0]][move[1]] = 'O' self.Osum.append(self.MagicSquare[move[0]][move[1]]) # 检查O是否获胜或平局 if self.checkWinner(self.grid, "O"): self.gameOver = True self.Owins = True elif self.checkDraw(self.grid): self.gameOver = True self.draw = True else: # 切换回玩家回合 self.XtoMove = True
修复后的完整代码
class GameState(): def __init__(self): self.grid = [["-","-","-"], ["-","-","-"], ["-","-","-"]] self.MagicSquare = [[4, 9, 2], [3, 5, 7], [8, 1, 6]] self.XtoMove = True self.gameOver = False self.Xsum = [] self.Osum = [] self.Xwins = False self.Owins = False self.draw = False def makeMove(self, row, col): if self.grid[row][col] == "-" and not self.gameOver: if self.XtoMove: self.grid[row][col] = 'X' self.Xsum.append(self.MagicSquare[row][col]) if self.checkWinner(self.grid, "X"): self.gameOver = True self.Xwins = True elif self.checkDraw(self.grid): self.gameOver = True self.draw = True else: self.XtoMove = False self.bestMove() def checkDraw(self, grid): return all(cell != "-" for row in grid for cell in row) def checkWinner(self, grid, player): # 检查行 for row in grid: if all(cell == player for cell in row): return True # 检查列 for col in range(3): if all(grid[row][col] == player for row in range(3)): return True # 检查对角线 if all(grid[i][i] == player for i in range(3)) or all(grid[i][2-i] == player for i in range(3)): return True return False def minimax(self, grid, depth, isMaximising): if self.checkWinner(grid, "O"): return 10 - depth elif self.checkWinner(grid, "X"): return depth - 10 elif self.checkDraw(grid): return 0 if isMaximising: bestScore = -float('inf') for r in range(3): for c in range(3): if grid[r][c] == "-": grid[r][c] = 'O' score = self.minimax(grid, depth + 1, False) grid[r][c] = "-" bestScore = max(score, bestScore) return bestScore else: bestScore = float('inf') for r in range(3): for c in range(3): if grid[r][c] == "-": grid[r][c] = 'X' score = self.minimax(grid, depth + 1, True) grid[r][c] = "-" bestScore = min(score, bestScore) return bestScore def bestMove(self): if self.gameOver: return bestScore = -float('inf') move = (-1, -1) for r in range(3): for c in range(3): if self.grid[r][c] == "-": self.grid[r][c] = 'O' score = self.minimax(self.grid, 0, False) self.grid[r][c] = "-" if score > bestScore: bestScore = score move = (r, c) if move != (-1,-1): self.grid[move[0]][move[1]] = 'O' self.Osum.append(self.MagicSquare[move[0]][move[1]]) if self.checkWinner(self.grid, "O"): self.gameOver = True self.Owins = True elif self.checkDraw(self.grid): self.gameOver = True self.draw = True else: self.XtoMove = True
内容的提问来源于stack exchange,提问作者Tobi
相关产品推荐
相关产品推荐

