软件工程第二次作业:一箭又一箭
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 202601 软件工程 |
| 这个作业要求在哪里 | 第二次个人作业要求 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成「一箭又一箭」小游戏 |
| 学号 | 102401521 |
| GitHub 仓库 | https://github.com/10thcn/arrow-game |
一、项目展示
开始界面:

游戏界面:

通关界面:

失败界面:

二、项目介绍
「一箭又一箭」是一款点击式箭头解谜小游戏。棋盘由网格组成,每个格子里可能有一个箭头,方向为上、下、左、右之一。玩家用鼠标点击箭头:
- 若该箭头前进方向(同一行或同一列)到棋盘边界之间没有其他箭头阻挡,箭头飞出棋盘并被消除;
- 若前进方向上存在其他箭头,则箭头不能消除,发生碰撞(晃动并变红提示),同时消耗一次失误机会。
消除本关全部箭头即可进入下一关;失误次数耗尽则本关失败,可重新开始。
游戏包含开始界面、游戏界面、通关/失败界面三个界面。游戏界面顶部实时显示当前关卡、剩余箭头数量和剩余失误次数,底部提供「重新开始」和「提示」两个按钮。箭头按方向用颜色区分(上绿、右橙、下蓝、左粉),飞出和碰撞时都有动画反馈。共设计 4 个关卡,箭头方向交错、难度递进。
三、实现思路
1. 箭头、方向与关卡的表示
方向用字符 U / R / D / L 表示上 / 右 / 下 / 左,映射到坐标增量字典:
DIR_VEC = {
'U': (0, -1), # 上(屏幕坐标 y 向下)
'R': (1, 0), # 右
'D': (0, 1), # 下
'L': (-1, 0), # 左
}
每一关用字符串列表表示,每个字符对应一个格子,. 表示空格:
[
".RU.R", # 第 1 关(5×5,四个方向交错分布)
"DU...",
"..L..",
".L.UR",
".LD.D",
]
这种表示直观、易读、易改,也方便直接做单元测试。
2. 路径检测(核心)
判断 (r, c) 处的箭头能否飞出:沿其方向逐格前进,越过棋盘边界即成功;途中遇到任何非空格即被阻挡。
def can_fly(board, r, c):
ch = board[r][c]
if ch not in DIR_VEC:
return False
dc, dr = DIR_VEC[ch]
rows, cols = len(board), len(board[0])
rr, cc = r + dr, c + dc
while 0 <= rr < rows and 0 <= cc < cols:
if board[rr][cc] != '.': # 路径上有其他箭头
return False
rr += dr
cc += dc
return True # 顺利到达边界
只检查同一行 / 同一列(由方向向量决定),循环的边界判断 0 <= rr < rows 保证了边缘箭头朝向棋盘外时不会越界。
3. 关卡设计:逆向构造与可解性验证
为了让箭头方向交错、位置错落的同时一定存在通关顺序,关卡采用逆向构造法生成:从空棋盘开始逐个放入箭头,每次放入时要求该箭头的方向路径上没有已放入的箭头。这样构造出的棋盘沿放入的逆序消除就必然能通关;又因为「消除任意箭头只会减少障碍、不会破坏可解性」,玩家只要点击当前能飞出的箭头就一定过关(随机贪心模拟通关率 100%)。
最后再用 DFS 求解器 find_solution 对每个关卡逐一验证,这个求解器同时复用于「提示」功能。
四、AIGC 使用过程
本次开发全程使用 Claude Code(Anthropic 的 AI 编程助手)。以下是三次有代表性的协作过程:
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 需求分析与代码结构设计 | Claude Code | 解析作业要求,设计棋盘表示、方向向量表、关卡数据结构,拆分「纯逻辑 / 渲染 / 状态机」三部分 | 结构清晰,逻辑与界面解耦,便于写单元测试 | 审查后采纳,补充求解器用于验证关卡 |
| 路径检测与关卡设计 | Claude Code | 生成四方向 can_fly 路径检测代码,并用逆向构造法生成 4 个箭头交错、方向均衡的关卡 |
初版关卡过于整齐且存在「R..L 相对箭头互相卡死」的死锁,被求解器定位;改用逆向构造后 4 关均验证有解 |
结合求解器与随机通关模拟,反复调整关卡 |
| 界面渲染与字体修复 | Claude Code | 用 pygame 实现箭头多边形绘制、四个界面状态机、飞出/碰撞动画 | 集成时 pygame.font.match_font 在 Windows 上抛 TypeError(字体注册表枚举 bug) |
改用「字体文件路径直接加载」绕过该 bug |
本次使用AIGC技术打的过程,我感受到AI的强大,使用AIGC技术大大缩短了我所需要的工作时间。
五、测试结果
采用自动化测试 + 手工试玩结合。自动化测试见 test_game.py(python test_game.py 运行,7 项全部通过)。
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头飞出并消除,剩余数量减 1 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头晃动变红、不消失,失误减 1 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 正常消失,不发生越界错误 | 正常消除,无越界 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 4 个关卡均能通关并切换到下一关 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 失误耗尽后显示失败,可重新开始 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局恢复初始,失误恢复为 3 | 通过 |
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1 | 1.1 | 0.1 |
| Python 与图形库学习 | 2 | 3 | 1 |
| 游戏界面实现 | 3 | 2.5 | -0.5 |
| 路径与碰撞逻辑实现 | 3 | 3.2 | 0.2 |
| 关卡设计 | 2 | 2.5 | 0.5 |
| AIGC 辅助开发 | 4 | 3 | -1 |
| 测试与修改 | 2 | 1.5 | -0.5 |
| README 与博客撰写 | 2 | 2 | 0 |
| 合计 | 19 | 18.8 | -0.2 |
七、心得体会
这次作业让我第一次完整地体验了「借助 AIGC 完成一个小型软件开发」的流程,感触最深的有三点:
第一,AIGC 确实大幅加快了从想法到可运行程序的进程。借助 Claude Code,从需求分析、代码骨架到可运行版本,只用了几轮对话就完成了。以往需要自己翻文档、反复试错的界面绘制和动画实现,这次大多由 AI 直接给出,我得以把精力更多地放在理解逻辑和验证正确性上。
第二,AI 生成的代码不能照单全收,运行、测试、判断、修改仍然不可省略。开发中至少踩了两个坑:一是初版关卡存在「同一行 R..L 相对箭头互相卡死」的死锁,如果不是用求解器验证和核对,几乎不会发现;二是 pygame 在 Windows 上枚举字体注册表会抛 TypeError,导致程序一启动就崩溃。这些都说明,AI 更像是高产的「结对伙伴」,最终的正确性还是需要自己负责。
第三,把核心逻辑写成可测试的纯函数非常有价值。路径检测和关卡可解性都被自动化测试覆盖后,我修改关卡、调整代码时更有底气,也切身体会到「测试先行」对维护性的帮助。通过这次作业,我对路径检测这类二维网格问题的边界处理、以及「如何保证随机生成的关卡一定有解」都有了更具体的理解。
总结:本次使用AIGC制作一个小游戏的作业我受益匪浅,但是AI并不能主导一切,主要的框架,测试,运行还是需要本人亲力亲为。AI是一个辅助我们学习的工具,不能完全依赖AI。
浙公网安备 33010602011771号