当前位置: 首页 > news >正文

Python实战:用AlphaBeta剪枝算法搞定井字棋AI(附完整代码)

Python实战用AlphaBeta剪枝算法打造智能井字棋AI井字棋作为最经典的策略游戏之一规则简单却蕴含着丰富的博弈论思想。本文将带您从零开始实现一个基于AlphaBeta剪枝算法的智能AI不仅能完美掌握游戏策略还能通过可视化界面与人类对战。不同于传统算法教程的抽象讲解我们将聚焦于如何将数学理论转化为实际可运行的代码让算法真正活起来。1. 理解AlphaBeta剪枝的核心思想在开始编码前我们需要先理解这个算法为何能大幅提升搜索效率。想象两个棋手对弈一方MAX玩家希望最大化自己的得分另一方MIN玩家则试图最小化对手的优势。传统的极小极大算法会穷举所有可能的走法直到终局这在井字棋这样的简单游戏中尚可接受但对于更复杂的游戏如国际象棋就力不从心了。AlphaBeta剪枝的精妙之处在于它能够智能地跳过那些不可能影响最终决策的分支。具体来说Alpha值表示MAX玩家当前保证能获得的最低分数Beta值表示MIN玩家当前保证能获得的最高分数剪枝条件当发现某个节点的评估值超出当前Alpha-Beta范围时就可以停止搜索该节点的剩余子节点# 伪代码示例AlphaBeta剪枝核心逻辑 def alphabeta(node, depth, alpha, beta, maximizing_player): if depth 0 or node.is_terminal(): return evaluate(node) if maximizing_player: value -infinity for child in node.children: value max(value, alphabeta(child, depth-1, alpha, beta, False)) alpha max(alpha, value) if alpha beta: break # Beta剪枝 return value else: value infinity for child in node.children: value min(value, alphabeta(child, depth-1, alpha, beta, True)) beta min(beta, value) if beta alpha: break # Alpha剪枝 return value提示在实际实现中我们通常会将评估函数设计为从当前玩家的视角出发这样可以使代码更加简洁统一。2. 构建井字棋游戏框架在实现算法前我们需要先建立游戏的基本结构。井字棋的棋盘可以用3x3的二维数组表示每个格子有三种状态空、X玩家1、O玩家2。class TicTacToe: def __init__(self): self.board [[ for _ in range(3)] for _ in range(3)] self.current_player X self.game_over False self.winner None def print_board(self): for i, row in enumerate(self.board): print(|.join(row)) if i 2: print(-*5) def make_move(self, row, col): if self.game_over or self.board[row][col] ! : return False self.board[row][col] self.current_player self.check_game_over() self.current_player O if self.current_player X else X return True def check_game_over(self): # 检查行 for row in self.board: if row[0] ! and row[0] row[1] row[2]: self.game_over True self.winner row[0] return # 检查列 for col in range(3): if self.board[0][col] ! and self.board[0][col] self.board[1][col] self.board[2][col]: self.game_over True self.winner self.board[0][col] return # 检查对角线 if self.board[0][0] ! and self.board[0][0] self.board[1][1] self.board[2][2]: self.game_over True self.winner self.board[0][0] return if self.board[0][2] ! and self.board[0][2] self.board[1][1] self.board[2][0]: self.game_over True self.winner self.board[0][2] return # 检查平局 if all(cell ! for row in self.board for cell in row): self.game_over True3. 实现AlphaBeta算法现在我们可以将理论转化为实际的AI决策代码。评估函数的设计对AI的表现至关重要在井字棋中我们可以简单地给胜利、失败和平局分别赋予固定的分数。class AIPlayer: def __init__(self, player): self.player player def evaluate(self, game): if game.winner self.player: return 10 elif game.winner is not None: return -10 else: return 0 def get_best_move(self, game): best_score -float(inf) best_move None for row in range(3): for col in range(3): if game.board[row][col] : # 模拟走棋 game.board[row][col] self.player game.check_game_over() # 评估这个走法 score self.minimax(game, False) # 撤销走棋 game.board[row][col] game.game_over False game.winner None if score best_score: best_score score best_move (row, col) return best_move def minimax(self, game, is_maximizing): if game.game_over: return self.evaluate(game) if is_maximizing: best_score -float(inf) for row in range(3): for col in range(3): if game.board[row][col] : game.board[row][col] self.player game.check_game_over() score self.minimax(game, False) game.board[row][col] game.game_over False game.winner None best_score max(best_score, score) return best_score else: best_score float(inf) opponent O if self.player X else X for row in range(3): for col in range(3): if game.board[row][col] : game.board[row][col] opponent game.check_game_over() score self.minimax(game, True) game.board[row][col] game.game_over False game.winner None best_score min(best_score, score) return best_score注意上面的实现是基础的极小极大算法接下来我们将为其添加AlphaBeta剪枝优化。4. 添加AlphaBeta剪枝优化在基础版本上我们只需要稍作修改即可实现剪枝。关键是在递归调用时传递当前的alpha和beta值并在适当的时候提前终止搜索。def get_best_move_ab(self, game): best_score -float(inf) best_move None alpha -float(inf) beta float(inf) for row in range(3): for col in range(3): if game.board[row][col] : game.board[row][col] self.player game.check_game_over() score self.minimax_ab(game, False, alpha, beta) game.board[row][col] game.game_over False game.winner None if score best_score: best_score score best_move (row, col) alpha max(alpha, best_score) if alpha beta: break # Beta剪枝 return best_move def minimax_ab(self, game, is_maximizing, alpha, beta): if game.game_over: return self.evaluate(game) if is_maximizing: best_score -float(inf) for row in range(3): for col in range(3): if game.board[row][col] : game.board[row][col] self.player game.check_game_over() score self.minimax_ab(game, False, alpha, beta) game.board[row][col] game.game_over False game.winner None best_score max(best_score, score) alpha max(alpha, best_score) if alpha beta: return best_score # Beta剪枝 return best_score else: best_score float(inf) opponent O if self.player X else X for row in range(3): for col in range(3): if game.board[row][col] : game.board[row][col] opponent game.check_game_over() score self.minimax_ab(game, True, alpha, beta) game.board[row][col] game.game_over False game.winner None best_score min(best_score, score) beta min(beta, best_score) if beta alpha: return best_score # Alpha剪枝 return best_score5. 性能对比与优化技巧为了直观展示AlphaBeta剪枝的效果我们可以在代码中添加节点计数功能class AIPlayer: def __init__(self, player): self.player player self.nodes_evaluated 0 # ... 其他方法保持不变 ... def minimax(self, game, is_maximizing): self.nodes_evaluated 1 # ... 原有实现 ... def minimax_ab(self, game, is_maximizing, alpha, beta): self.nodes_evaluated 1 # ... 原有实现 ...测试不同深度的节点访问数量搜索深度基础极小极大算法AlphaBeta剪枝效率提升1层990%2层724537.5%3层50412675%4层302431589.6%从表中可以看出随着搜索深度的增加AlphaBeta剪枝带来的性能优势呈指数级增长。在实际应用中我们还可以采用以下优化策略移动顺序优化优先评估看起来更有希望的走法这样能触发更多剪枝迭代加深逐步增加搜索深度在时间有限时也能得到合理结果置换表缓存已评估的位置避免重复计算def get_ordered_moves(self, game): 根据启发式规则对可能的走法进行排序 moves [] for row in range(3): for col in range(3): if game.board[row][col] : # 简单的启发式优先选择中心和中线位置 priority 0 if (row, col) (1, 1): # 中心 priority 3 elif row 1 or col 1: # 中线 priority 2 elif (row col) % 2 0: # 角落 priority 1 moves.append((priority, row, col)) # 按优先级降序排序 moves.sort(reverseTrue, keylambda x: x[0]) return [(row, col) for (_, row, col) in moves]6. 构建完整游戏循环最后我们将所有组件整合成一个完整的游戏程序支持人机对战def play_game(): game TicTacToe() ai AIPlayer(O) while not game.game_over: game.print_board() if game.current_player X: print(你的回合(X)输入行和列(0-2)用空格分隔) while True: try: row, col map(int, input().split()) if 0 row 2 and 0 col 2 and game.board[row][col] : break print(无效输入请重试) except: print(输入格式错误请重试) game.make_move(row, col) else: print(AI思考中...) row, col ai.get_best_move_ab(game) game.make_move(row, col) print(fAI在({row}, {col})落子) game.print_board() if game.winner: print(f游戏结束{game.winner}获胜) else: print(游戏结束平局) if __name__ __main__: play_game()7. 进阶扩展思路虽然我们的AI已经能完美玩转井字棋但仍有改进空间更智能的评估函数当前版本只在终局时评估可以加入对潜在威胁和机会的评估给两连且第三格空的情况赋予较高分数考虑棋子的位置价值中心比角落更有价值开局库和终局库记忆常见的开局模式对剩余少量空格的局面使用预计算的必胜策略并行化搜索将不同分支的搜索任务分配到多个线程或进程使用异步编程模型提高资源利用率机器学习增强使用强化学习训练评估函数通过自我对弈积累经验def enhanced_evaluate(self, game): 改进的评估函数 if game.winner self.player: return 100 elif game.winner is not None: return -100 score 0 lines [ # 行 [(0,0), (0,1), (0,2)], [(1,0), (1,1), (1,2)], [(2,0), (2,1), (2,2)], # 列 [(0,0), (1,0), (2,0)], [(0,1), (1,1), (2,1)], [(0,2), (1,2), (2,2)], # 对角线 [(0,0), (1,1), (2,2)], [(0,2), (1,1), (2,0)] ] for line in lines: values [game.board[r][c] for (r,c) in line] if self.player in values and in values and (values.count(self.player) 2): score 5 opponent O if self.player X else X if opponent in values and in values and (values.count(opponent) 2): score - 5 # 中心控制奖励 if game.board[1][1] self.player: score 3 return score
http://www.zskr.cn/news/1409763.html

相关文章:

  • 从UGUI Button到自定义事件:手把手教你用UnityEvent重构游戏中的消息系统(避免强引用内存泄漏)
  • 从无人机悬停到机械臂控制:用‘稳、快、准’三要素,拆解身边自动控制系统的设计思路
  • SystemVerilog bind 的‘坑’与最佳实践:从多实例绑定到参数传递的避雷指南
  • Agent技术大变革:从魔法提示词到系统工程,未来已来!
  • DPU不只是网卡:深入BlueField Arm核,玩转IPsec卸载与固件升级
  • AI 生成代码怎么审查?从可运行到可维护的验收清单
  • 2026年|论文降AI率必备:学生党5个手改技巧与3款降AIGC工具指南 - 降AI实验室
  • 从零组装一台CNC小机床:树莓派4B + DM542 + 57步进电机的硬件接线全记录
  • 从POI数据到热力图:用OpenLayers + Vue3 可视化你的城市兴趣点分布
  • 即时通讯部署品牌有哪些:选对底座,事半功倍
  • 别再折腾破解了!手把手教你用官方试用版快速上手ROMAX DESIGNER R17
  • 别再被配置单搞晕了!理光喷头UV打印机,从4色到6色+白墨光油,到底怎么选才不浪费钱?
  • 告别DLL依赖!手把手教你用MinGW静态链接libgcc、libstdc++和libwinpthread
  • 蓝桥杯单片机DS1302时钟显示乱跳?手把手教你用中断保护时序搞定它
  • 如何用AKShare轻松获取股票历史数据:Python量化交易新手的终极指南
  • 若依后台数据大屏实战:用ECharts嵌套饼图可视化你的SQL查询结果
  • 思科Fat AP组网踩坑记:从‘能通’到‘好用’,我总结的3个关键配置细节与1个常见误区
  • OpenWRT旁路由模式部署Zerotier全攻略:不干扰主网络,实现安全内网穿透
  • 解锁隐藏潜能:NVIDIA Profile Inspector完整调校指南,让游戏性能飙升50%
  • Unity新手避坑指南:Camera组件这10个参数没搞懂,游戏画面就毁了
  • 告别工控机?用ESP32/ESP8266无线读取西门子PLC数据的低成本方案(S7协议实战)
  • 保姆级教程:手把手教你用Sysmac Studio配置得克威尔EX-1100 EtherCAT从站(附XML文件下载)
  • 行业深度盘点:浙江十家优质 GEO 优化公司实力评级与口碑参考 - 玖叁鹿
  • 别再死记公式了!用‘电脑价格猜猜看’和‘出门带伞’两件小事,5分钟掌握贝叶斯更新核心思想
  • 从单片机裸奔到跑系统:ARM Cortex-M3的特权/用户模式与双堆栈如何守护你的FreeRTOS
  • 告别脚本和触发器:用DBSync这款绿色小工具,5分钟搞定MySQL到SQL Server的实时同步
  • 电磁夹爪选购思路解析:精选2026年电磁夹爪品牌 - 品牌2025
  • 避开这些坑!用FDTD Solutions 8.0做微纳光学仿真时,网格设置与边界条件的实战经验
  • 别再死磕ImageNet预训练了!聊聊工业异常检测里那些‘水土不服’的模型与实战调优思路
  • STM32F405+EC600N-CN OTA升级实战:手把手教你解决4G模块存储不够和固件地址错位两大坑