软件工程第二次作业
软件工程第二次作业
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业属于哪个课程 | 2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102402145 |
| GitHub 仓库 | zsp-c/one_arrow_after_another: 一箭又一箭项目 |
一、项目展示
1.游戏开始界面

游戏开始界面,包含游戏玩法说明,及自选关卡。
2.游戏中画面

画面包含生命值,剩余箭头数等等,鼠标放在箭头上会有高亮和箭头路径提示,箭头撞到其他箭头时会有红色高亮,和文字提示。
3.通过画面

4.失败画面

二、项目介绍
这是一个参考微信小游戏《一箭又一箭》核心玩法实现的小游戏作业。棋盘上摆着若干带方向
的箭头(上、下、左、右四种),玩家点击箭头,程序检查它前进方向上有没有别的箭头挡路:
- 前方畅通 → 箭头飞出棋盘并被消除;
- 前方有箭头挡路 → 箭头飞不出去,会被弹回来并消耗一次失误机会。
把一关的箭头全部清空即可通关进入下一关;失误次数耗尽则本关失败。
主要特性
- 上、下、左、右四种方向的箭头,鼠标点击操作,点击判定严格按“同一行 / 同一列、
箭头与边界之间是否还有其他箭头”执行; - 飞出、碰撞都有动画反馈:飞出带残影拖尾与火花,碰撞会顶出去再弹回、闪红,
并把挡路的那支箭头用金色方框闪两下; - 悬停任意箭头即可预览它的前进路线(绿点畅通 / 金点可走 / 红点被挡);
- 自动提示:每关 2 次,点了直接帮你飞掉一支能走的箭头,不消耗失误次数;
- 4 个可通关关卡,难度从 5 支箭头递增到 12 支;
- 开始界面、游戏界面、通关 / 失败结算界面,支持重新开始本关。
三、实现思路
1.方向表示
四个方向就是四个字符串常量,加一张「方向 → 行列增量」的对照表:
UP = "up"
DOWN = "down"
LEFT = "left"
RIGHT = "right"
# 方向 -> (行增量, 列增量)。屏幕坐标里行号向下增大。
DELTA = {
UP: (-1, 0),
DOWN: (1, 0),
LEFT: (0, -1),
RIGHT: (0, 1),
}
DELTA 是整套实现的关键。屏幕坐标里行号向下增大,所以「上」是行号 -1、「下」是 +1、
「左」是列号 -1、「右」是 +1。
把方向统一成 (行增量, 列增量) 之后,上下左右四种情况就能用同一段代码处理,
不需要写四个 if 分支——后面路径检测就是靠这一点压成一次循环的。
2.箭头表示
一个格子里最多一支箭头,整张棋盘表示成字典 {(r, c): 方向}:
{(0, 3): "up", (1, 1): "left", (3, 3): "down"}
用字典进行表示。
3.关卡表示
levels.py 里用字符画描述棋盘,^ v < > 是箭头,. 是空格:
{
"name": "初识箭头",
"tip": "箭头前方没有别的箭头,才能飞出棋盘",
"mistakes": 3,
"map": [
"....^",
".<...",
".....",
".>.v.",
"...v.",
],
},
4.路径检测
- 先求出前进路线
def path_cells(rows, cols, pos, direction):
"""箭头前进方向上、棋盘以内的所有格子(不含自己),按由近到远排列。"""
dr, dc = DELTA[direction]
r, c = pos[0] + dr, pos[1] + dc
cells = []
while 0 <= r < rows and 0 <= c < cols:
cells.append((r, c))
r += dr
c += dc
return cells
- 在判断路径上是否存在障碍
def find_blocker(arrows, rows, cols, pos, direction):
"""返回挡在这个箭头前方的第一个箭头坐标;前方畅通则返回 None。"""
for cell in path_cells(rows, cols, pos, direction):
if cell in arrows:
return cell
return None
- 关卡合理性判断,通过DFS找到最优解
def find_solution(index):
"""深度优先搜索一条零失误的通关顺序。
返回 [(r, c), ...](按点击先后排列);无解返回 None。
箭头数量很少(<= 12),直接穷举即可。
"""
rows, cols, arrows = parse_level(LEVELS[index])
order = []
failed_states = set()
def search(state):
if not state:
return True
key = frozenset(state)
if key in failed_states: # 该局面已证明走不通,剪枝
return False
for pos in sorted(state):
if find_blocker(state, rows, cols, pos, state[pos]) is None:
direction = state.pop(pos)
order.append(pos)
if search(state):
return True
order.pop()
state[pos] = direction
failed_states.add(key)
return False
return order if search(dict(arrows)) else None
四、AIGC使用过程
| 子任务 | 借助何种AIGC技术 | AI实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 提示功能的添加 | deepseek | 添加提示功能代码 | 功能完善 | 由单纯高亮提示改为直接点击箭头 |
| 画面清晰图优化 | deepseek | 优化画面清晰度 | 画面明显变清晰 | 进行验证 |
| 重开功能实现 | deepseek | 功能代码 | 无法使用 | 进行断点调试,修改 |
1.提示功能优化

2.画面清晰度优化

3.重开功能实现

人工修改:
通过断点调试确定按下r键的事件并没有被捕获,通过判断确定是中文输入法的原因,导致r键无法被捕获,这里设置进入游戏
后强制变更为英文输入,且禁用中文输入,原本的逻辑代码没有问题。修改后,功能正常。
五、自动化测试
通过代码进行自动化测试
核心代码:

这段代码会根据 find_solution(通过DFS找到最佳步骤)给出的方案,进行一次测试,确保关卡的可行性。
部分检测报告:

六、psp表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1 | 1 | 0 |
| Python 与图形库学习 | 3 | 2 | -1 |
| 游戏界面实现 | 1 | 2 | +1 |
| 路径与碰撞逻辑实现 | 1 | 1 | 0 |
| 关卡设计 | 1 | 1 | 0 |
| AIGC 辅助开发 | 1 | 0.5 | -0.5 |
| 测试与修改 | 1 | 1 | 0 |
| README 与博客撰写 | 1 | 1 | 0 |
| 合计 | 10 | 9.5 | -0.5 |
七、心得体会
-AI 带来的帮助
- 搭起项目骨架。把逻辑和渲染拆开:
game_logic.py不导入 pygame,规则判定可以脱离
图形界面单独运行和测试。这个结构是后面所有自动化验证的前提。 - 自动化验证脚本。
check_levels.py校验规则,main.py --auto直接驱动真实界面代码
把 4 关自动打通一遍,还覆盖了碰撞扣失误、重开复原、提示次数、判负等分支。 - 动画与视觉反馈。飞出拖尾、碰撞回弹闪红、路径预览、脉冲圆环这些效果直接可用。
- 定位画面模糊的真因。不是分辨率不够,而是 Windows 125% 缩放下进程不是 DPI 感知,
窗口被系统位图拉伸。这个原因我自己不一定会想到。
二、出现的问题
- AI 设计的第 3 关是无解的。它把
r3c5(下) 和r5c5(上) 摆成了互相阻挡,形成死局。
这是求解器报出"无解"才发现的。 - AI 的代码问题。发现R键重置关卡的bug
三、自己的收获
- 关键结论必须自己验证。AI 说得越顺、越像那么回事,越要动手确认。输入法那次就是
典型:推理链条听起来很合理,但前提是错的。 - 把"能自动检查的东西"交给程序。路径判定、关卡是否可解、重开是否复原,
这些都不该靠人一遍遍手点,写成脚本一次跑完,改代码后几秒就能回归。

浙公网安备 33010602011771号