Python实战教程:用Pygame从零打造五子棋对战游戏

为什么选五子棋作为Python实战项目
对于正在学习Python的初学者来说,从零构建一个完整的小游戏,是巩固编程基础、理解程序结构的绝佳方式。五子棋(Gomoku)规则简单、逻辑清晰,却涵盖了图形界面绘制、鼠标事件处理、游戏状态管理、胜负判定算法等多个核心知识点,是一个兼具趣味性与教学价值的入门级实战项目。
值得一提的是,五子棋在计算机博弈(Computer Game Playing)研究领域有着悠久的历史地位。五子棋起源于中国古代,后经日本发展为现代竞技形式,在19世纪末传入欧洲并形成国际规则。在禁手规则(黑棋禁止三三、四四、长连)下,理论上已证明先手(黑棋)必胜,但标准15×15五子棋的完整状态空间仍未被穷举,这使其成为展示搜索算法与启发式剪枝技术的绝佳教学案例——从入门练手到AI进阶,五子棋提供了一条完整的学习路径。
本文基于B站UP主分享的Python五子棋对战小游戏教程,梳理该项目的完整实现思路。整个项目被拆分为六个清晰的模块,从模块导入到主循环,环环相扣,非常适合初学者按部就班地跟练。
六大核心模块:项目结构一览
根据教程作者的拆解,这个五子棋游戏的完整代码由六个部分组成,每一部分承担着独立的职责,体现了良好的程序结构设计思维。
第一部分:模块导入与初始化
项目使用 pygame 这一经典的Python游戏开发库实现图形界面。Pygame基于SDL(Simple DirectMedia Layer)底层图形库封装而来,自2000年发布以来已成为Python入门游戏开发的事实标准,提供了窗口管理、图形渲染、声音播放、键鼠事件处理等一整套工具链,让开发者无需深入了解底层图形API即可快速构建2D游戏原型。
SDL于1998年由Sam Lantinga开发,最初是为了将《文明:权力的召唤》移植到Linux而创建,采用硬件抽象层(HAL)设计:在Windows上调用DirectX或GDI+,在macOS上调用Metal/OpenGL,在Linux上调用X11、Wayland或KMS/DRM,实现真正的跨平台图形输出。Pygame通过Python的C扩展机制(CPython Extension)将SDL的C接口包装为Python可调用的模块——例如pygame.Surface对应SDL内部的SDL_Surface结构体,pygame.display.flip()实际调用SDL_Flip()完成帧缓冲交换。这种分层架构意味着,即便Python本身是解释执行的,图形渲染的核心计算依然在C层高效完成,这也是初学者用寥寥数百行Python代码就能实现流畅图形界面的根本原因。
在程序开头,需要导入必要的模块并调用 pygame.init() 完成初始化工作,为后续的窗口创建、事件监听打好基础。
第二部分:颜色与游戏参数定义
这一部分集中定义程序中会反复用到的常量,包括棋盘颜色、黑白棋子颜色、线条颜色等RGB值,以及棋盘尺寸(15×15)、窗口大小、格子间距等游戏参数。将这些参数统一管理,既方便后续调用,也便于整体调整,是良好的编程习惯。
RGB(红绿蓝)色彩模型是计算机图形学中最常用的颜色表示方式,每个分量取值0-255,三值组合可表达约1670万种颜色。这一模型的物理依据是人眼视网膜上存在三种锥细胞(S/M/L型),分别对短波长(蓝色,~420nm)、中波长(绿色,~530nm)和长波长(红色,~560nm)的光最为敏感——此理论由托马斯·杨(Thomas Young)于1802年提出,后由赫尔曼·冯·亥姆霍兹(Hermann von Helmholtz)完善为杨-亥姆霍兹三色理论。计算机显示器的每个像素由红、绿、蓝三个子像素构成,8位深度下三通道组合产生256³≈1677万种颜色,超过人眼能分辨的颜色数量上限(约1000万种)。在Pygame中,颜色通常以三元组(R, G, B)传入,也支持四元组(R, G, B, A)添加Alpha透明度通道,用于实现半透明效果。在实际编程中,将所有颜色常量集中定义(如 BLACK = (0, 0, 0)、BOARD_COLOR = (220, 179, 92)),不仅避免了"魔法数字"的出现,还使日后更换主题配色时只需修改一处即可全局生效,是提升代码可维护性的重要习惯。
第三部分:字体设置
游戏中需要显示当前回合状态、胜利提示等文字信息,因此需要提前设置字体对象。通过 pygame.font 模块加载合适的字体和字号,为状态显示和胜利弹窗提供支持。
在Pygame中,字体对象创建后可反复调用 render() 方法生成文字Surface,再通过 blit() 绘制到屏幕指定位置。从底层原理看,render() 方法会将字符串栅格化(Rasterize)为像素图像:现代字体文件(如TrueType的.ttf或OpenType的.otf格式)以贝塞尔曲线(Bézier Curves)描述字形轮廓,Pygame底层调用FreeType2库执行栅格化——首先将贝塞尔曲线转换为多边形轮廓,然后用扫描线算法(Scanline Algorithm)填充像素,最后应用亚像素抗锯齿(Sub-pixel Anti-aliasing)来平滑边缘。这一过程在字体尺寸较大时计算量显著增加,因此"创建一次、多次渲染"的设计思路至关重要:对于游戏中频繁显示的固定文字(如"黑棋回合"),建议在初始化阶段一次性渲染好并缓存Surface结果;对于需要动态变化的文字(如计时器数字),则在每次数值改变时才重新调用 render(),以平衡灵活性与性能。

游戏状态管理与函数设计
第四部分:游戏初始化状态
这一部分负责维护游戏的运行状态——用一个二维数组记录棋盘上每个位置的落子情况(空、黑子、白子),用变量跟踪当前轮到哪一方落子,以及标记游戏是否已经结束。
用二维列表(List of Lists)表示棋盘状态是矩阵类问题的经典数据结构选择:15×15的棋盘对应一个 board[15][15] 的二维数组,每个元素存储该格状态(0=空,1=黑子,2=白子),坐标映射直观,访问任意位置的时间复杂度为O(1)。在Python中,可通过列表推导式 board = [[0]*15 for _ in range(15)] 快速创建这一结构——注意不能用 [[0]*15]*15,这是初学者最常犯的经典错误:*15操作并不复制内层列表,而是让外层列表的15个槽位全部指向同一个内层列表对象(浅拷贝,Shallow Copy),导致修改board[0][0]会同时改变所有行的第0列。而列表推导式每次迭代都调用[0]*15创建全新的列表对象,确保15行相互独立。若追求更高的内存效率,可改用NumPy的np.zeros((15,15), dtype=np.int8),其以真正的连续C数组存储数据,访问速度比Python列表快数十倍,更适合后续引入AI搜索算法时的高频棋盘状态读写。清晰的状态管理是保证游戏逻辑正确运行的基础。
第五部分:核心函数定义
作者将核心逻辑封装成多个独立函数,充分体现了模块化编程的思想,主要包括:
- 玩家名称转换函数:将内部棋子标记(如1、2)转换为"黑棋""白棋"等可读文字。
- 胜负判定函数:检测某一方是否达成五子连珠,是整个游戏的算法核心。该函数需分别判断横向、纵向、正斜线、反斜线四个方向的连子情况。常见实现方式是从最新落子点向两侧延伸计数,若某方向连续同色棋子总计达到5枚即判定获胜。由于每次只需检查最新落子点周围固定范围(最多向每侧延伸4格,共8×4=32个格子),时间复杂度为O(1),远比每次扫描全棋盘(O(n²))高效。更进阶的位棋盘(Bitboard)表示法可将棋盘状态压缩为整数的二进制位,利用CPU位运算在单条指令内完成多格检查,进一步提速数十倍——这一"局部检查"与"位操作优化"的双重思路,是理解算法局部性原理与底层优化的直观案例。
- 棋盘绘制函数:负责渲染15×15网格及已落下的棋子。
- 状态显示函数:实时显示当前回合与提示信息。
- 胜利弹窗函数:一方获胜时弹出对应提示。

将功能拆分为函数,不仅让代码结构更清晰,也大幅提升了可维护性与复用性——这正是初学者需要重点培养的工程化思维。
游戏主循环与实际运行效果
第六部分:游戏主循环
主循环是所有Pygame游戏的运行核心,也是事件驱动编程(Event-Driven Programming)范式的典型体现。与传统顺序执行的程序不同,事件驱动程序的执行流程由外部事件(鼠标点击、键盘输入、窗口关闭等)驱动——程序本身并不主动推进,而是被动等待并响应事件。
Pygame的主循环本质上是一个持续轮询(Polling)事件队列的无限循环:每帧调用 pygame.event.get() 取出队列中积累的所有事件,逐一判断类型并执行对应逻辑,最后调用 pygame.display.flip() 将缓冲区内容刷新到屏幕。这种"获取事件→更新状态→重绘画面"的三段式结构,即著名的游戏循环模式(Game Loop Pattern)——由Robert Nystrom在《游戏编程模式》一书中系统归纳,是几乎所有实时交互程序的基础架构,从简单的2D小游戏到商业3A大作均遵循这一范式。帧率(FPS)控制同样关键:Pygame提供pygame.time.Clock对象,调用clock.tick(60)可精确限制帧率上限为60FPS,其内部通过计算上帧耗时、调用操作系统sleep()函数补足剩余时间来实现节流(Throttling)——对于五子棋这类回合制游戏,帧率约束不影响游戏逻辑,但可显著降低CPU占用(无限制循环会导致单核占用率接近100%)。理解事件驱动与游戏循环,是初学者从线性脚本思维转向GUI/游戏开发思维的关键跨越。主循环持续监听用户输入,根据事件更新游戏状态,并不断重绘画面。当玩家点击鼠标左键时,程序计算落点对应的棋盘坐标,放置当前回合的棋子,随即调用胜负判定函数检查是否分出胜负。

实际演示效果
运行代码后,游戏窗口呈现标准的15×15棋盘,玩法直观流畅:
- 鼠标左键点击棋盘任意交叉点,落下黑子;
- 落子后回合自动切换到白方;
- 黑白双方轮流落子,率先达成五子连珠即判定获胜;
- 游戏结束后,点击任意位置即可重新开局。

演示中分别展示了黑棋获胜和白棋获胜两种情况,系统均能正确弹出"黑棋胜利"或"白棋胜利"提示,验证了胜负判定逻辑的正确性。
从练手到进阶:实战项目的真正价值
这个Python五子棋项目规模虽小,却"麻雀虽小,五脏俱全"。它让初学者在一个完整项目中综合运用变量、列表、函数、循环、条件判断等基础语法,同时接触图形界面开发与事件驱动编程的核心思想。
对于想要从入门迈向进阶的学习者,动手完成大量类似实战项目,远比单纯阅读教程更能提升编程能力。建议跟练完成后,尝试自行扩展功能,例如:加入悔棋功能、实现人机对战AI、增加计时器或计分系统等。
其中,实现人机对战AI是最具挑战性也最具教学价值的进阶方向。经典的Minimax算法由约翰·冯·诺依曼(John von Neumann)于1928年在博弈论论文中正式提出,后被克劳德·香农(Claude Shannon)于1950年引入计算机国际象棋领域。其核心假设是双方均采取最优策略:算法将棋局建模为一棵博弈树,AI(Max方)试图最大化己方得分,玩家(Min方)试图最小化AI得分,递归搜索所有可能的落子序列,在叶节点通过静态评估函数(Heuristic Evaluation Function)打分并逐层回传最优值。然而,五子棋每步的合法落点多达数十至数百个,纯Minimax在深度稍大时搜索空间会呈指数级爆炸(O(b^d),b为分支因子,d为搜索深度)。
Alpha-Beta剪枝正是为此而生,由约翰·麦卡锡(John McCarthy)团队在1956年前后独立发现:算法在搜索过程中维护两个边界值α(已知最优Max值)和β(已知最优Min值),当发现某分支不可能超越当前边界时立即剪掉,理论上可将搜索节点数从O(b^d)压缩至O(b^(d/2))——意味着在相同时间内可将搜索深度翻倍,使AI棋力显著提升。现代五子棋AI还会在Alpha-Beta基础上叠加迭代加深(Iterative Deepening)、置换表(Transposition Table,缓存已计算棋局的评估结果)和启发式落点排序(Move Ordering,优先搜索最有价值的落点),进一步将实际搜索效率压缩到理论极限的数倍以内。
从双人对战扩展到人机对战,不仅是功能上的升级,更是从基础算法迈向人工智能领域的重要一步。通过不断改造与优化,才能真正将知识内化为自己的能力。
核心要点
核心要点
核心要点
相关推荐

Claude被曝可在正常图片中隐藏秘密信息
Reddit帖子称Claude Fable 5.1能在正常图片中隐藏秘密信息,本文梳理事件背景、图片隐写技术原理及潜在安全风险,并给出从传闻走向验证的测试路径建议。

AI助手何时该主动建议?时机决定一切
AI助手何时该主动建议?Reddit讨论揭示:同样的建议在不同时机感受迥异。本文分析主动建议的双面性、用户期待的分界线及设计原则,探讨如何平衡自动化与用户控制。

联邦政府拨款8500万美元,CFS研发聚变专用半导体
联邦政府向Commonwealth Fusion Systems拨款8500万美元,用于研发聚变电站所需的导体与功率半导体。本文解读这笔资助对聚变产业链与商业化路径的意义。