2026秋软件工程个人作业(第二次)—— 一箭又一箭
2026秋软件工程个人作业(第二次)—— 一箭又一箭
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 202601 软件工程(福州大学 计算机与大数据学院) |
| 这个作业要求在哪里 | 作业链接 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成"一箭又一箭"小游戏 |
| 学号 | 102401414 |
| GitHub 仓库 | https://github.com/shukai123123/arrow-game |
一、项目展示
开始界面(标题 + 规则说明 + 开始按钮):

游戏界面(顶栏显示当前关卡 / 剩余箭头 / 剩余失误,右上角重新开始按钮):

点击可飞箭头后(箭头飞出消失,剩余箭头数更新):

通关界面(半透明遮罩 + "本关通过" + 下一关按钮):

失败界面(失误耗尽后红色提示 + 重新开始按钮):

二、项目介绍
2.1 游戏规则
棋盘上有若干带方向的箭头(↑↓←→)。玩家点击某个箭头:
- 程序沿该箭头指向的方向,向棋盘边界扫描;
- 如果这条路径上、箭头与边界之间没有任何其他箭头,则箭头飞出棋盘并消失;
- 如果路径上存在其他箭头,箭头不能飞出,变红抖动并记一次失误;
- 清空本关全部箭头 → 进入下一关;失误次数(3 次)耗尽 → 本关失败,可重来。
2.2 界面设计
- 三个界面状态:
START(开始)、PLAYING(游戏中)、LEVEL_CLEAR / GAME_OVER / ALL_CLEAR(结果),由一个状态机驱动。 - 游戏界面顶栏实时显示:当前关 / 总关数、剩余箭头数、剩余失误数(失误即将用完时变红)。
- 右上角常驻"重新开始"按钮。
- 视觉反馈:成功飞出时箭头沿方向飞出屏幕并渐隐;被阻挡时箭头变红、左右抖动。
2.3 主要功能与特色
- 纯 Python + pygame-ce 实现,无外部素材,箭头用 Unicode 字符
↑↓←→绘制。 - 逻辑层与界面层分离:
core.py只做纯数据判断,不 import pygame,因此可以在无图形环境下直接单元测试。 - 内置 3 个手工设计、并经脚本验证可通关的关卡。
三、实现思路
3.1 箭头、方向与关卡的表示
棋盘用二维整数列表表示,每个格子的取值含义如下:
EMPTY = 0 # 空
UP = 1 # 上
DOWN = 2 # 下
LEFT = 3 # 左
RIGHT = 4 # 右
方向到坐标增量的映射:
DIRS = {
UP: (-1, 0), # 行号减小
DOWN: (1, 0), # 行号增大
LEFT: (0, -1), # 列号减小
RIGHT: (0, 1), # 列号增大
}
每个关卡就是一个二维列表,例如第 1 关:
→ · ↑
· · ·
· · ←
3.2 路径检测(核心算法)
can_fly(board, row, col) 是整个游戏最核心的函数。它从箭头所在格出发,沿方向一格一格走向边界,只要途中遇到任何非空格子(另一个箭头)就立刻判定为"被挡住";一路走到边界都为空则判定为"可飞出"。
def can_fly(board, row, col):
direction = board[row][col]
dr, dc = DIRS[direction]
r, c = row + dr, col + dc # 从相邻一格开始扫,不看自己
while 0 <= r < rows(board) and 0 <= c < cols(board):
if board[r][c] != EMPTY: # 路上还有别的箭头 → 挡住
return False
r += dr
c += dc
return True # 一路走到边界都空 → 可飞
为什么这样写就能正确?因为题目约定"路径检测只需判断同一行或同一列、箭头与边界之间是否还有其他箭头",所以沿单一方向线性扫描即可,不需要 BFS/DFS。
关键边界处理:循环条件是 0 <= r < rows and 0 <= c < cols,天然处理了"箭头本来就在边界上、朝向棋盘外"的情况——此时相邻格就越界,循环不执行,直接返回 True,不会数组越界。
3.3 点击与状态流转
try_click(board, row, col) 封装了一次点击的结果,返回 {ok, flew, blocked} 三元组:
- 点到空格 / 棋盘外 →
ok=False,无任何变化; - 点到可飞箭头 → 把该格置空,并返回
flew=True,界面层播放飞出动画; - 点到被挡箭头 → 保持棋盘不变,返回
blocked=True,界面层记一次失误并播放抖动动画。
界面层(main.py)只负责画图和读鼠标,所有"能不能飞""清没清空"都交给 core.py 判断。
3.4 关卡的可解性验证
设计完关卡后,我没有靠"觉得能通",而是在测试脚本里写了一个贪心校验:反复找任意一个当前可飞的箭头消除,直到清空或死局。结果三个关卡分别用 3、4、4 步清空,证明都存在合法通关顺序。
四、AIGC 使用过程
开发过程中使用了豆包等 AIGC 编程工具辅助,以下记录 3 次有代表性的协作。
协作 1:让 AI 帮我理清"路径检测"到底该扫什么
我最初的想法很模糊,只知道"箭头前面不能有别的箭"。我把游戏规则原样描述给 AI,问它"这个路径判断最核心的循环应该怎么写"。
AI 给出的关键点让我一下子明白了:要从箭头相邻的下一格开始扫,而不是从箭头自己开始,否则会把自己误判成阻挡。它还提醒我用 while 0<=r<rows and 0<=c<cols 这种写法天然处理边界。这正好对应上面的 can_fly。
协作 2:让 AI 帮我把"逻辑"和"界面"拆开
我一开始把判断和画图全写在一个函数里,结果想测路径判断时一运行就弹出游戏窗口,很不方便。我把这个困扰告诉 AI,它建议:
- 把方向常量、
can_fly、count_arrows、关卡数据抽到一个不 import pygame 的core.py; main.py只负责读鼠标、调core、画图。
这样我就能用 python test_core.py 在命令行直接跑测试,不用开窗口。这是这次作业里对我启发最大的一步——原来"能测试"的代码结构和"能跑"的代码结构是两回事。
协作 3:让 AI 帮我排查"向上扫会越界"的 bug
自测时我发现:当箭头在第一行、方向朝上时,偶尔报 IndexError。我把报错堆栈和 can_fly 贴给 AI。AI 一眼指出:如果循环写成 while True: r += dr 而没有先判断范围,第一行的箭头 r-1 就会变 -1。它建议把"边界判断"写进 while 条件里。改完后 T03 测试(边缘箭头不越界)就稳定通过了。
说明:AI 给出的代码我都没有直接照抄,而是先读懂它在做什么,再自己敲进项目,并补了对应的测试。
五、测试结果
运行 python test_core.py,共 20 个断言全部通过。对应作业要求的 T01~T06:
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头被置空,flew=True |
✅ 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数 -1 | 箭头保留,blocked=True |
✅ 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 正常飞出,不越界 | 上/下/右边界箭头均可飞,越界访问不抛异常 | ✅ 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 三关按验证顺序点完后 level_cleared=True |
✅ 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 连续 3 次被挡后累计失误 = MAX | ✅ 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 深拷贝恢复初始关卡,失误归零 | ✅ 通过 |
附加校验:三个关卡分别用 3、4、4 步可解,无死局。
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 1.5 | +0.5 |
| Python 与图形库学习 | 1.5 | 2.0 | +0.5 |
| 游戏界面实现 | 2.0 | 2.5 | +0.5 |
| 路径与碰撞逻辑实现 | 1.5 | 1.5 | 0 |
| 关卡设计 | 0.5 | 1.0 | +0.5 |
| AIGC 辅助开发 | 1.0 | 1.0 | 0 |
| 测试与修改 | 1.0 | 1.5 | +0.5 |
| README 与博客撰写 | 1.5 | 2.0 | +0.5 |
| 合计 | 10.0 | 13.0 | +3.0 |
实际耗时普遍高于预估,主要花在"pygame 在 Python 3.14 上装不上、换 pygame-ce"以及界面调优上。
七、心得体会
- AIGC 是"结对编程",不是"一键生成":AI 能很快给出一版能跑的代码,但如果直接照抄,遇到 bug 就会完全不知道从哪改。这次我坚持让 AI 解释每段代码在做什么,反而比直接要代码更快。
- "可测试的结构"比"能跑的代码"更重要:把逻辑层抽离出来后,我才能用
test_core.py一键验证 T01~T06,而不是每次都开着窗口手点。这是这次作业最大的收获。 - 关卡设计要"自己解一遍":一开始我随手摆了几个箭头,写贪心校验才发现有死局。后来每个关卡都用脚本验证过通关步数,才敢交。
- 环境问题也是开发的一部分:Python 3.14 太新,原版 pygame 装不上,换 pygame-ce 才解决。这种问题 AI 帮我快速定位了原因,但最终换库决策和依赖记录是我自己做的。
- 不足与改进:目前动画还比较简单(飞出 + 抖动),没有音效;关卡也只有 3 个。如果时间允许,想加一个"提示当前哪个箭头能飞"的提示功能,以及一个能自动求解的 AI solver。
本项目代码与素材均为本人借助 AIGC 工具独立编写,未使用原商业游戏的代码、美术或关卡。

浙公网安备 33010602011771号