Python井字棋Minimax算法返回相似负值 CPU决策异常排查
Minimax井字棋AI逻辑异常修复
问题根因
你的代码存在两个核心逻辑错误,导致回合传递、胜负判定完全错位:
- 初始调用minimax的参数错误:在
smart_CPU_choice中,CPU完成测试落子后,下一回合应当是人类玩家行动,但你调用minimax时传入的turn仍然是CPU的回合标识,且depth传值为0,相当于让CPU在自己刚落子的棋盘上继续走棋,从搜索树第一层就打乱了回合交替顺序。 - minimax内部玩家标识逻辑错误:你在递归遍历落子前,先取了当前传入
turn对应的棋子符号,但在胜负判定时,默认当前传入的turn是刚落子造成胜负的玩家——实际上传入minimax的turn应当是接下来要落子的玩家,刚完成落子、可能触发胜负的是上一个玩家,这就导致很多深层节点的获胜方判定错误。
修正后的代码
不需要改动极大极小值的选择规则,仅调整参数传递逻辑即可:
def smart_CPU_choice(self): state=self.current_state # 棋盘用长度为9的列表表示 cpu_turn = self.turn # 记录当前CPU的回合标识 human_turn = 1 - cpu_turn # 计算人类玩家的回合标识 cpu_piece = self.XO_tuple[cpu_turn] best=[None,-999] depth=1 # CPU已经落了1层子,深度从1开始 for target in range(9): if state[target] == '': state[target] = cpu_piece # CPU落子后,下一步是人类玩家走,传入人类回合标识 score = self.minimax(depth, state, human_turn) state[target]='' if score > best[1]: best[1] = score best[0] = target return best[0] def minimax(self,depth,state,next_turn): # 先判断上一步落子的玩家是否获胜:上一步的玩家是当前待行动玩家的对手 last_turn = 1 - next_turn if self.win_check(True, state) == True: if self.players_tuple[last_turn] == "CPU": return 10 - depth else: return -10 + depth # 棋盘填满返回平局分 if len(''.join(state))==9: return 0 current_piece = self.XO_tuple[next_turn] scores = [] # 遍历所有空位,模拟当前回合玩家落子 for space in range(9): if state[space] == '': state[space] = current_piece # 递归调用时传入下一个回合的玩家标识,深度+1 scores.append(self.minimax(depth+1, state, 1-next_turn)) state[space]='' # 当前回合是CPU就选最大值,是人类就选最小值 if self.players_tuple[next_turn] == "CPU": return max(scores) else: return min(scores)
逻辑说明
- 修正后
minimax的turn参数统一表示接下来要落子的玩家,每次递归调用时直接通过1-next_turn切换回合,不会出现回合数分配错误的问题 - 胜负判定永远检查上一个落子的玩家(即当前待行动玩家的对手),不会出现获胜方识别错误
- 深度计数从CPU第一次落子后开始累加,终局分值的计算逻辑保持原本设计即可,不需要调换max/min逻辑
修正后AI不仅能识别直接获胜的落子,还会主动封堵人类的必胜点、布局自身的获胜路线,非必胜状态下的分值也会根据双方对局风险正常分布,不会全为无区分度的大负数。
内容的提问来源于stack exchange,提问作者Darkstar
相关产品推荐
相关产品推荐

