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

井字棋Min Max算法Python实现问题:AI决策不稳健

问题分析与修复方案

你的双人井字棋AI的核心问题出在MinMax算法的实现逻辑上,以及辅助函数的设计错误,具体来说有这几个关键问题:


1. pos_moves() 函数逻辑错误

你用permutations(self.posis())生成所有空位的排列,这会产生大量冗余的对局序列(比如空位[1,4]会生成(1,4)和(4,1)两个完全不同的序列),但井字棋的每一步只需要选择一个空位,而不是预先生成整个对局的走法顺序。这不仅会导致计算量爆炸,还会让min_max函数错误地模拟“固定顺序的对局”,而不是模拟双方每一步都会做出最优选择的过程。

正确的做法是:pos_moves()只需要返回当前棋盘的所有空位即可,也就是直接返回self.posis()的结果。


2. min_max() 不是真正的MinMax算法

当前的min_max是一次性模拟从某个初始走法开始的完整对局,但没有考虑到人类玩家会选择对AI最不利的走法(Min玩家的角色)。真正的MinMax是递归的:

  • Max玩家(AI)会选择能让自己得分最高的走法
  • Min玩家(人类)会选择能让AI得分最低的走法

你的代码里只是模拟了双方按固定顺序走完全局,完全没有体现“最优选择”的核心逻辑,这才是AI走不出最优步的根本原因。


3. 评分逻辑与决策逻辑的小问题

  • 当前评分的计算方式虽然考虑了深度,但没有结合MinMax的递归评估
  • comp_think里两次调用min_max,做了重复计算
  • 当多个走法评分相同时,只取第一个,导致AI走法单一且可能错过更优的选择

修复后的完整代码

下面是修正后的核心函数,我会逐一解释改进点:

1. 修正辅助函数

# 查找棋盘上所有空位(这个函数没问题,保留)
def posis(self): 
    return [x for x, coordinate in enumerate(self.gameBoard) if coordinate not in ('X', 'O')]

# 返回当前棋盘的所有可能走法(修正:只返回空位,不需要排列)
def pos_moves(self): 
    return self.posis()

2. 重构为递归的MinMax算法

def min_max(self, is_maximizing, depth, player):
    # 先判断当前棋盘的终止状态
    human_player = 'O' if player == 'X' else 'X'
    winner = self.win_checker(self.gameBoard)
    
    # 终止条件:AI获胜,返回高分(深度越小,得分越高,因为越早赢越好)
    if winner == player:
        return 10 - depth
    # 人类获胜,返回低分
    elif winner == human_player:
        return depth - 10
    # 平局,返回0
    elif self.board_full(self.gameBoard):
        return 0

    if is_maximizing:
        best_score = -float('inf')
        # 遍历所有可能的走法
        for move in self.pos_moves():
            # 模拟走这一步
            self.gameBoard[move] = player
            # 递归调用,切换为Min玩家(人类),深度+1
            score = self.min_max(False, depth + 1, player)
            # 回溯,撤销这一步
            self.gameBoard[move] = str(move)
            # 更新最高分
            best_score = max(best_score, score)
        return best_score
    else:
        best_score = float('inf')
        for move in self.pos_moves():
            self.gameBoard[move] = human_player
            score = self.min_max(True, depth + 1, player)
            self.gameBoard[move] = str(move)
            best_score = min(best_score, score)
        return best_score

3. 修正AI决策函数

def comp_think(self, player):
    best_score = -float('inf')
    best_moves = []
    human_player = 'O' if player == 'X' else 'X'

    # 遍历所有可能的初始走法,评估每个走法的得分
    for move in self.pos_moves():
        self.gameBoard[move] = player
        score = self.min_max(False, 1, player)
        self.gameBoard[move] = str(move)
        
        # 如果当前走法得分更高,更新最优走法列表
        if score > best_score:
            best_score = score
            best_moves = [move]
        # 如果得分相同,加入最优走法列表
        elif score == best_score:
            best_moves.append(move)
    
    # 从所有最优走法中随机选一个(避免每次走法都一样)
    import random
    chosen_move = random.choice(best_moves)
    print(f"AI选择的最优走法: {chosen_move}")
    return str(chosen_move)

关键改进点说明

  1. 递归MinMax:通过递归模拟每一步的选择,Max玩家(AI)选最高分,Min玩家(人类)选最低分,真正实现了“AI选择最优走法,人类选择对AI最不利的走法”的逻辑。
  2. 回溯机制:在模拟走法后,会把棋盘恢复原样,避免影响后续的评估。
  3. 评分优化:AI获胜得正分,人类获胜得负分,平局得0,同时结合深度调整得分——越早获胜,得分越高,鼓励AI快速赢下对局。
  4. 多最优走法处理:当多个走法评分相同时,随机选择一个,避免AI走法僵化。
  5. 避免重复计算:comp_think里只做一次评估,不再重复调用min_max。

测试验证

用你提供的示例对局测试:

  • 人类走位置0后,AI会优先选择位置4(正中间),因为这是井字棋中最优的初始应对,能最大化后续的获胜概率。
  • 后续的每一步AI都会选择能阻止人类获胜,同时最大化自己获胜机会的走法。

内容的提问来源于stack exchange,提问作者Kaleba KB Keitshokile

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:26:40