软工第二次作业
软工作业:Python + AIGC 实现“一箭又一箭”小游戏
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026秋软件工程人人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401512 |
| GitHub 仓库 | arrow-arrow-game |
一、项目展示
1. 自动通关演示 GIF
以下 GIF 由内置求解器自动点击生成,演示第 3 关的完整通关过程(点击顺序、飞出动画、通关切换):

2. 界面截图
开始界面 / 选关界面:


游戏界面(含提示高亮)/ 碰撞反馈(晃动变红 + “受阻!”):


通关界面 / 失败界面:


二、项目介绍
一箭又一箭 是一款点击式箭头解谜游戏,用 Python + Pygame 开发。棋盘上有上、下、左、右四种方向的箭头,玩家需要观察箭头方向与相互阻挡关系,按合适的顺序点击:
- 点击箭头后,若它与棋盘边界之间没有其他箭头,箭头飞出棋盘并消除(带飞出动画);
- 若路径上有其他箭头,箭头无法消除,出现碰撞反馈(晃动 + 变红 + “受阻!”飘字),并消耗 1 次失误机会;
- 清空本关全部箭头即可通关、解锁下一关;失误耗尽则挑战失败,可重新挑战。
主要功能与特色:
- 完整游戏流程:开始界面 → 选关界面 → 游戏界面 → 通关/全部通关/失败界面;
- 5 个手调关卡:每个关卡都经过 BFS 求解器验证可通关,且有合理难度梯度;
- 动画反馈:箭头飞出(加速渐隐)、碰撞晃动、提示脉冲高亮、标题弹入;
- 附加功能:提示(求解器保证正确)、撤销上一步、关卡解锁与选择、Esc 返回;
- 逻辑与界面分离:核心逻辑为纯 Python 模块,可用 pytest 做 29 项自动化测试;
- 零外部素材:全部图形由代码绘制,中文字体使用 Windows 自带微软雅黑。
三、实现思路
1. 数据表示
箭头和关卡用最简单的方式表示——二维网格:
# 方向用 0~3 四个常量表示,方向对应的行列偏移放在字典里
DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT = 0, 1, 2, 3
DIR_DELTA = {DIR_UP: (-1, 0), DIR_RIGHT: (0, 1), DIR_DOWN: (1, 0), DIR_LEFT: (0, -1)}
# 棋盘是 rows x cols 的二维列表,每个格子为 None(空)或方向常量
grid = [[None, 1, None], [2, None, None]]
关卡数据用字符画描述,直观易改(→←↑↓ 表示箭头,· 表示空格):
"layout": ["→·↑·", "····", "←·↓·", "····"]
2. 核心路径检测
判断箭头能否飞出:从箭头所在格出发,沿其方向逐格检查到边界,中途遇到任何箭头即被阻挡。注意边界条件:边缘且朝外的箭头中间没有格子,while 循环一次都不执行,直接返回可飞,天然不会越界:
def is_path_clear(self, row, col):
direction = self.grid[row][col]
dr, dc = DIR_DELTA[direction]
r, c = row + dr, col + dc
while 0 <= r < self.rows and 0 <= c < self.cols:
if self.grid[r][c] is not None:
return False
r += dr
c += dc
return True
3. 关卡设计规则(本项目推导出的关键结论)
设计关卡时发现一条重要规律:同一行若出现“→ 在 ← 左边”(两箭对头),它们会永远互相阻挡,该关必然无解;同一列“↓ 在 ↑ 上方”同理。反之,只要每行每列没有对头箭,任何局面下都至少有一支可飞的箭头,因此“只点可飞的箭头”一定能通关。
基于此规则手工设计 5 个关卡后,又写了 BFS 求解器逐关机器验证(见 game_engine.py 的 solve() 函数):
def solve(arrows, rows, cols):
"""广度优先搜索清空全部箭头的点击序列,无解返回 None。"""
# 状态 = 剩余箭头的集合;每次扩展“可飞出”的箭头;找到空集合即得到解
求解器还顺带实现了提示功能:对每支可飞的箭头,验证“飞出它之后剩余局面仍有解”,保证提示不会把玩家带入死局。
4. 动画系统
游戏界面维护一个动画列表,每帧更新并剔除播完的动画:飞出动画(沿方向加速位移 + 渐隐缩小)、碰撞动画(箭头沿自身方向前后抖动衰减 + 红色快速褪回原色)、飘字动画(“受阻!”上浮淡出)。通关/失败场景用定时器延迟切换,让动画播完再跳转。
四、AIGC 使用过程
本次开发全程使用 Claude Code 辅助。以下是 6 次有代表性的协作记录(均为真实开发过程):
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 游戏逻辑与路径检测 | Claude Code | 生成四个方向的路径检测、失误判定、撤销/提示逻辑,并按“逻辑与界面分离”的思路拆分模块 | 一次通过全部自动化测试 | 人工审阅边界条件(边缘箭头空循环不越界),补充中文注释便于理解 |
| 关卡设计 | Claude Code | 生成 5 个关卡的字符画布局 | 初版第 3 关存在“对头箭”死局,实际无法通关 | 人工总结出“对头箭必无解”的设计规则,重排关卡布局,再用 BFS 求解器逐关验证 |
| 界面与动画 | Claude Code | 生成开始/选关/游戏/通关/失败界面、飞出与碰撞动画、按钮组件 | 基本可用 | 调整动画时长、颜色、按钮布局与文字大小等参数 |
| 字体加载 Bug 修复 | Claude Code | 定位 pygame 2.6.1 在 Windows 下 match_font 枚举系统字体崩溃的原因 |
AI 初版字体代码在本机运行时直接崩溃 | 改为直接按文件路径加载 msyh.ttc 等字体文件,绕开已知 bug,验证中文字形渲染正常 |
| 演示 GIF 工具 | Claude Code | 生成“自动求解 + 逐帧渲染合成 GIF”的脚本 | 首版因逐帧累积全尺寸图片导致 MemoryError;修复后又因场景切换后标志位未清空陷入死循环 | 改为捕获时立即缩小图片;场景切换后清空 pending 标志 |
| 自动化测试 | Claude Code | 编写 pytest 测试:作业要求的 T01~T06 + 题干示例 + 边界情况 + 撤销/提示 + 关卡可解性 | 29 项测试全部通过 | 无 |
五、测试结果
测试方式:逻辑层用 pytest 自动化测试(python -m pytest tests/ -v,29 项全部通过);界面与动画经本人实际试玩验证。
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头被移除,棋盘剩余数减 1 | ✅ |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头保留,失误 3→2,有碰撞动画 | ✅ |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 正常消失,不发生越界错误 | 8 种边缘朝向用例全部正常消除 | ✅ |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 状态变 won,0.55s 后进入通关界面,解锁下一关 | ✅ |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 状态变 failed,进入失败界面,可重新挑战 | ✅ |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局、失误、撤销历史全部恢复 | ✅ |
| 附加 | 每个关卡可通关性 | BFS 求解器找到解 | 5 关均找到解并模拟通关成功 | ✅ |
| 附加 | 提示功能 | 提示的箭头可飞且不引入死局 | 逐关验证通过 | ✅ |
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.5 | 1.5 | 0 |
| Python 与图形库学习 | 1 | 1 | 0 |
| 游戏界面实现 | 3 | 3.5 | +0.5 |
| 路径与碰撞逻辑实现 | 2 | 2 | 0 |
| 关卡设计 | 1.5 | 2 | +0.5 |
| AIGC 辅助开发 | 2 | 3 | +1 |
| 测试与修改 | 1.5 | 2 | +0.5 |
| README 与博客撰写 | 2 | 2 | 0 |
| 合计 | 14.5 | 17 | +2.5 |
提示:请按你真实的开发过程调整“实际耗时”列。
七、心得体会
这次作业最大的收获是体会到 “AI 写代码很快,但验证代码是人的事”:
- AI 带来的帮助:路径检测、界面框架、BFS 求解器这类“套路明确”的代码,AI 一次就能生成可用版本;把逻辑与界面分离后,自动化测试(T01~T06)可以脱离图形界面运行,回归测试只需 0.1 秒,修改逻辑时非常有底气。
- AI 出的问题:AI 生成的关卡数据曾出现“对头箭”死局——表面看着合理,实际无法通关;字体加载代码在 Windows 上直接崩溃;GIF 脚本内存溢出。这些问题都是通过运行 + 测试才暴露出来的。
- 自己的收获:为了验证关卡可解性,自己推导并证明了“对头箭必无解、无对头箭必可贪心通关”的规律,并学会用 BFS 求解器做机器验证;也学会了用 dummy 视频驱动做无窗口截图和 GIF 生成这类实用技巧。
素材来源说明:全部图形由代码绘制,未使用任何外部图片/音效素材;界面文字使用 Windows 自带字体。
浙公网安备 33010602011771号