示例工程教程【免费下载链接】materialsBonus materials, exercises, and example projects for our Python tutorials项目地址https://gitcode.com/gh_mirrors/ma/materials点击查看免费下载本文以tic-tac-toe-ai-python项目中的 library 子包 为核心讲解如何把一套与 UI 完全解耦的纯 Python 井字棋游戏引擎打包成可复用、可分发、可被多种前端调用的 Python 库。读完本文你将掌握该库的pip install .安装流程、pip wheel .构建分发包的方法并理解其背后的领域模型、Minimax 人工智能、同步/异步引擎抽象与三个前端浏览器、终端、Tkinter 窗口的完整调用链。一、库的定位与前端解耦的公共游戏引擎这个项目由两大部分组成参见 项目 READMEGame Engine Library游戏引擎库把井字棋的底层游戏逻辑棋盘、规则、胜负判定、Minimax AI全部封装在tic_tac_toe这一个 Python 包中不包含任何 UI 代码Game Front Ends游戏前端浏览器PyScript、终端console、Tkinter 窗口window三个独立实现全部复用同一个引擎库。library/README.md对该库的描述是A pure-Python library for creating tic-tac-toe game front ends——即一个用于构建井字棋前端的纯 Python 库。它的核心价值在于不同前端之间零重复逻辑任何游戏状态、规则校验与 AI 决策都来自唯一的事实来源前端只需要实现各自的Player与Renderer。从源码目录 library/src/tic_tac_toe/ 可以看到清晰的两层划分tic_tac_toe/ ├── logic/ # 纯业务逻辑模型、校验、异常、Minimax │ ├── exceptions.py │ ├── models.py │ ├── validators.py │ ├── minimax.py │ └── minimax.json # 预计算分数表 └── game/ # 可运行的引擎与抽象基类 ├── engine.py ├── engine_async.py ├── players.py ├── players_async.py └── renderers.pylogic层不依赖任何 UI 概念game层通过抽象基类定义Player、Renderer接口前端只需注入具体实现即可运行。二、安装库python -m pip install .library/README.md给出的标准安装方式是在已激活的虚拟环境中从库目录安装(venv) $ python -m pip install .结合 项目 README 的完整流程推荐按如下步骤操作$ cd tic-tac-toe/ $ python -m venv venv/ $ source venv/bin/activate (venv) $ python -m pip install library/安装完成后库即进入当前环境的site-packages可以像任何第三方包一样被导入from tic_tac_toe.game.engine import TicTacToe from tic_tac_toe.logic.models import Mark该库安装后没有任何运行时依赖见下方pyproject.toml的dependencies []只需要 Python 3.10 及以上版本。2.1 构建元数据解读安装行为完全由 pyproject.toml 驱动其关键配置如下配置项值说明[build-system]setuptools64.0.0wheel使用新版 Setuptools 构建后端nametic-tac-toe发行包名称version1.0.0库版本对应生成的 wheel 文件名requires-python3.10Python 版本下限dependencies[]零运行时依赖引擎纯标准库实现keywordstic-tac-toe, minimax, gamedev, tutorial便于索引的关键词[project.optional-dependencies].devblack, flake8, isort, mypy, pylint开发依赖集合此外MANIFEST.in 中的include src/tic_tac_toe/logic/minimax.json保证了预计算的 Minimax 分数表会随源码一起打包这是 V4 版 AI 能离线瞬间决策的关键。三、打包分发python -m pip wheel .library/README.md还说明了如何把库构建成可独立分发的 wheel 包$ python -m pip wheel .该命令会在当前目录生成一个形如tic_tac_toe-1.0.0-py3-none-any.whl的平台无关通用 wheelpy3-none-any表示纯 Python 3、不依赖平台。在真实项目中构建出的 wheel 通常需要移动到使用它的前端目录项目 README 中给出了完整指令$ cd tic-tac-toe/ $ python -m pip wheel library/ $ mv tic_tac_toe-1.0.0-py3-none-any.whl frontends/browser/注意这两条命令不需要虚拟环境即可运行但放在虚拟环境中也完全没问题。打包结果在仓库中已有实物佐证frontends/browser/tic_tac_toe-1.0.0-py3-none-any.whl。3.1 wheel 的实际用途浏览器前端动态加载wheel 并不是打完就算完它在项目中有一个真实消费场景浏览器前端。frontends/browser/index.html 通过 PyScript 的py-env标签声明运行时依赖py-env - tic_tac_toe-1.0.0-py3-none-any.whl - paths: - players.py - renderers.py /py-env因此浏览器端无需创建虚拟环境、也无需pip install库——PyScript 会动态从 wheel 文件中加载引擎库。这就是 项目 README 中浏览器前端不依赖虚拟环境即可运行的底层原因。四、库架构纵深从模型到引擎的调用链4.1 核心领域模型logic/models.pylogic/models.py 用 9 个字符的字符串表示棋盘实现了四个核心类型Mark继承自str的枚举只有CROSS X与NAUGHT O并提供other属性快速取对手标记Grid不可变数据类frozenTrue默认值 * 99 个空格通过x_count/o_count/empty_count三个cached_property快速统计棋盘点位Move记录一步棋的mark、落子下标cell_index以及before_state/after_state前后状态天然适合复盘与 AI 搜索GameState组合grid与starting_mark用cached_property派生出一系列只读状态——current_mark当前行棋方、game_over、tie、winner、winning_cells、possible_moves。胜负判定利用正则与 8 种连线模式WINNING_PATTERNS ( ???......, ...???..., ......???, ?..?..?.., .?..?..?., ..?..?..?, ?...?...?, ..?.?.?.., )winner属性将每个模式中的?替换为X或O后用re.match匹配棋盘字符串winning_cells则用re.finditer(r\?, pattern)回取获胜格子的下标供前端高亮显示。evaluate_score()是 AI 评分的基础平局返回0当前方获胜返回1失败返回-1未结束的游戏抛出UnknownGameScore。4.2 校验器与异常体系validators.py 通过__post_init__钩子在每次构造Grid/GameState时自动校验validate_grid棋盘必须恰好 9 个X、O或空格validate_number_of_marksX与O的数量差不能超过 1validate_starting_mark由谁先手必须与落子数量一致validate_winner胜利方的落子数量必须与先手规则相容validate_players两名玩家不得使用相同标记。对应地exceptions.py 定义了InvalidGameState、InvalidMove、UnknownGameScore三个异常分别覆盖非法状态、非法落子与无法评分的场景前端可以直接捕获并友好提示。4.3 引擎主循环game/engine.pyengine.py 中的TicTacToe是不可变数据类组装了player1、player2、renderer与可选error_handler其play()是完整的游戏主循环def play(self, starting_mark: Mark Mark(X)) - None: game_state GameState(Grid(), starting_mark) while True: self.renderer.render(game_state) if game_state.game_over: break player self.get_current_player(game_state) try: game_state player.make_move(game_state) except InvalidMove as ex: if self.error_handler: self.error_handler(ex)每轮渲染 → 判定是否终局 → 找到当前行棋玩家 → 让其产生一步新状态非法落子如点击已被占用的格子由error_handler兜底而不是崩溃。get_current_player根据game_state.current_mark与两名玩家的标记比对来决定由谁出棋。4.4 同步与异步两套引擎除了同步版仓库还提供了 engine_async.py 中的AsyncTicTacToe逻辑与同步版完全同构只是play()与player.make_move()变为await版本专门服务于浏览器 PyScript 等事件驱动的异步环境。从源码可以看出两套引擎共用同一个Renderer抽象因此同一套渲染器可以横跨同步与异步引擎。五、Minimax 人工智能四个版本的演进minimax.py 是 AI 的核心它提供了四个递进版本分别对应 players.py 中的MinimaxComputerPlayerV1~V4版本算法特点V1minimax()朴素递归完整极小极大搜索概念最清晰但最慢V2find_best_move_optimized()加入 Alpha-Beta 剪枝alpha-2, beta2大幅削减搜索分支V3首步随机 Alpha-Beta开局第一手随机化避免对局千篇一律V4查预计算表首步随机其余走法直接查minimax.json零搜索延迟players.py最后一行MinimaxComputerPlayer MinimaxComputerPlayerV4表明当前项目默认使用的 AI 是 V4查表版这也是三个前端中minimax选项实际绑定的类。MinimaxSerializer负责把整棵博弈树的评分预计算为 JSON 表key()用before_state.grid.cells after_state.grid.cells拼出唯一键表中每个键对应[X 视角分数, O 视角分数]两个值precompute_scores()从空盘分别以X、O先手出发遍历所有可达状态。find_best_move_precomputed()只需按当前行棋方取表中分数再max(possible_moves, key...)一步选出最佳落子。六、播放器与渲染器抽象6.1 播放器game/players.pyplayers.py 定义了如下继承体系Player抽象基类持有markmake_move()负责校验是否轮到自己再委托get_move()获取走法ComputerPlayer在get_move()中先time.sleep(delay_seconds)默认 0.25 秒模拟思考再调用子类实现的get_computer_move()RandomComputerPlayer调用game_state.make_random_move()随机落子MinimaxComputerPlayerV1~V4分别调用上述四版 Minimax 查找函数。6.2 渲染器game/renderers.pyrenderers.py 只定义一个抽象方法render(game_state)。三个前端各自实现console/renderers.py终端文本渲染胜负后用 ANSI 闪烁码高亮获胜行并打印 browser/renderers.py通过js桥接操作 DOM获胜格子标红winclasswindow/renderers.py更新 Tkinter 按钮文字获胜时用粗体样式加亮并改写窗口标题。这就是引擎库 可插拔渲染器的典型架构逻辑一份展示多样。七、三种前端实战如何运行这个库安装并打包完成后就可以运行配套的三个前端目录切换至 frontends 下。7.1 终端前端console(venv) $ python -m consoleconsole支持通过命令行参数配置双方玩家由 args.py 解析(venv) $ python -m console -X minimax -O random --starting O参数取值范围默认值说明-Xhuman/random/minimaxhumanX 方玩家类型-Ohuman/random/minimaxminimaxO 方玩家类型--startingX/OX先手方底层实现上parse_args通过PLAYER_CLASSES字典把字符串映射到ConsolePlayer、RandomComputerPlayer、MinimaxComputerPlayer类若先手为O还会交换player1/player2。人机对战时players.py 中的grid_to_index()支持A1或1A两种坐标输入规则为3 * (int(row) - 1) (ord(col.upper()) - ord(A))落子前会捕获ValueError坐标非法与InvalidMove格子已占用并给出提示。7.2 浏览器前端browserPyScript$ python -m browser该命令由 browser/cli.py 实现先起一个后台线程webbrowser.open打开页面再在 8000 端口启动SimpleHTTPRequestHandler静态服务器。如前文所述该前端不需要虚拟环境、不需要安装库——PyScript 直接从本地 wheel 加载引擎。页面上的playerX/playerO两个下拉框见 index.html可选Random、Minimax、Humanscript.py 通过AsyncTicTacToe驱动异步对局——人类玩家是BrowserPlayer从asyncio.Queue中等待点击事件电脑玩家是AsyncRandomComputerPlayer或AsyncMinimaxComputerPlayer点击Replay?即可重新开局。7.3 窗口前端windowTkinter(venv) $ python -m windowwindow/cli.py 在守护线程中运行游戏主循环主线程进入window.mainloop()维持 GUI 事件循环WindowPlayer通过queue.Queue接收按钮点击。默认配置是人对 Minimax AI双方与先手在game_loop中硬编码如需修改可编辑如下片段def game_loop(window: Window, events: Queue) - None: player1 WindowPlayer(Mark(X), events) player2 MinimaxComputerPlayer(Mark(O)) starting_mark Mark(X) TicTacToe(player1, player2, WindowRenderer(window)).play(starting_mark)例如把player2换成RandomComputerPlayer(Mark(O))即可与随机 AI 对战把starting_mark改为Mark(O)则让 AI 先手。八、总结tic-tac-toe库展示了游戏逻辑与 UI 彻底解耦的工程化范式领域层自治logic模块用不可变数据类与cached_property保证状态安全与查询高效正则完成胜负判定AI 分层演进从朴素 Minimax → Alpha-Beta 剪枝 → 首步随机化 → 预计算查表V4 通过 minimax.json 把决策延迟降到接近零前后端双向可插拔Player/Renderer抽象 同步/异步双引擎让终端、浏览器、窗口三种完全异构的 UI 共享同一套规则与 AI。上手时只需记住两条命令python -m pip install .安装到虚拟环境与python -m pip wheel .打包分发再配合三种前端即可完整体验这个引擎库驱动多前端的完整项目。赞分享示例工程教程【免费下载链接】materialsBonus materials, exercises, and example projects for our Python tutorials项目地址https://gitcode.com/gh_mirrors/ma/materials点击查看免费下载相关推荐低级别系统设计实战Tic Tac Toe井字棋游戏的设计与多语言实现低级别系统设计实战Tic Tac Toe井字棋游戏的设计与多语言实现 导读 本篇技术指南以 awesome low level design 仓库中 pr示例工程python-mini-projects 双人井字棋Tic Tac Toe命令行游戏运行方式与源码实现解析python mini projects 双人井字棋Tic Tac Toe命令行游戏运行方式与源码实现解析 本文以 python mini project示例工程用 C 设计井字棋Tic Tac Toe游戏面向对象分析与最小最大MinimaxAI 实战用 C 设计井字棋Tic Tac Toe游戏面向对象分析与最小最大MinimaxAI 实战 本指南基于 awesome low level des示例工程上一篇OpenViking SessionCommit 队列并发配置解析默认值 8 的仓库级统一与本地 50 覆盖实践下一篇5个技巧让Jumpserver用户数据查询提速10倍从卡顿到秒级响应的实践指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?