首页 / 资讯中心 / 文章详情

Python+PyQt5五子棋毕设:深度搜索与α-β剪枝实战

Python+PyQt5五子棋毕设:深度搜索与α-β剪枝实战 ★ FEATURED ARTICLE
简介这是一份面向计算机相关专业学生与AI爱好者的毕业设计级五子棋项目源码基于Python与PyQt5实现完整的人机博弈对弈界面核心算法涵盖深度优先搜索与α-β剪枝优化适合作为人工智能、博弈树搜索方向的学习范例也可直接用于毕设、课程设计或项目立项演示。资源包共17个文件包含4个Python源码文件、1个Qt界面文件与1个资源文件另有9张png界面截图、1个ico图标及README说明文档压缩包约5.63MB结构清晰便于快速上手。目前已有213人学习下载。项目代码均经过实际运行测试答辩评审平均分达96分读者可从中掌握PyQt5界面搭建、五子棋胜负判定、极大极小搜索与剪枝策略的完整实现思路并在此基础上修改扩展功能如调整评估函数或增加难度等级是学习博弈AI与桌面应用开发的实用参考。1. 从一份能跑通的毕设说起PythonPyQt5 五子棋到底交付了什么很多计算机专业的同学在选毕设题目时都会卡在同一个地方想做 AI 方向又怕算法太深写不出来想做桌面应用又担心没有技术含量。这份基于 PythonPyQt5 的多智能体博弈五子棋恰好卡在两者的交叉点上——它既有一个能看得见摸得着的图形界面又在底层塞进了深度搜索和 α-β 剪枝这套博弈树的核心逻辑。拿到手的第一感觉是这不是那种只跑个 print 的玩具代码而是一个从 UI 到 AI 决策完整闭环的小型工程。它解决的问题很具体让你在答辩时能指着屏幕说“这里 AI 走这一步是因为它搜索了未来 N 层并且剪掉了哪些废分支”。适合的人群也很明确——计科、人工智能、通信、自动化等专业的在校生需要一份能讲清楚原理、又能现场演示的毕设或课设也适合刚学完 Python 基础、想找一个有界面有算法的项目来练手的进阶者。整个包里有start.py作为入口gobang_ui.py负责界面AI.py承载博弈逻辑gobang_qrc_rc.py是资源文件结构清晰没有故弄玄虚的封装。2. 环境搭建与首次运行把 PyQt5 和资源文件理顺2.1 为什么是 PyQt5 而不是 Tkinter选 PyQt5 做五子棋界面不是因为它时髦而是因为棋盘绘制这件事对控件刷新和事件响应有硬要求。Tkinter 画 15×15 的网格加棋子重绘时容易闪烁而且鼠标点击坐标和棋盘交叉点的映射要自己写不少换算。PyQt5 的QPainter配合QWidget的paintEvent可以做到局部刷新棋子落下的动画和悬停提示都更自然。另一个现实原因是这份代码的 UI 文件是用 Qt Designer 生成的gobang_ui.py里能看到典型的setupUi结构如果你后续想改布局直接拖控件比手写 Tkinter 布局代码快得多。安装 PyQt5 本身不复杂但版本要卡一下。Python 3.8 到 3.10 配 PyQt5 5.15.x 是经过大量项目验证的组合太新的 Python 3.12 在某些系统上装 PyQt5 会碰到 wheel 缺失的问题。# 建议在虚拟环境里操作避免污染全局包 python -m venv venv # Windows 激活 venv\Scripts\activate # macOS/Linux 激活 source venv/bin/activate # 安装 PyQt5指定 5.15 系列 pip install PyQt55.15.9这里指定5.15.9是因为这个版本对pyrcc生成的资源文件兼容性最稳。代码里的gobang_qrc_rc.py就是pyrcc5把.qrc资源编译后的产物里面通常打包了棋盘背景、棋子图标、favicon 等。如果你拿到的是源码包这个文件已经生成好了不需要自己再跑pyrcc5但如果你改了.qrc里的图片就得重新编译。2.2 入口文件与启动顺序start.py是整个程序的入口它做的事情通常就三件创建QApplication、实例化主窗口、进入事件循环。但这份代码里有一个容易忽略的点——AI.py的导入时机。如果AI.py在模块顶层就初始化了搜索树或者加载了棋型评估表那么启动时会有一小段延迟。我一般会先单独跑一次AI.py里的测试函数确认评估逻辑不报错再启动界面。# start.py 的典型结构根据项目文件推断 import sys from PyQt5.QtWidgets import QApplication from gobang_ui import GobangWindow # 主窗口类 if __name__ __main__: app QApplication(sys.argv) window GobangWindow() window.show() sys.exit(app.exec_())逻辑说明QApplication管理整个 GUI 程序的生命周期GobangWindow继承自QMainWindow或QWidget在它的__init__里会调用setupUi完成界面搭建同时连接棋盘控件的鼠标点击信号到落子槽函数。sys.exit(app.exec_())保证窗口关闭时进程干净退出。参数方面sys.argv直接透传即可这个项目没有用到命令行参数。运行命令就是最朴素的python start.py如果报ModuleNotFoundError: No module named PyQt5说明虚拟环境没激活或者 pip 装到了别的解释器里。用which pythonLinux/macOS或where pythonWindows确认当前解释器路径再pip list看一眼 PyQt5 在不在列表里。3. 深度搜索与 α-β 剪枝AI.py 里的博弈树怎么搭3.1 棋型评估给每个局面打分五子棋 AI 的核心不是搜索本身而是评估函数。搜索只是在有限时间内找到评估分最高的走法如果评估函数把活三当成死三搜得再深也是白搭。这份代码里AI.py通常会定义一个棋型分值表常见做法是用模式匹配来识别“活四”“冲四”“活三”“眠三”等。# AI.py 中棋型评估的简化示意 SCORE { FIVE: 100000, # 五连 LIVE_FOUR: 10000, # 活四 RUSH_FOUR: 1000, # 冲四 LIVE_THREE: 1000, # 活三 SLEEP_THREE: 100, # 眠三 LIVE_TWO: 100, # 活二 SLEEP_TWO: 10, # 眠二 } def evaluate_point(board, x, y, role): # 以 (x, y) 为中心向四个方向统计连子情况 # 返回该点对 role 方的分值贡献 total 0 for dx, dy in [(1,0), (0,1), (1,1), (1,-1)]: count 1 block 0 # 正向统计 for step in range(1, 5): nx, ny x dx*step, y dy*step if not in_board(nx, ny): block 1 break if board[nx][ny] role: count 1 elif board[nx][ny] 0: break else: block 1 break # 反向统计同理... total score_of(count, block) return total逻辑说明evaluate_point不是全局评估而是评估“在某个空点落子后该点周围形成的棋型价值”。这种增量评估在搜索里很常用因为每走一步只需要看落子点附近的变化不用重算整个棋盘。参数role区分黑白block记录被对方堵住的端数count是连子数。score_of根据连子数和封堵情况查表返回分值。这里有个血泪经验很多同学直接把LIVE_THREE和RUSH_FOUR设成一样的分结果 AI 会优先去堵冲四而不去形成自己的活四因为冲四的威胁看起来更急。实际上活四的胜率远高于冲四分值必须拉开一个数量级。3.2 极大极小搜索与 α-β 剪枝的落点AI.py里搜索部分一般会有一个minimax或negamax函数配合alpha和beta两个边界值。α-β 剪枝的本质是在极大层如果当前节点的评估值已经超过了祖先节点已知的 β 上界那这个分支后面的内容就不用看了因为对手不会让你走到这一步。def alphabeta(board, depth, alpha, beta, is_max, role): if depth 0 or game_over(board): return evaluate_board(board, role) if is_max: max_eval -float(inf) for x, y in generate_moves(board): board[x][y] role eval_score alphabeta(board, depth-1, alpha, beta, False, role) board[x][y] 0 max_eval max(max_eval, eval_score) alpha max(alpha, eval_score) if beta alpha: break # β 剪枝 return max_eval else: min_eval float(inf) for x, y in generate_moves(board): board[x][y] 3 - role # 对手落子 eval_score alphabeta(board, depth-1, alpha, beta, True, role) board[x][y] 0 min_eval min(min_eval, eval_score) beta min(beta, eval_score) if beta alpha: break # α 剪枝 return min_eval逻辑说明is_max为真时轮到 AI 自己走它要最大化评估值为假时轮到对手对手会最小化 AI 的评估值。alpha是当前路径上极大层已经找到的最好值beta是极小层已经找到的最坏值。当beta alpha时说明这个分支不可能影响最终决策直接break。generate_moves是走法生成函数常见优化是只考虑已有棋子周围两格内的空点而不是全盘 225 个点这样搜索宽度能降一个数量级。参数depth控制搜索层数。这份毕设里通常设 4 到 6 层再深的话 Python 的递归开销会让界面卡住。如果你在答辩时想演示“更深搜索更强”可以临时把depth调到 6但要提前跟评委说明会有几秒延迟。4. 多智能体博弈的界面联动落子、悔棋与状态同步4.1 棋盘绘制与鼠标事件映射gobang_ui.py里的棋盘通常是一个自定义QWidget在paintEvent里画网格和棋子。鼠标点击时mousePressEvent拿到的是像素坐标需要换算成棋盘交叉点的行列索引。这个换算的精度直接决定落子准不准。# gobang_ui.py 中坐标映射的典型写法 CELL_SIZE 40 MARGIN 30 def pixel_to_grid(self, px, py): # 将像素坐标转换为棋盘行列 col round((px - MARGIN) / CELL_SIZE) row round((py - MARGIN) / CELL_SIZE) if 0 row 15 and 0 col 15: return row, col return None, None逻辑说明MARGIN是棋盘边缘留白CELL_SIZE是格子间距。用round而不是整除是因为点击位置很少正好落在交叉点上四舍五入能吸附到最近的交叉点。如果发现落子总是偏一格先检查MARGIN和CELL_SIZE是否和paintEvent里画网格时用的值一致——这两个地方各写一套常量是新手最常见的翻车点。4.2 人机交替与悔棋的实现人机博弈的流程控制一般放在主窗口类里玩家点击后先判断该位置是否为空、是否轮到玩家然后落子并刷新界面接着调用AI.py的搜索函数拿到 AI 的走法再落子刷新。悔棋则是把最近两步玩家一步、AI 一步从棋盘上撤掉同时把历史记录栈弹出。def on_click(self, row, col): if self.board[row][col] ! 0 or self.game_over: return if self.current_player ! self.human_role: return self.place_stone(row, col, self.human_role) if self.check_win(row, col, self.human_role): self.show_result(你赢了) return self.current_player self.ai_role # 调用 AI 搜索 ai_row, ai_col self.ai.get_best_move(self.board, self.ai_role) self.place_stone(ai_row, ai_col, self.ai_role) if self.check_win(ai_row, ai_col, self.ai_role): self.show_result(AI 赢了) return self.current_player self.human_role逻辑说明place_stone负责更新棋盘数组、往历史栈里压入记录、触发update()重绘。check_win只需要检查刚落子的点向四个方向延伸是否形成五连不用全盘扫描。悔棋时从历史栈弹出两条记录把对应位置置零并切换current_player回人类。注意如果 AI 搜索耗时较长界面会短暂无响应常见做法是在搜索前把鼠标事件禁用或者用QTimer.singleShot把 AI 走子延后到下一帧让界面先刷新出玩家的棋子。5. 避坑与排查从环境到算法的五个真实翻车点5.1 现象运行start.py报ImportError: DLL load failed原因Windows 上 PyQt5 依赖的 Qt 动态库没有正确加载通常是因为 Python 版本和 PyQt5 wheel 不匹配或者系统缺少 Visual C 运行库。解决先确认 Python 是 3.83.10 的 64 位版本然后卸载重装pip install PyQt55.15.9。如果还不行装一下 VC 2015-2022 运行库。别去网上找那些来路不明的 DLL 替换越换越乱。5.2 现象棋盘画出来了但点击没反应原因自定义棋盘控件的mousePressEvent没有正确绑定或者控件被上层透明 widget 挡住了。解决在gobang_ui.py里检查棋盘控件是否设置了setMouseTracking(True)以及mousePressEvent里是否调用了super().mousePressEvent(event)导致事件被吞。另一个可能是paintEvent里画的棋盘区域和实际控件大小不一致点击落在了控件外面。5.3 现象AI 第一步思考很久后面反而快原因搜索深度固定时开局阶段棋盘空点最多generate_moves产生的分支数最大α-β 剪枝在根节点附近效果最弱。解决在AI.py里给开局加一个简单的启发式——如果棋盘上棋子少于 4 个直接走中心点或者中心附近的随机点不走完整搜索。另外把generate_moves限制在已有棋子周围两格内能显著减少开局分支。5.4 现象AI 明明能赢却去堵对方原因评估函数里防守分和进攻分的权重没调好或者搜索时没有把“自己形成五连”的分数设得足够高。解决检查SCORE表里FIVE是否远大于其他所有棋型之和。另一个常见错误是在evaluate_board里对双方分别评估后简单相减但减的时候没有考虑轮到谁走——如果轮到 AI 走AI 的活四应该比对手的活四权重更高。5.5 现象悔棋后 AI 走法变了原因悔棋只恢复了棋盘数组但没有恢复 AI 内部的搜索缓存或随机种子。如果AI.py里用了random来做同分走法的随机选择每次搜索的结果可能不同。解决悔棋时把历史栈完整回滚并且如果 AI 有置换表或缓存一并清空。如果希望 AI 走法可复现在start.py里固定random.seed(42)。6. 进阶调参与验证让 AI 强度可量化、可演示把 AI 调到一个“看起来聪明”的状态比把代码跑起来更花时间。我一般会用一个简单的自对弈脚本来验证搜索深度和评估函数的效果而不是靠肉眼盯着棋盘猜。# 自对弈验证脚本放在项目根目录单独运行 from AI import AI from copy import deepcopy def self_play(depth_black4, depth_white2, rounds10): black_win 0 for _ in range(rounds): board [[0]*15 for _ in range(15)] ai_black AI(depthdepth_black) ai_white AI(depthdepth_white) turn 1 # 1 黑2 白 while True: ai ai_black if turn 1 else ai_white x, y ai.get_best_move(board, turn) board[x][y] turn if ai.check_win(board, x, y, turn): if turn 1: black_win 1 break turn 3 - turn print(f黑方深度{depth_black}胜率{black_win}/{rounds}) if __name__ __main__: self_play(depth_black4, depth_white2, rounds10)逻辑说明这个脚本让不同搜索深度的 AI 互相对弈深度 4 的黑方如果胜率明显高于深度 2 的白方说明搜索加深确实带来了棋力提升评估函数没有把搜索方向带偏。rounds设 10 是因为每局搜索耗时可能几秒到十几秒跑太多轮不现实。如果黑方胜率低于 7/10优先检查评估函数里活三和冲四的分值是否合理而不是继续加深度。参数调整上depth每加 1搜索节点数大约翻 3 到 5 倍有了 α-β 剪枝后但棋力提升不是线性的。我一般会做一组对比搜索深度平均每步耗时对深度 2 的胜率适用场景2 0.1 秒基准演示、低配机器40.52 秒约 80%答辩默认6310 秒约 95%性能演示需提前说明延迟如果答辩现场机器性能一般建议默认用深度 4并在界面上加一个“思考中”的提示标签避免评委以为程序卡死。深度 6 可以作为“展示搜索威力”的按钮点之前先口头说明会有几秒等待。还有一个容易被忽略的验证点gobang_qrc_rc.py里的资源路径。如果你把项目拷贝到另一台机器图片路径如果是绝对路径就会失效。检查这个文件里qt_resource_data的引用方式确保用的是相对路径或者 Qt 资源系统内部的:/前缀。我吃过一次亏在实验室机器上跑得好好的换到答辩教室的电脑上图标全没了就是因为资源文件里写死了C:\Users\xxx\...。从那以后我每次拿到带_rc.py的项目都先全局搜一遍盘符和用户目录名确认没有硬编码路径才继续往下调。希望这份拆解能帮你把这份五子棋毕设跑通、讲清、调出效果。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站