2026秋软件工程个人作业(第二次):一箭又一箭
2026秋软件工程个人作业(第二次):一箭又一箭
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 202601 软件工程班级博客 |
| 这个作业要求在哪里 | 第二次个人作业要求 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401128 |
| GitHub 仓库 | https://github.com/kasinglee/ArrowAfterArrow |
项目展示
本项目使用 Pygame 绘制 810 × 1440 的手机竖屏逻辑画布,窗口缩放时保持比例。基础玩法是本作业的主体;开始页还提供进阶玩法入口和中英文切换,进阶玩法及后文所述附加功能均建立在完成基础要求之后。
| 开始界面 | 基础玩法:单格箭头 |
|---|---|
![]() | ![]() |
| 碰撞反馈 | 通关结果 |
|---|---|
![]() | ![]() |
| 失败结果 | 进阶玩法(附加功能) |
|---|---|
![]() | ![]() |
以上截图与 GIF 均来自本人于 2026 年 9 月 14 日的实际运行记录,分别展示开始、基础关卡、碰撞、通关、失败和附加玩法的界面效果。
项目介绍
“一箭又一箭”是一个通过观察方向与遮挡关系决定点击顺序的点击式解谜游戏。点击一支箭头后,程序检查它朝向棋盘边界的直线路径:没有任何箭头占用时,箭头飞出棋盘;路径被占用时,箭头撞击后变红、返回原位并扣除一次机会。每局有 3 次机会,清除全部箭头即可通关,机会耗尽则失败并可重新开始。
在完成作业规定的基础玩法后,本项目再提供一个附加模式:
- 基础玩法(作业主体):每支箭头只占一个网格,方向为上、下、左、右,完全按作业题目的统一判定实现。
- 进阶玩法(附加功能):每支箭头是一条尾部到头部的正交折线路径,形状类似贪吃蛇。只有头部最后一段朝向的射线用于判定;射线命中其他箭头或自身较早的轨迹都会碰撞。
两种模式均包含 5 个固定关卡和随机关卡;还实现了关卡选择、计时、得分、星级、提示、撤销、进度保存、重置存档、内置自动求解、程序生成音效与 Windows EXE 打包脚本。项目已使用 PyInstaller 打包为 Windows .exe 可执行文件,便于在未配置 Python 环境的电脑上直接运行。基础模式始终保持单格箭头,便于直接展示题目要求的路径检测;进阶模式的长轨道箭头则作为额外尝试。
界面采用手机竖屏布局:顶部集中显示关卡、剩余箭头和失误次数,中部为棋盘,底部放置重来、提示、撤销和自动求解等操作。开始、游戏、通关和失败页面均有明确的状态提示,保证玩家能理解当前操作与结果。
我的参与
本项目由我独立完成需求分析、功能取舍、代码整合、运行调试和最终测试。AIGC 主要帮助我学习 Python/Pygame、提供代码结构和排查思路;我没有直接照搬生成结果,而是逐段阅读关键代码、运行程序、比较实际效果,并根据作业要求和试玩体验进行修改。特别是基础玩法是否符合题目、进阶箭头是否应沿轨迹移动、关卡是否真的可通关,都是我在实际检查后做出的决定。
实现思路
数据表示与路径检测
Direction 枚举保存四个方向及其行列增量。Arrow 使用有序的 cells 保存占用格:基础箭头只有一个格并显式保存方向;进阶箭头包含两个或更多连续格,方向由最后一段路径自动推导。Board 维护“网格坐标 → 箭头”的占用表,因此点击网格即可找到对象。
核心检测从箭头头部的下一格开始,按方向循环到棋盘边界:
cell = head + direction.delta
while cell 在棋盘内:
如果 cell 被占用:返回阻挡物
cell += direction.delta
返回无阻挡
基础模式中 head 就是单格箭头自身的位置;进阶模式中 head 是轨迹最后一个格。进阶模式统一查占用表,因此头部射线命中自身较早的轨迹也会正确判定为碰撞,不会产生“看似可飞出、实际会撞到自己”的错误。
在实现和学习过程中,我重点理解了 Direction.delta 如何把方向转换为行列增量,Board.first_collision 如何沿射线逐格查找,以及 GameSession.click_arrow 如何根据检测结果更新机会、历史和关卡状态。最初试玩时我发现把整支折线整体平移会产生不符合玩法的效果,因此主动要求改为头部前进、尾部沿旧轨迹跟随,并通过动画测试确认转弯处仍保持直角。
可解关卡生成与验证
基础随机关卡采用“反向剥离”构造:先随机选择若干占用格,再反复寻找当前沿某个方向可以直达边界的格子,记录该格的移除顺序与方向。反向得到初始棋盘后,这个记录顺序就是零失误通关证书。生成时会优先让箭头朝向已移除的区域,使布局存在合理依赖而不是全部箭头同时可消除。
进阶满盘生成器先生成经过所有格的 Hamilton 路径,再使用 backbite(端点回咬)变换打乱路径拓扑;该变换保持“连续、无重复、覆盖全部格”三个性质。之后将整条路径随机切成长度和转弯数不同的箭头,并从满盘状态向外剥离:只有头部射线不碰到任意轨迹(包括自身)的片段才可被选中。程序记录每次成功剥离的箭头 ID,并调用验证器逐步复放,确保每张固定关和随机关都有零失误解。
存档与自动求解器
存档保存在 JSON 文件。源码运行时文件是项目根目录的 savegame.json;打包版使用 %LOCALAPPDATA%\ArrowAfterArrow\savegame.json。文件包含进阶/基础玩法各自的解锁进度、最高分、最高星级与语言设置。读取时对值做范围限制;写入失败不会影响游戏运行。重置存档需要二次确认,只清除解锁与成绩记录,保留当前语言。
内置自动求解器不调用外部在线模型,而是使用与验证器相同的确定性规则:复制当前未消除箭头组成快照,不断扫描可飞出的箭头,选取第一支并从快照移除;若某一步没有候选箭头就返回无解。已生成关卡带有构造证书并会在生成后验证,因此求解器可以找到完整顺序。界面再按该顺序模拟点击并播放动画;为了区分玩家自己完成与演示,使用自动求解的本局最多获得 1 星。
AIGC 使用过程
下面选择几次代表性协作过程。每次协作中,我负责提出具体问题、运行和比较结果,并决定是否采用 AI 的建议:
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 实际效果如何 | 人工修改 |
|---|---|---|---|---|
| 基础玩法恢复与测试 | OpenAI Codex | 在进阶玩法旁加入单格箭头模式、独立进度、固定/随机关及测试 | 我运行开始页、关卡页和基础关卡,确认单格箭头符合题目规则 | 我保留基础模式作为作业主体,检查四方向、边界和阻挡扣机会,并补充 T07、T08、E22 |
| 进阶轨道玩法建模 | OpenAI Codex | 提供多格正交轨迹、头部射线判定与贪吃蛇式动画结构 | 我试玩后发现整体平移不符合参考玩法 | 我明确要求只检查头部射线、尾部沿旧轨迹跟随,并要求自身轨迹也能阻挡 |
| 可解关卡生成 | OpenAI Codex | 提供反向剥离证书、满盘 Hamilton 路径与 backbite 拓扑随机化方案 | 我查看生成布局并按顺序试玩,固定关和随机局均可通关 | 我调整棋盘密度、形状多样性、U 形比例和自身碰撞筛选 |
| Python/Pygame 学习 | OpenAI Codex | 解释事件循环、Surface、Rect 点击判断和逻辑坐标缩放 | 我能读懂界面更新、鼠标点击和页面切换的主要流程 | 我根据实际窗口效果调整竖屏比例、棋盘位置、字体和按钮布局 |
测试结果
运行 python scripts/run_tests.py 会生成自动化测试的 Markdown 和 PNG 证据。测试首先覆盖作业要求的单格箭头、四方向、边界、阻挡扣机会、通关、失败和重开;长轨道箭头、提示、撤销、保存、随机生成、自动求解器、动画和界面流程则作为扩展测试。

| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的基础单格箭头 | 飞出并消失 | 箭头被移除,余量减少 | 通过 |
| T02 | 点击前方有阻挡的基础单格箭头 | 不消失,机会减 1 | 箭头保留,机会减 1 | 通过 |
| T03 | 位于边缘且朝向棋盘外的单格箭头 | 正常飞出且不越界 | 通过边界测试 | 通过 |
| T04 | 清除基础关卡全部箭头 | 显示通关并进入下一关 | 最后一支箭头后进入通关状态 | 通过 |
| T05 | 基础玩法连续三次碰撞 | 显示失败并允许重新开始 | 第三次碰撞后进入失败状态 | 通过 |
| T06 | 基础玩法进行中重新开始 | 布局和机会恢复 | 棋盘、生命、历史恢复初值 | 通过 |
| T07 | 基础单格箭头四方向路径检测 | 同行/列阻挡扣机会,清空后可飞出 | 显式方向与边界判定正确 | 通过 |
| T08 | 基础固定/随机关 | 均存在零失误解 | 5 个固定关与多种子证书通过验证 | 通过 |
| E19 | 进阶箭头头部撞自身轨迹 | 视为阻挡 | 扣命且箭头保留 | 通过 |
| E22 | 基础模式界面流程 | 可进入、显示单格箭头、自动求解器可完成 | 开始页和关卡页流程通过 | 通过 |
除了自动化测试外,我还在 2026 年 9 月 14 日 21:00 左右进行了人工试玩。我亲自从头到尾测试了基础玩法和进阶玩法的 5 个固定关卡,观察每一步可点击的箭头并按合理顺序完成通关;另外测试了 2 局随机关卡,也都可以正常完成。试玩过程中我主动检查了箭头点击、阻挡扣除机会、碰撞反馈、通关结果、失败结果和重新开始功能,未发现无法通关或越界问题。
| 人工测试范围 | 我的操作 | 实际结果 | 是否通过 |
|---|---|---|---|
| 基础玩法固定关卡 1—5 | 逐关观察方向并按合理顺序点击 | 全部可以正常通关 | 通过 |
| 进阶玩法固定关卡 1—5 | 逐关沿箭头轨迹判断头部出口并点击 | 全部可以正常通关 | 通过 |
| 随机关卡 2 局 | 分别运行随机棋盘并尝试完整通关 | 两局均可以正常完成 | 通过 |
| 点击、阻挡、碰撞、失败、重开和通关流程 | 手动触发并观察界面反馈 | 操作和反馈均正常 | 通过 |
PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 0.5 | -0.5 |
| Python 与图形库学习 | 1.5 | 2 | 0.5 |
| 游戏界面实现 | 1.0 | 0.5 | -0.5 |
| 路径与碰撞逻辑实现 | 1.0 | 0.5 | -0.5 |
| 关卡设计与生成器 | 1.0 | 0.25 | -0.75 |
| AIGC 辅助开发与人工修改 | 1.0 | 1.5 | 0.5 |
| 测试与修改 | 1.0 | 2 | 1.0 |
| README 与博客撰写 | 1.5 | 1 | -0.5 |
| 合计 | 9.0 | 8.25 | -0.75 |
心得体会
本作业中,AIGC 对快速建立 Pygame 界面、拆分游戏逻辑与测试脚本非常有帮助,但不能替代对规则的理解。开发过程中最重要的修改来自实际试玩和对参考玩法的反复比对:先发现单格模型无法表达进阶轨道玩法,再发现整条箭头刚体平移不正确,最后补上头部射线撞自身轨迹的规则。每一次修改都同步增加了自动化回归测试,避免后续优化生成器或动画时重新引入错误。
另一个收获是“随机生成”不能只看画面随机。游戏生成器让游戏生成的多样化的同时,也要必须让游戏可解,否则很容易生成无解或体验不合理的棋盘。(虽然羊了个羊、一箭又一箭等游戏大概率可以避免游戏可解,以吸引更多人观看广告或充值)基础玩法和进阶玩法分别保留,使我既能展示题目规定的单格路径检测,也能展示在此之上扩展的轨道、满盘生成与自动求解功能。
通过这次作业,我实际掌握了用枚举表示方向、用数据类组织游戏对象、用集合维护棋盘占用关系,以及用 unittest 编写边界和状态测试。AI 可以帮助我快速获得可运行的起点,但最终哪些规则正确、哪些动画自然、哪些关卡真的能通关,仍然需要我自己运行、观察和判断。
最后对于 AIGC 和 Agent 有以下体会:在目前这个 Agent 发展的时代当你舍得烧 Token 的时候 Angent 可以通过大量的 COT、大量的大参数模型(比如GPT5.6 Sol、 GPT6 Astra)、1M 的 context 等等经过长时间的编码、编译、验证之后也是可以达到很好的效果,但是副作用就是会及其消耗 Token 以及上下文。但是如果引入一个所谓产品经理的人类,就算编码能力不需要很强,也能节省很多时间和 Token,可以在短时间内达到更好的效果。当然如果是一个完全不懂的人类,那你就是 codex 的阻碍还不如让他自己来,,,我曾经试过 prompt 里面让 llm 自己选 UI 的架构、或者不 prompt UI的风格,他的效果会比较参差,因此学习依旧是非常重要的。
这次经历也让我认识到,学习编程不能只关注代码能否运行,还要理解代码背后的规则和设计原因。通过自己提出需求、检查 AI 生成的结果并进行修改,我对 Python 和 Pygame 的使用更熟悉了,也积累了从需求分析到测试验证的完整开发经验。







浙公网安备 33010602011771号