Python实现井字棋Minimax算法失效问题求助
问题:Minimax算法井字棋AI未遍历所有可能,仅输出首个检查位置
我参考YouTube教程实现了基于Minimax算法的简易井字棋AI,但算法无法正常工作——它没有遍历所有可能并返回最优位置,而是直接输出首个检查到的位置。复制教程代码后问题依然存在;尝试调换电脑与玩家的棋子标识、调整算法的最大化/最小化逻辑,均未解决问题。
以下是我的代码:
import math import random print() board = {1: ' ', 2: ' ', 3: ' ', 4: ' ', 5: ' ', 6: ' ', 7: ' ', 8: ' ', 9: ' '} computerLetter = 'X' playerLetter = 'O' def print_board(board=board): for i in range(1, 8, 3): print('|' + board[i] + '|' + board[i + 1] + '|' + board[i + 2] + '|') if i < 7: print('-' * 13) print() def space_is_free(position): if board[position] == ' ': return True else: return False def free_spaces(board=board): freeSpaces = 0 for key in board.keys(): if key == ' ': freeSpaces += 1 return freeSpaces def make_move(letter, position): if space_is_free(position): board[position] = ' ' + letter + ' ' print_board(board) if check_for_win(board): if letter == 'O': print("You win!!") exit() else: print("The computer wins. Better luck next time!") exit() elif check_for_tie(board): print("It's a tie! Well played.") exit() else: print("Invalid choice.") position = int(input("Enter new position: ")) make_move(letter, position) def check_for_win(board=board): if board[1] == board[2] == board[3] != ' ' or board[4] == board[5] == board[6] != ' ' or board[7] == board[8] \ == board[9] != ' ' or board[1] == board[4] == board[7] != ' ' or board[2] == board[5] == board[6] != \ ' ' or board[3] == board[6] == board[9] != ' ' or board[1] == board[5] == board[9] != ' ' or board[3]\ == board[5] == board[7] != ' ': return True else: return False def check_for_win_letter(letter): if board[1] == board[2] == board[3] == ' ' + letter + ' ' or board[4] == board[5] == board[6] == ' ' + letter + ' '\ or board[7] == board[8] == board[9] == ' ' + letter + ' ' or board[1] == board[4] or board[7] == ' ' +\ letter + ' ' or board[2] == board[5] or board[6] == ' ' + letter + ' ' or board[3] == board[6] or board[9]\ == ' ' + letter + ' ' or board[1] == board[5] == board[9] == ' ' + letter + ' ' or board[3] == board[5] ==\ board[7] == ' ' + letter + ' ': return True else: return False def check_for_tie(board=board): for key in board.keys(): if board[key] == ' ': return False else: return True def player_move(playerLetter='O'): if free_spaces(board) >= 9: print_board(board) position = int(input("Enter position (1-9): ")) make_move(playerLetter, position) def computer_move(computerLetter='X'): if free_spaces(board) == 9: make_move(computerLetter, 5) else: bestScore = -math.inf bestPosition = 0 for key in board.keys(): if space_is_free(key): board[key] = ' ' + computerLetter + ' ' score = minimax(board, 0, False) board[key] = ' ' if score > bestScore: bestScore = score bestPosition = key make_move(computerLetter, bestPosition) print(f"Computer moves to {bestPosition}.") def minimax(board, depth, isMaximising): if check_for_win_letter('X'): return 1 * (free_spaces(board) + 1) elif check_for_win_letter('O'): return -1 * (free_spaces(board) + 1) elif check_for_tie(board): return 0 if isMaximising: bestScore = -math.inf for key in board.keys(): if space_is_free(key): board[key] = ' ' + computerLetter + ' ' score = minimax(board, depth + 1, False) board[key] = ' ' bestScore = max(score, bestScore) return bestScore else: bestScore = math.inf for key in board.keys(): if space_is_free(key): board[key] = ' ' + playerLetter + ' ' score = minimax(board, depth + 1, True) board[key] = ' ' bestScore = min(score, bestScore) return bestScore while not check_for_win(board): computer_move('X') player_move('O') # gameState = input("Would you like to play again? (y/n)") # # if gameState.lower() == 'y': # main() # elif gameState.lower() == 'n': # exit() # else: # print("Invalid choice.")
问题根源及修复方案
1. free_spaces函数逻辑错误
原函数错误地判断board的key是否等于空字符串(key == ' '),而board的key是1-9的数字,永远不可能等于空字符串,导致该函数始终返回0。这会让Minimax算法错误评估游戏状态,无法正确计算得分。
修复后的代码:
def free_spaces(board=board): freeSpaces = 0 for key in board.keys(): if board[key] == ' ': # 修正为判断对应位置的取值是否为空 freeSpaces += 1 return freeSpaces
2. check_for_win_letter函数逻辑错误
原函数存在多处逻辑错误:
- 竖排判断中,将
board[2] == board[5] == board[8]错误写成board[2] == board[5] or board[6],导致竖排检测失效。 - 多处使用
or连接条件,而非判断三个位置全部等于目标棋子,导致错误识别获胜状态。
修复后的代码:
def check_for_win_letter(letter): target = ' ' + letter + ' ' # 横排检测 if board[1] == board[2] == board[3] == target: return True if board[4] == board[5] == board[6] == target: return True if board[7] == board[8] == board[9] == target: return True # 竖排检测 if board[1] == board[4] == board[7] == target: return True if board[2] == board[5] == board[8] == target: return True if board[3] == board[6] == board[9] == target: return True # 对角线检测 if board[1] == board[5] == board[9] == target: return True if board[3] == board[5] == board[7] == target: return True return False
3. 主循环逻辑优化
原主循环在电脑获胜后仍会执行玩家移动,可在computer_move和player_move中通过check_for_win提前终止循环,不过修复前两个核心错误后,make_move函数已经会在获胜时调用exit()终止程序,该问题可忽略。
修复后效果验证
修复上述错误后,Minimax算法会正确遍历所有可用位置,计算每个位置的得分:
- 当AI有直接获胜的位置时,会优先选择该位置。
- 当玩家即将获胜时,AI会优先阻止玩家。
- 无直接胜负时,AI会选择能引导至平局或最优局面的位置。
内容的提问来源于stack exchange,提问作者Toxic
相关产品推荐
相关产品推荐

