基于Kivy与Minimax算法的Python井字棋AI无法拦截玩家走子问题求解
问题核心原因及修复方案
排查代码后共发现3个致命逻辑错误直接导致AI无法正常工作:
- 第一:
check_victory函数未检测行的胜负状态,仅检测了列和对角线,导致AI完全无法识别玩家凑齐行的获胜趋势,自然不会做拦截 - 第二:
max_play函数生成下一步状态时未对原始棋盘做拷贝,直接修改了遍历用的棋盘状态,导致后续递归逻辑全部错乱 - 第三:估值函数
evaluate的返回值未结合搜索深度,所有获胜/失败场景分值完全相同,导致AI在多个可选走法中只会选择遍历到的第一个,表现出随机落子的规律
具体修改步骤
- 修复
check_victory函数,补充行胜负检测逻辑,同时将浮点数除法替换为整除避免精度问题:
def check_victory(self, array): # 新增行求和检测 row_sum = np.sum(array, axis=1) for r in row_sum: if r % 10 == 3: return 'Player' if r // 10 == 3: return 'Computer' temp1 = array temp2 = np.rot90(array) column1 = np.sum(temp1, axis=0) column2 = np.sum(temp2, axis=0) diagonal1 = np.diag(temp1).sum() diagonal2 = np.diag(temp2).sum() for i in range(3): if column1[i] % 10 == 3 or column2[i] % 10 == 3: return 'Player' if column1[i] // 10 == 3 or column2[i] // 10 == 3: return 'Computer' if diagonal1 % 10 == 3 or diagonal2 % 10 == 3: return 'Player' if diagonal1 // 10 == 3 or diagonal2 // 10 ==3: return 'Computer' return 'None'
- 修复
max_play函数的状态拷贝问题,生成克隆棋盘时调用copy()方法:
def max_play(self, game_state, level): if self.check_victory(game_state) == 'Computer' or level == 0: return self.evaluate(game_state, level) moves = self.find_moves(game_state) best_score = float('-inf') for move in moves: # 新增copy()调用,避免修改原棋盘 clone = self.next_state(game_state.copy(), move[0], move[1], 'Computer') score = self.min_play(clone, level - 1) if score > best_score: best_score = score return best_score
- 优化
evaluate函数,结合搜索深度调整分值,让AI优先选择最快获胜、最慢落败的走法:
def evaluate(self, array, level): if self.check_victory(array) == 'Player': # 玩家获胜分值为负,深度越小玩家赢的越快,分值越低 return -10 - level if self.check_victory(array) == 'Computer': # AI获胜分值为正,深度越小AI赢的越快,分值越高 return 10 + level return 0
- 同步修改
min_play函数中调用evaluate的参数,传入当前深度:
def min_play(self, game_state, level): if self.check_victory(game_state) == 'Player' or level == 0: return self.evaluate(game_state, level) moves = self.find_moves(game_state) best_score = float('inf') for move in moves: clone = self.next_state(game_state.copy(), move[0], move[1], 'Player') score = self.max_play(clone, level - 1) if score < best_score: best_score = score return best_score
修改完成后AI即可正常识别获胜/拦截场景,不会再出现随机落子的问题。
内容的提问来源于stack exchange,提问作者Amir Ben Bassat
相关产品推荐
相关产品推荐

