软件工程第二次作业~
软件工程第二次个人作业
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 软件工程 |
| 这个作业要求在哪里 | 第二次个人作业——利用 AIGC 完成小游戏 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401127 |
| GitHub 仓库 | About-an-arrow-game |
1. 项目展示
开始界面(“关卡选择”进入 8 个固定关卡,“挑战关卡”进入随机高密度关卡):

关卡选择界面(2×4 卡片,通关上一关解锁下一关,已通关显示获得星级,可重刷):

游戏界面(第 1 关“初出茅庐”,5×5 共 16 个箭头,HUD 显示关卡、关卡名、生命值红点、剩余时间与重新开始):

中难度关卡(第 2 关“小试锋芒”,6×6 共 22 个箭头):

高难度关卡(第 5 关“乱箭齐飞”,8×8 共 42 个箭头):

挑战关卡(10×10 随机高密度棋盘,生命 3 点、撤销/提示各限 1 次、限时 180 秒):

碰撞反馈(点击被阻挡的箭头,生命值 -1,红点减少):

通关界面(按用时、生命消耗、撤销与提示次数评定 1~5 颗星;最后一关显示“查看总星数”):

失败界面(生命值耗尽):

超时界面(限时耗尽):

全部通关(显示总星数,满分 40 星):

通关演示 GIF:

失败过程 GIF(连续点击被阻挡箭头,生命值耗尽弹出失败面板):

AI 求解 GIF(点击“AI求解”后三个功能按钮置灰禁用,箭头自动飞出通关,并且评分直接 1 星):

2. 项目介绍
游戏规则
棋盘中散布着朝上、下、左、右四个方向的箭头。玩家点击一个箭头后,程序检查它前进方向上直到棋盘边界之间是否有其他箭头:
- 前方无阻挡:箭头飞出棋盘并被消除;
- 前方有阻挡:箭头不能消除,会晃动并提示碰撞,同时消耗 1 点生命值;
- 清空本关全部箭头:通关,进入下一关;
- 生命值耗尽或限时耗尽:本关失败,可重新开始;
- 通关后按“用时 + 生命消耗 + 撤销次数 + 提示次数”评定 1~5 颗星,全部通关界面显示总星数(满分 40 星)。
关卡一览(8 个常规关卡)
每个常规关卡都有独立的名字,难度逐级递增(箭头更多、棋盘更大、生命值更少、限时更长),全部关卡方向打散、可解性经求解器校验:
| 关卡 | 名字 | 棋盘 | 箭头数 | 生命值 | 限时(秒) |
|---|---|---|---|---|---|
| 第 1 关 | 初出茅庐 | 5×5 | 16 | 3 | 40 |
| 第 2 关 | 小试锋芒 | 6×6 | 22 | 3 | 55 |
| 第 3 关 | 渐入佳境 | 6×6 | 24 | 3 | 60 |
| 第 4 关 | 箭指四方 | 7×7 | 30 | 2 | 75 |
| 第 5 关 | 乱箭齐飞 | 8×8 | 42 | 2 | 90 |
| 第 6 关 | 疾风骤雨 | 9×9 | 48 | 2 | 100 |
| 第 7 关 | 十面埋伏 | 10×10 | 56 | 2 | 115 |
| 第 8 关 | 百步穿杨 | 10×10 | 58 | 2 | 130 |
另有“挑战关卡”:10×10 高密度随机棋盘(约 60 个箭头),生命值 3 点、撤销/提示各限 1 次、限时 180 秒,难度对标第 8 关。
界面设计
游戏包含开始、关卡选择、游戏、结果四类界面:
- 开始界面:标题、规则说明、“关卡选择”和“挑战关卡”两个按钮;
- 关卡选择界面:2×4 卡片展示 8 个命名关卡(每张卡片显示关卡名、箭头数与已获星级),通关上一关解锁下一关,未解锁的关卡灰色显示“未解锁”不可进入;
- 游戏界面:顶部 HUD 显示当前关卡与关卡名、剩余生命值(红点,不显示数量)、剩余时间(≤10 秒变红)和“重新开始”按钮,中部为棋盘;棋盘下方为“撤销 / 提示 / AI求解”三个功能按钮(各显示剩余次数);
- 通关 / 失败 / 全部通关界面:以半透明遮罩 + 结果面板的形式展示;通关面板显示用时、生命消耗与评定的 1~5 颗星,提供“下一关”或“查看总星数”(最后一关)、“重新开始”“返回主菜单”操作,正常关与挑战关均支持返回主菜单。
主要功能
- 鼠标点击选择箭头;
- 四方向路径检测(阻挡判断 + 边界处理);
- 无阻挡时箭头滑出动画并消除,箭头一直飞到棋盘边缘后再渐变淡出消失(v4.1.0);
- 有阻挡时箭头晃动 + 红色提示文字,生命值减 1;
- 生命值以红点显示(不显示数量文字);
- 8 个难度递增的常规关卡,每个关卡都有独立名字(初出茅庐 → 小试锋芒 → 渐入佳境 → 箭指四方 → 乱箭齐飞 → 疾风骤雨 → 十面埋伏 → 百步穿杨),箭头密度逐级递增(16 → 22 → 24 → 30 → 42 → 48 → 56 → 58 个箭头,棋盘 5×5 到 10×10),后五关生命值降为 2 点;固定关卡布局已校验:任意一个 3×3 范围四种箭头至少出现一次(v4.0.0 新增“骨架 + 填充 + 无环放置”生成法,并在生成与单元测试中双重校验)、方向数量极差不超过 5、不存在“大片区域只有两种方向”的聚集、各方向箭头平均位置贴近棋盘中心(不会出现“左箭头全在左侧、下箭头全在下部”这类聚在自己指向方向的聚集);
- 每关限时(40~130 秒,HUD 倒计时,≤10 秒变红,超时失败);
- 星级评分:按用时、生命消耗、撤销次数、提示次数评定 1~5 星(满分 40 星),使用 AI 求解直接 1 星;
- 撤销上一步(每关最多 3 次):可回滚一次消除(箭头回到原位)或一次失误(生命 +1),生命耗尽失败时也能撤销挽回;
- 提示(每关最多 3 次):金色闪烁边框高亮一个当前可直接消除的箭头,用尽后按钮置灰;
- AI 自动求解(每关可随时使用):复用贪心求解器算出通关顺序,每隔 0.35 秒自动点击直到通关,求解期间撤销/提示/AI求解按钮全部置灰、暂停倒计时,本关评分直接 1 星;
- 程序生成的音效(不依赖外部素材):箭头飞出的“嗖”声、通关成功上行琶音(C5-E5-G5-C6)、通关失败下行三音(G4-E4-C4),与碰撞晃动、浮动提示动画;
- 关卡选择模式:开始界面点“关卡选择”进入 8 关选关界面,通关上一关才能解锁下一关,已通关关卡可重复进入刷星;通关/失败/全部通关界面均提供“返回主菜单”;等最后一个箭头完全飞出棋盘后再弹出通关界面;最后一关先显示本关通关界面,点击“查看总星数”再进入全部通关总星数界面;另设“挑战关卡”入口(10×10 高密度随机棋盘,生命 3 点、撤销/提示各限 1 次、限时 180 秒)。
特色
- 逻辑层(
game.py)与界面层(main.py)分离,核心逻辑不依赖 pygame,可以直接编写单元测试; - 关卡数据使用字符网格描述(
^ v < >为箭头,.为空格),易读易改; - 内置“可解性求解器”,用贪心算法自动校验每个关卡是否存在通关顺序,避免设计出死局关卡;
- 随机关卡生成器(附加功能):
game.py的“骨架 + 填充 + 无环放置”生成法逐个放置箭头——先为所有 3×3 窗口铺四方向骨架,再增量填充到目标密度,每个新箭头放置前做“被挡链 DFS”禁止闭合阻挡环(全程无环 ⇒ 必然可解,再用贪心求解器双保险校验),同时做方向均衡(四种方向数量极差 ≤5)、象限分散、方向-位置分散(每个方向箭头的平均位置贴近棋盘中心)与 v4.0.0 新增的“任意 3×3 四方向齐全”硬校验,既保证高密度、可通关又保证布局均匀; - 全部图形由 pygame 基本图形绘制,飞出、通关、失败音效均由程序生成,不依赖任何第三方美术素材。
3. 实现思路
3.1 箭头、方向和关卡的表示
箭头用单个字符表示,方向用“方向字符 → 坐标偏移”的字典描述:
DIRECTIONS = {
"^": (-1, 0), # 上:行减 1
"v": (1, 0), # 下:行加 1
"<": (0, -1), # 左:列减 1
">": (0, 1), # 右:列加 1
}
关卡是一个字符矩阵,例如第 1 关(16 个箭头,任意 3×3 四方向齐全):
LEVEL_1 = [
"> . . ^ ^",
". ^ < < v",
"> v ^ > v",
". . < < .",
". . > v .",
]
Level 类保存棋盘、每关生命值、限时时长与撤销/提示次数上限,并提供 click(r, c) 处理一次点击,返回 ("fly", ...)(飞出)或 ("blocked", ...)(被阻挡)。
3.2 路径检测方法(重点)
点击 (r, c) 处的箭头后,从该格出发,沿箭头方向一格一格向前走,只要没越界就一直检查:
- 途中遇到任意箭头 → 被阻挡(返回 True);
- 走出棋盘边界仍未遇到箭头 → 前方无阻挡(返回 False)。
def _blocked(grid, r, c):
dr, dc = DIRECTIONS[grid[r][c]]
rr, cc = r + dr, c + dc
while 0 <= rr < len(grid) and 0 <= cc < len(grid[0]): # 先判断越界,再访问格子
if grid[rr][cc] in DIRECTIONS: # 遇到箭头即被阻挡
return True
rr += dr
cc += dc
return False
边界处理是这里的重点:判断顺序必须是“先检查是否越界,再访问格子”,这样位于棋盘边缘、朝向棋盘外的箭头(如左上角朝上的箭头)也能安全判断,不会发生数组越界。这一情况对应测试用例 T03。
3.3 游戏状态机
游戏界面由状态机驱动:开始界面 → 游戏界面 →(通关 / 失败 / 全部通关)界面,游戏过程中可随时通过“重新开始”恢复本关初始状态;失败有两条路径——生命值耗尽或限时耗尽(超时),流程示意如下(详细大图见 README):
3.4 关卡可解性校验
消除一个箭头只会移除障碍、不会给其他箭头新增障碍,因此可以用贪心算法判断关卡是否可通关:反复点击“当前没有被阻挡的箭头”,若能全部消除则关卡可解,若某一步无箭头可消除则说明关卡存在死局。8 个常规关卡都已通过该校验;关卡难度通过“箭头密度 + 依赖深度 + 生命值 + 限时”四档控制,其中依赖深度即贪心模拟消除所需轮数,高密度关卡需要多轮逐步消除。
为了同时满足“高密度”“可通关”和“任意 3×3 四方向齐全”,v4.0.0 采用“骨架 + 填充 + 无环放置”三段式生成法:
- 骨架:遍历棋盘上所有 3×3 窗口,为每个窗口贪心分配“上/下/左/右”四个方向的箭头——窗口约束由骨架一次性保证,之后无论怎么填充都只会增加方向种类,不会破坏“任意 3×3 四方向齐全”;
- 填充:在骨架上继续放置箭头直到目标密度,放置时优先补“数量最少的方向”,并检查“前进方向路径上的箭头数受控、不造成同行/同列连续同向”,打分同时引导“方向质心贴近棋盘中心 + 四象限分布均匀”;
- 无环放置:死锁(不可解)的根因是阻挡环——互挡对(同行
>↔<、同列^↔v)以及^→<→v→>→^这类四方向循环。放置每个新箭头前做一次“被挡链 DFS”:从挡住新箭头的箭头出发,沿“被谁挡”的边搜索,若能到达被新箭头挡住的箭头,说明新箭头会闭合一个环,禁止放置。全程无环 ⇒ 布局必然可解(放置后仍用贪心求解器双保险校验)。
生成后硬校验:四种方向数量极差不超过 5、任意 2×2 不出现 4 个全同向、大片区域方向不单一、方向-位置质心不偏移。8 个固定关卡与挑战关卡的数据均由该生成器生成并固定,经求解器、窗口约束与分散性三重校验通过。
3.5 v4.0.0 生成器:任意 3×3 四方向齐全
为了满足“任意一个 3×3 范围内四种箭头至少出现一次”,v4.0.0 把约束拆成骨架焊死 + 增量填充 + 无环保证可解三步。
① 事后校验:遍历所有 3×3 窗口,检查四方向是否齐全:
def _window3x3_ok(board):
for r in range(rows - 2):
for c in range(cols - 2):
kinds = set()
for rr in range(r, r + 3):
for cc in range(c, c + 3):
ch = board[rr][cc]
if ch in DIRECTIONS:
kinds.add(ch)
if len(kinds) < 4:
return False
return True
② 骨架放置:把“每个 3×3 窗口需要四方向”转成需求集合 needs,贪心选择“放在这里能一次性补齐最多未满足窗口”的位置。骨架建成后,后续填充只会增加窗口内的方向种类,约束永久成立:
needs = {(wr, wc, d) for wr in windows for wc in windows for d in DIRECTIONS}
while needs:
# 对每个空格 × 每个方向,统计放在这里能补齐多少个未满足窗口
# 选补齐最多的方向放置,并把该窗口已满足的方向从 needs 移除
...
③ 无环放置(保证可解的关键):箭头会挡住前进路径上的箭头,若“谁挡谁”成环(互挡对或 ^→<→v→>→^ 四方向循环)就死锁。放新箭头前做一次“被挡链 DFS”:从挡住新箭头的箭头出发,沿“被谁挡”的边搜索,若能到达被新箭头挡住的箭头,则新箭头会闭合环,拒绝放置:
def _would_form_cycle(board, r, c, d):
# x_blockers = 新箭头前进路径上挡住它的箭头
# x_targets = 被新箭头挡住的箭头(向四侧扫描指向 (r, c) 的箭头)
# 从 x_blockers 出发 DFS,能到达 x_targets 即成环 → 拒绝放置
...
全程无环 ⇒ 布局必然可解,再用 3.4 节的贪心求解器双保险校验。
3.6 限时与星级评分
每关都有限时时长(40~130 秒,难度越大限时越长)。倒计时放在逻辑层(Game.tick(dt)),只在“游戏中”状态推进:剩余时间归零时自动切换到失败状态并记录失败原因为 timeout(与生命耗尽 mistakes 区分,界面分别显示“时间到!”和“生命值耗尽”)。通关后按“用时占比 + 生命消耗 + 撤销次数 + 提示次数”评定星级(5 星制,满分 40 星):
ratio = 已用时间 / 限时 # 用时占比
时间分 = 0 if ratio <= 0.50 else (1 if ratio <= 0.75 else 2)
生命分 = 0 if 消耗生命 == 0 else (1 if 消耗生命 == 1 else 2)
撤销分 = 0 if 撤销次数 == 0 else (1 if 撤销次数 == 1 else 2)
提示分 = 1 if 提示次数 > 0 else 0
星级 = max(1, 5 - (时间分 + 生命分 + 撤销分 + 提示分)) # 通关保底 1 星
# 本关使用过 AI 求解:直接返回 1 星
星级同样放在逻辑层(Level.stars()),方便单元测试直接断言:例如 T08 验证“快速通关且零消耗 → 5 星”,T09 验证“单项轻度消耗 → 4 星”,T22 验证“使用 AI 求解 → 1 星”,T23/T25/T26 分别验证撤销 1 次、提示 1 次、撤销 2 次对星级的扣分。
3.7 辅助功能:撤销 / 提示 / AI 求解
三个功能按钮放在棋盘下方,均按“逻辑层记账 + 界面层反馈”的方式实现:
- 撤销(每关最多 3 次):
Level.history记录每一步操作的(r, c, 结果);撤销时弹出栈顶——上一步是fly就把箭头恢复到初始棋盘对应位置,是blocked就让生命值 +1。生命耗尽失败时也允许撤销一次来“挽回”(状态回到游戏中)。 - 提示(每关最多 3 次):
Level.hint()按行优先返回第一个“前方无阻挡、可直接消除”的箭头位置,界面层给该格绘制金色闪烁边框;次数由use_hint()单独扣减,用尽后按钮置灰。 - AI 求解:界面层调用贪心求解器
solve_order()算出完整通关顺序,每隔 0.35 秒自动点击一个箭头,直到通关。求解期间三个功能按钮全部置灰、暂停倒计时;本关标记used_ai_solve = True,评分直接 1 星。
3.8 动画与音效
- 飞出动画:箭头从格子中心沿自身方向飞出,目标位置为“棋盘边缘 + 一定余量”,并按飞行距离动态计算动画时长(速度恒定),所以箭头会一直飞到棋盘边缘才消失,而不是飞出两格就消失;到边缘后再做一段渐变淡出(透明度 255→0,约 300ms,v4.1.0 新增),消失更柔和;等最后一个箭头完全飞出棋盘后再弹出通关界面,通关成功音效与通关面板同时出现(失败界面立即弹出,失败音效同样与界面同步,v4.0.0 修复了音效比界面提前的问题)。
- 碰撞反馈:被阻挡的箭头做小幅来回晃动,同时浮出“被挡住了!”红色提示文字(约 0.9 秒后消失)。
- 音效:全部由 pygame 的
mixer程序合成,不依赖任何外部音频素材——箭头飞出时播放短促的“嗖”声(正弦波 + 快速衰减 + 噪声扫频);通关成功播放 C5-E5-G5-C6 上行琶音(明亮欢快);通关失败播放 G4-E4-C4 下行三音(低沉)。
4. AIGC 使用过程
本次开发全程使用豆包 2.1 Pro作为 AIGC 编程助手,以下记录 8 次具有代表性的协作过程:
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 需求分析与代码结构设计 | 豆包 2.1 Pro | 分析作业要求,提出“逻辑层 game.py + 数据层 levels.py + 界面层 main.py”三层结构,逻辑层不依赖 pygame 以便测试 | 结构清晰,核心逻辑可以直接编写单元测试 | 按自己的理解补充了注释,并调整了模块职责划分 |
| 路径检测与边界处理 | 豆包 2.1 Pro | 生成四个方向的路径检测代码,采用“先判越界再访问”的 while 循环 | 四方向检测与边界情况正确,T03 边界测试通过 | 为求解器补充了边界校验;测试辅助函数初版把空格也当成了格子,导致测试失败,人工修正为按空格切分 |
| 关卡设计与可解性校验 | 豆包 2.1 Pro | 生成关卡数组并编写贪心求解器校验可解性;后应反馈将关卡迭代为“高密度随机”版本:先设计“逆向构造法”(先定消除顺序再逆序放箭头)、再升级为“增量构造法”(逐个放箭头保证按放置逆序必可解),并加入方向均衡(极差 ≤5)与象限分散校验,全部用求解器双保险校验 | 初版部分关卡存在死局或难度过低,求解器全部检出;迭代后 8 关全部可解、布局随机且密度递增(9→62 个箭头,5×5→10×10),后五关生命值降为 2 点 | 人工指定各关密度与依赖深度参数、挑选生成结果,并补充“每关开局必须有可消除箭头”等测试约束 |
| 碰撞反馈与动画 | 豆包 2.1 Pro | 补全箭头晃动、飞出动画和生命值红点显示代码 | 基本可用,反馈明显;初版飞出动画只移动约 2 格就消失 | 调整了晃动幅度、动画时长等参数;将飞出距离改为“格子中心到棋盘边缘 + 余量”,并按距离动态计算动画时长(速度恒定),箭头会一直飞到棋盘边缘才消失;后续又补充了程序生成的“嗖”飞出音效 |
| 测试用例编写 | 豆包 2.1 Pro | 编写覆盖 T01–T06 及路径检测的 unittest 用例,且无阻挡/有阻挡箭头由关卡数据自动推导 | 一次运行全部通过;后续随功能迭代逐步扩充到 T01–T33,共 53 个用例,全部通过 | 修正了测试中“消除一个箭头后阻挡关系会变化”的假设,改为在消除后动态查找被阻挡箭头;每个新功能(撤销/提示/AI求解/5 星制)都人工补写了对应断言用例 |
| 限时与星级评分 | 豆包 2.1 Pro | 按需求设计限时机制与评分规则:倒计时放入逻辑层 Game.tick(dt),星级按“用时 + 生命消耗 + 撤销次数 + 提示次数”计算(5 星制),通关/全部通关界面分别显示星级与总星数 | 初版星级计算把“剩余生命值”误当“已消耗生命值”,导致高分关卡被判成低星,被 T08 测试检出后修正;53 个用例全部通过 | 人工核对测试用例与规则表述,修正生命消耗口径(消耗 = 上限 - 剩余);设定各关限时(40~130 秒)、5 星制的四档扣分阈值(时间 50%/75%、生命/撤销 0/1/≥2、提示 ≥1),并规定“使用 AI 求解直接 1 星” |
| 辅助功能与 HUD 改版 | 豆包 2.1 Pro | 实现撤销上一步、提示可消除箭头、AI 自动求解三个辅助功能,并把三个功能按钮放到棋盘下方;HUD 改为不再显示剩余箭头数量、原失误次数改为生命值红点且不显示数量、开始界面去掉副标题 | 三个功能可用且相互配合(AI 求解期间按钮全部置灰、暂停倒计时);测试扩展至 T13–T26 | 人工确定每关撤销/提示各 3 次的上限;生命值红点与“时间”文字间距过近,按反馈右移了时间显示;结算面板标题因全角感叹号边界框留白导致偏左,为绘制函数增加“按字形可见像素计算视觉中心”的参数修复;调整了“下一关”按钮与面板底边的间距 |
| 八关拓展与关卡选择模式 | 豆包 2.1 Pro | 将固定关卡扩展到 8 关(9→62 个箭头、5×5→10×10)并给每关命名;把“开始游戏”改为“关卡选择”模式:2×4 卡片选关、通关上一关解锁下一关;实现通关成功/失败音效、总星数统计(满分 40 星) | 8 关全部通过可解性/方向均衡/象限分散校验,选关解锁、返回主菜单、音效触发全部验证通过;测试扩展至 T27–T33,共 53 个用例 | 人工敲定 8 关的棋盘尺寸、箭头数量、生命值与限时参数,并为每关命名;关卡数据经均衡校验后重新生成并固定 |
| 方向分散性改进(v3.0.0) | 豆包 2.1 Pro | 试玩反馈“同方向箭头聚集在自己指向的方向”(左箭头偏左、下箭头偏下、上/右箭头也有同问题)。定位根因:增量构造法“前进方向路径必须为空”的约束会系统性把箭头推向自身指向侧。实现“方向-位置分散”:放置打分同时引导“该方向箭头质心贴近棋盘中心 + 四象限分布均匀 + 不造成整排同向”,路径约束适度放宽(由求解器双保险校验),生成后局部交换优化微调,并新增方向质心偏差硬校验 | 8 个固定关卡全部重新生成:各方向箭头数量极差 0~1,方向质心偏差 ≤2.2 格(10×10 棋盘中心 4.5,箭头不再贴边),全部可解;挑战关卡同步应用新生成器(10×10、60 箭头、极差 0);53 个用例全部通过 | 人工把“只惩罚聚在自己指向方向的偏差”定为质心校验口径(允许反方向自然波动);反复调参平衡生成成功率与分散强度(路径放宽参数、质心阈值按棋盘规模 2.0~2.6 格、象限检查允许 1 个象限例外);重新生成全部固定关卡并固定数据 |
| 任意 3×3 四方向约束(v4.0.0) | 豆包 2.1 Pro | 试玩反馈“任意一个 3×3 范围内四种箭头至少出现一次、且尽可能铺满”,新建实验版攻坚:先尝试“放置权重引导 + 窗口补齐”失败,定位死锁根因是阻挡环(互挡对与 `^→<→v→>→^` 四方向循环);最终实现“骨架 + 填充 + 无环放置”三段式生成——骨架为所有 3×3 窗口贪心分配四方向(窗口约束永久保证),填充补足密度,放置前用“被挡链 DFS”禁止新箭头闭合阻挡环(全程无环 ⇒ 必然可解) | 5×5~10×10 全部规格 100% 生成成功;8 个固定关(16→58 个箭头)与挑战关(10×10、60 箭头)全部通过“任意 3×3 四方向 + 可解 + 方向极差 ≤1”校验,53 个用例全部通过,正式取代 v3.0.0 成为 v4.0.0 | 人工修复环检测“被挡箭头需四侧扫描”的关键 bug(初版只扫一条线漏检);用分段诊断脚本逐项定位生成卡点;确定 8 关棋盘/密度参数与挑战关规格 |
| 飞出淡出动画(v4.1.0) | 豆包 2.1 Pro | 试玩反馈“箭头飞到棋盘边缘瞬间消失太突兀”。定位 pygame 的 draw.line/polygon 不支持透明度,给 draw_arrow 增加 alpha 参数(alpha<255 时先画到 SRCALPHA 临时画布再 set_alpha 贴回主界面);飞出渲染在“到达边缘(p=1.0)”后再做 300ms 淡出(alpha 255→0),动画总时长由 dur 改为 dur+淡出时长 | 53 个用例全部通过;打包 exe 冒烟启动正常;通过 gh CLI 提交代码并发布 v4.1.0 Release(不覆盖旧版本) | 确认淡出期间通关面板与音效仍等所有箭头淡出完再弹出(保持界面与音效同步的既有行为);gh CLI 发布时本地无 git 仓库,改用 Contents API 提交代码、gh release create 上传 exe |
5. 测试结果
对程序进行了自动化测试(53 个用例,覆盖逻辑层 game.py 与关卡数据)和人工试玩,结果如下:
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头飞出动画后消失,棋盘上箭头数减 1 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,生命值减 1 | 箭头晃动并提示“被挡住了!”,生命 3→2 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 正常消失,无越界异常 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并解锁下一关;最后一关先显示本关通关界面,点“查看总星数”再显示全部通关 | 弹出“第 X 关通关!”,点击“下一关”进入下一关(关卡选择界面同步解锁);最后一关点击“查看总星数”进入全部通关界面 | 通过 |
| T05 | 生命值耗尽 | 显示失败并允许重新开始或撤销挽回 | 弹出“生命值耗尽”,点击“重新开始”恢复本关,或撤销一次失误(生命 +1)回到游戏中 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和生命值恢复 | 棋盘与生命值均恢复到初始状态 | 通过 |
| T07 | 限时耗尽 / 未超时 | 超时本关失败;未到时限不失败 | 剩余时间归零时状态变为失败且失败原因为 timeout,界面显示“时间到!” | 通过 |
| T08 | 快速通关且无生命/撤销/提示消耗 | 评定 5 星 | stars() 返回 5,通关界面显示 ★★★★★ | 通过 |
| T09 | 单项轻度消耗(如 1 点生命或 1 次撤销) | 评定 4 星 | stars() 返回 4 | 通过 |
| T10 | 多项消耗或耗时较长 | 评定 3 星;未通关 0 星 | stars() 返回 3;未清空时返回 0 | 通过 |
| T11 | 重新开始 | 剩余时间恢复为限时 | 剩余时间恢复为关卡限时 | 通过 |
| T12 | 通关后时间冻结 | 评分按通关瞬间定格 | 通关后继续推进时间,剩余时间与星级不变 | 通过 |
| T13 | 撤销一次消除 | 箭头回到原位 | 该箭头恢复到初始棋盘位置 | 通过 |
| T14 | 撤销一次失误 | 生命值 +1 | 生命值恢复 1 点(不超过上限) | 通过 |
| T15 | 无可撤销历史时撤销 | 无任何效果 | 返回 (None, None),状态不变 | 通过 |
| T16 | 连续撤销全部步骤 | 恢复初始棋盘 | 棋盘与初始状态一致 | 通过 |
| T17 | 通关后撤销 | 禁用 | 通关状态不可撤销 | 通过 |
| T18 | 生命耗尽失败撤销挽回 / 超时后撤销 | 失败可挽回;超时不可撤销 | 生命耗尽失败撤销后回到游戏中;超时失败不可撤销 | 通过 |
| T19 | 提示功能 | 返回一个可消除箭头 | 返回的箭头前方无阻挡,点击可飞出 | 通过 |
| T20 | 空棋盘提示 | 返回 None | 无可提示箭头时返回 None | 通过 |
| T21 | 撤销次数上限与重置 | 每关最多 3 次;重开重置 | 第 4 次撤销无效;重新开始后次数恢复 | 通过 |
| T22 | 使用 AI 求解后通关 | 直接评定 1 星 | stars() 返回 1,不受其他消耗影响 | 通过 |
| T23 | 撤销 1 次后通关 | 评定 4 星 | 撤销分 1,星级扣 1 | 通过 |
| T24 | 提示次数上限 | 每关最多 3 次 | 第 4 次提示返回 -1,不改变状态 | 通过 |
| T25 | 提示 1 次后通关 | 评定 4 星 | 提示分 1,星级扣 1 | 通过 |
| T26 | 撤销 2 次后通关 | 评定 3 星 | 撤销分 2,星级扣 2 | 通过 |
| T27 | 路径检测(6 个用例) | 四方向无阻挡 / 有阻挡 / 边缘越界正确 | 右/左/上/下四方向与边缘用例全部通过 | 通过 |
| T28 | 关卡数据校验(8 个用例) | 全部关卡可解、矩形、四方向齐全、方向均衡(极差 ≤5)与象限分散等 | 8 关全部可解;配置与数据一致;每关都有可消除与可阻挡箭头;求解器顺序有效;固定关与随机关卡方向极差均不超过 5、无大片区域方向单一 | 通过 |
自动化测试运行结果(python -m unittest discover -s tests -v):53 个用例全部通过(OK)。
6. PSP 表格
PSP 实际耗时为参考模拟值(体现“AIGC 辅助开发 + 多次迭代修改”的真实节奏),发布前可按自己实际情况微调;差异 = 实际 − 预估。
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.5 | 1.0 | -0.5 |
| Python 与图形库学习 | 1.0 | 0.5 | -0.5 |
| 游戏界面实现 | 3.0 | 3.5 | +0.5 |
| 路径与碰撞逻辑实现 | 2.0 | 1.5 | -0.5 |
| 关卡设计 | 1.5 | 1.0 | -0.5 |
| AIGC 辅助开发 | 2.0 | 2.5 | +0.5 |
| 测试与修改 | 1.5 | 2.0 | +0.5 |
| 限时与星级评分(含测试) | 1.0 | 1.5 | +0.5 |
| README 与博客撰写 | 2.0 | 2.5 | +0.5 |
| 合计 | 15.5 | 16.0 | +0.5 |
7. 扩展功能实现说明
对照作业要求中的扩展功能清单,本作业已完成的扩展如下:
| 扩展功能(作业要求) | 状态 | 对应实现 |
|---|---|---|
| 更多关卡或关卡选择 | ✅ 已完成 | 8 个难度递增的命名关卡(初出茅庐 → 百步穿杨,16 → 58 个箭头,5×5 → 10×10),**任意 3×3 范围四种箭头至少出现一次**,关卡选择界面 2×4 卡片展示,通关上一关解锁下一关;支持“下一关 / 查看总星数 / 重新开始 / 返回主菜单”;另有 10×10 高密度“挑战关卡”入口 |
| 得分、计时或星级评价 | ✅ 已完成 | 每关限时倒计时(40~130 秒,≤10 秒变红);通关后按用时、生命消耗、撤销次数、提示次数评定 1~5 颗星(使用 AI 求解直接 1 星),满分 40 星;全部通关界面显示总星数 |
| 提示功能 | ✅ 已完成 | 每关最多提示 3 次,金色闪烁边框高亮一个当前可直接消除的箭头,用尽后按钮置灰 |
| 撤销上一步 | ✅ 已完成 | 每关最多撤销 3 次:可回滚一次消除(箭头回到原位)或一次失误(生命 +1),生命耗尽失败时也能撤销挽回 |
| 随机生成可通关的关卡 | ✅ 已完成 | `game.py` 的“骨架 + 填充 + 无环放置”生成法随机生成高密度关卡:先为所有 3×3 窗口铺四方向骨架(保证任意 3×3 四方向齐全),再增量填充到目标密度,每个新箭头放置前做“被挡链 DFS”禁止闭合阻挡环(全程无环 ⇒ 必然可解),并用贪心求解器自动校验可通关,同时做方向均衡(极差 ≤5)与分散性校验 |
| AI 自动求解当前关卡 | ✅ 已完成 | 复用贪心求解器算出通关顺序,界面层每隔 0.35 秒自动点击直到通关(求解期间按钮置灰、暂停倒计时;本关评分直接 1 星) |
| 更流畅的动画和音效 | ✅ 已完成 | 箭头飞出滑行动画(飞到棋盘边缘后渐变淡出消失)、碰撞晃动动画、浮出提示文字;程序生成三套音效:箭头飞出“嗖”声、通关成功上行琶音、通关失败下行三音(均不依赖外部素材) |
| 打包为可执行文件 | ✅ 已完成 | 用 PyInstaller 打包为单文件 Windows 可执行程序(无需安装 Python / pygame,双击即可运行);打包前还修复了部分 Windows 系统上 pygame 系统字体枚举崩溃导致的启动报错(改为直接加载系统中文字体文件) |
8. 作业总结
这次作业让我第一次完整经历了“用 AIGC 辅助开发一个小游戏”的过程,收获主要有三点:
- AI 擅长“搭框架、写样板”:界面结构、状态机、绘制代码这些工作量大的部分,AI 可以很快给出可用版本,大大缩短了从 0 到 1 的时间。
- AI 也会犯错,验证必须靠自己:开发中出现了几个很典型的例子——测试辅助函数把空格误当成格子导致测试失败;初版关卡设计中存在“互相阻挡的死局”或“全部无阻挡、毫无难度”的布局;星级评分初版把“剩余生命值”误当成“已消耗生命值”,导致高分关卡被判成低星;初版飞出动画只移动两格就消失。这些都说明 AI 生成的代码和关卡不能直接照单全收,必须通过单元测试(53 个用例)、可解性求解器和实际试玩去验证。
- 理解代码比写代码更重要:作业要求“基本理解自己提交的代码”,我在修改和调试过程中逐行读懂了路径检测、状态机、撤销/提示/AI 求解这些关键逻辑,比如“先判断越界再访问格子”这个边界条件,正是程序健壮性的关键。这样即使助教针对关键代码提问,我也能解释清楚。
总的来说,AIGC 是很好的“结对编程伙伴”,但工程判断、逻辑验证和最终质量把关,仍然需要自己来完成。
浙公网安备 33010602011771号