软件工程第二次作业
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice/homework/16718 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401337 |
| GitHub 仓库 | https://github.com/wuhaoyang-bot/homework2 |
一、项目展示
-
开始界面:
![image]()
-
游戏过程:
![image]()
-
碰撞反馈:
![image]()
-
通关结算:
![image]()
-
失败结算:
![image]()
-
时间预警:
![image]()
-
提示高亮:
![image]()
-
完整演示:
链接:https://pan.quark.cn/s/144a52d18891?pwd=sTfb
提取码:sTfb
二、项目介绍
"一箭又一箭"是一个点击式箭头解谜游戏。棋盘上有上、下、左、右四种方向的箭头,
点击一个箭头时,如果它前进方向到棋盘边界之间没有其他箭头阻挡,它就会飞出棋盘并被消除;
否则箭头晃动、闪红提示碰撞,并消耗一次失误机会。清空全部箭头即通关,失误耗尽则失败。
主要功能与特色:
- 开始界面、玩法说明、关卡选择、游戏界面、通关/失败结算界面完整;
- 6 个手工挑选并经过求解器验证的关卡,难度递增(4×4 到 7×7);
- 飞出动画(加速 + 残影)与碰撞反馈(晃动 + 闪红 + 浮动文字);
- 每关倒计时(顶部进度条),最后 10 秒屏幕边缘泛起红色脉动警告并伴随滴答声,超时判负;
- 计分与连击、通关星级评价、每关 3 次提示;
- 附加功能:随机关卡生成(保证可通关)、进度本地保存、程序合成音效(无外部素材)。
三、实现思路
1. 数据表示
- 方向:用枚举
Direction表示上下左右,值为(dc, dr)单位位移,遍历路径时直接累加; - 箭头:
Arrow(row, col, direction),每个箭头有唯一 id,方便做动画映射; - 棋盘:
rows × cols的二维数组,每格存放一个Arrow或None; - 关卡:用字符串布局表示,
↑↓←→为箭头、·为空格,直观且方便手工调整。
2. 路径检测(核心判定)
点击箭头后,从该箭头出发沿其方向逐格前进直到棋盘边界,途中遇到任何箭头即为被阻挡,相关代码如下:
def iter_path(self, arrow):
"""沿箭头方向,逐个产生从箭头到棋盘边界之间的格子坐标。"""
r, c = arrow.row + arrow.direction.dr, arrow.col + arrow.direction.dc
while self.inside(r, c):
yield r, c
r += arrow.direction.dr
c += arrow.direction.dc
def path_clear(self, arrow) -> bool:
"""前方无阻挡时返回 True,箭头可以飞出棋盘。"""
return not any(self.grid[r][c] for r, c in self.iter_path(arrow))
基础版只判断同一行/同一列,正好就是"沿方向走直线",用生成器写出来非常简洁,
而且走到边界自然停止,不会发生数组越界。
3. 逻辑与界面分离
所有规则(路径检测、失误、计分、胜负判定)都放在不依赖 pygame 的 model.py 里,
界面层只负责绘制和把鼠标点击翻译成 session.click(row, col)。
这样做最大的好处是核心逻辑可以直接用 unittest 自动化测试,不用打开窗口。
4. 关卡可通关性
每个关卡都要保证存在通关顺序。求解器用深度优先搜索:只要当前存在"前方无阻挡"的箭头,
就尝试消除它并递归,按剩余箭头集合做记忆化。随机关卡则用构造法生成——
按"消除顺序"依次放置箭头,要求新箭头不落在任何已放置箭头的前进路径上,
这样放置顺序本身就是一种可行解,生成是瞬时的且必然可通关。
四、AIGC 使用过程
本次开发全程使用 Kimi 辅助,以下为几次有代表性的记录:
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 路径检测与核心模型 | Kimi | 生成方向枚举、棋盘类和四方向路径检测代码 | 一次通过,逻辑正确 | 补充了"只算同行/列、斜线不算"的测试用例 |
| 随机关卡生成 | Kimi | 初版用"随机摆盘 + DFS 验证",7×7 棋盘生成一次约 15 秒,不可用 | 不符合要求 | 与 AI 讨论后改为"按消除顺序逆序放置"的构造法,并加"指向已有箭头"的偏置形成阻挡链,生成变为瞬时 |
| 碰撞与飞出动画 | Kimi | 生成晃动 + 闪红 + 浮动文字的碰撞反馈,以及加速飞出 + 残影的消除动画 | 基本可用 | 人工调整了晃动时长(0.45s)、飞出加速度等参数,使手感更干脆 |
| 自动化测试 | Kimi | 按 T01~T10 生成 unittest 测试 | 首次运行有 3 个用例失败 | 分析发现是测试布局本身设计有误(如把 ↓ 放在底边它其实能直接飞出、失误次数耗尽后点击被忽略),修正测试数据后 15 个用例全部通过 |
| 界面布局 | Kimi | 生成开始界面与标题绘制 | 标题旁装饰箭头与文字重叠 | 人工把装饰箭头移到标题两侧 |
五、测试结果
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 与预期一致 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 与预期一致 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 与预期一致 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 与预期一致 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 与预期一致 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 与预期一致 | 通过 |
| T07 | 倒计时耗尽 | 判负并提示"时间到",之后点击无效 | 与预期一致 | 通过 |
| T08 | 点击空格不扣失误 | 不会计入关卡失误次数 | 与预期一致 | 通过 |
| T09 | 斜线不算阻挡 | 箭头正常飞出 | 与预期一致 | 通过 |
| T10 | 连击计分 | 连续正确操作得分递增 | 与预期一致 | 通过 |
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 0.5 | 1 | 0.5 |
| Python 与图形库学习 | 2 | 2 | 0 |
| 游戏界面实现 | 1 | 0.5 | -0.5 |
| 路径与碰撞逻辑实现 | 1 | 0.5 | -0.5 |
| 关卡设计 | 0.5 | 0.5 | 0 |
| AIGC 辅助开发 | 1 | 1.5 | 0.5 |
| 测试与修改 | 2 | 1 | -1 |
| README 与博客撰写 | 0.5 | 0.5 | 0 |
| 合计 | 9 | 8 | -1 |
七、心得体会
- AI 最大的帮助是把"会做的事"变快:界面绘制、动画、测试骨架这些模式化的代码,描述清楚需求后几秒钟就能拿到能跑的版本,把精力留给了规则设计。
- AI 也会犯错,而且错得很"自信":这次测试用例里的布局数据就有三处自相矛盾,如果自己不真正理解路径检测规则,根本看不出是测试错了还是代码错了。
- 逻辑与界面分离后,核心规则可以脱离窗口直接测试,这为后续其他项目的开发起到了启示作用。







浙公网安备 33010602011771号