You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

井字棋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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:45:03