软件工程第二次作业~

软件工程第二次个人作业

项目 内容
这个作业属于哪个课程 软件工程
这个作业要求在哪里 第二次个人作业——利用 AIGC 完成小游戏
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102401127
GitHub 仓库 About-an-arrow-game

1. 项目展示

开始界面:

01_start

游戏界面(第 1 关,HUD 显示关卡、生命值红点、剩余时间与重新开始):

02_game_level1

随机生成的关卡(第 2 关,6×6 共 16 个箭头):

03_game_level2

高难度关卡(第 5 关,8×8 共 42 个箭头):

04_game_level5

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

05_collision

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

06_level_clear

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

07_failed

超时界面(限时耗尽):

08_timeout

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

09_all_clear

通关演示 GIF:

10_demo

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

11_fail

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

12_solving

2. 项目介绍

游戏规则

棋盘中散布着朝上、下、左、右四个方向的箭头。玩家点击一个箭头后,程序检查它前进方向上直到棋盘边界之间是否有其他箭头:

  • 前方无阻挡:箭头飞出棋盘并被消除;
  • 前方有阻挡:箭头不能消除,会晃动并提示碰撞,同时消耗 1 点生命值;
  • 清空本关全部箭头:通关,进入下一关;
  • 生命值耗尽或限时耗尽:本关失败,可重新开始;
  • 通关后按“用时 + 生命消耗 + 撤销次数 + 提示次数”评定 1~5 颗星,全部通关界面显示总星数(满分 25 星)。

界面设计

游戏包含开始、游戏、结果三类界面:

  • 开始界面:标题、规则说明、“开始游戏”按钮;
  • 游戏界面:顶部 HUD 显示当前关卡、剩余生命值(红点,不显示数量)、剩余时间(≤10 秒变红)和“重新开始”按钮,中部为棋盘;棋盘下方为“撤销 / 提示 / AI求解”三个功能按钮(各显示剩余次数);
  • 通关 / 失败 / 全部通关界面:以半透明遮罩 + 结果面板的形式展示;通关面板显示用时、生命消耗与评定的 1~5 颗星,提供“下一关”或“查看总星数”(最后一关)、“重新开始”“返回首页”操作。

主要功能

  1. 鼠标点击选择箭头;
  2. 四方向路径检测(阻挡判断 + 边界处理);
  3. 无阻挡时箭头滑出动画并消除,箭头一直飞到棋盘边缘才消失;
  4. 有阻挡时箭头晃动 + 红色提示文字,生命值减 1;
  5. 生命值以红点显示(不显示数量文字);
  6. 5 个已校验可通关的关卡,箭头密度与依赖深度逐级递增(9 → 16 → 18 → 22 → 42 个箭头,最后一关 8×8 共 42 个箭头、接近铺满棋盘),后两关生命值降为 2 点;除新手关外均为随机生成,方向完全打散,避免“一整行同一方向”的规律布局;
  7. 每关限时(40~90 秒,HUD 倒计时,≤10 秒变红,超时失败);
  8. 星级评分:按用时、生命消耗、撤销次数、提示次数评定 1~5 星(满分 25 星),使用 AI 求解直接 1 星;
  9. 撤销上一步(每关最多 3 次):可回滚一次消除(箭头回到原位)或一次失误(生命 +1),生命耗尽失败时也能撤销挽回;
  10. 提示(每关最多 3 次):金色闪烁边框高亮一个当前可直接消除的箭头,用尽后按钮置灰;
  11. AI 自动求解(每关可随时使用):复用贪心求解器算出通关顺序,每隔 0.35 秒自动点击直到通关,求解期间撤销/提示/AI求解按钮全部置灰、暂停倒计时,本关评分直接 1 星;
  12. 程序生成的“嗖”飞出音效(不依赖外部素材)与碰撞晃动、浮动提示动画;
  13. 通关、失败(生命耗尽 / 超时)、关卡切换、重新开始流程完整:等最后一个箭头完全飞出棋盘后再弹出通关界面最后一关先显示本关通关界面,点击“查看总星数”再进入全部通关总星数界面

特色

  • 逻辑层(game.py)与界面层(main.py)分离,核心逻辑不依赖 pygame,可以直接编写单元测试;
  • 关卡数据使用字符网格描述(^ v < > 为箭头,. 为空格),易读易改;
  • 内置“可解性求解器”,用贪心算法自动校验每个关卡是否存在通关顺序,避免设计出死局关卡;
  • 随机关卡生成器(附加功能)tools/generate_level.py 用“逆向构造法”随机生成高密度关卡并自动校验可通关,方向完全打散、布局每次不同;
  • 全部图形由 pygame 基本图形绘制,飞出音效由程序生成,不依赖任何第三方美术素材。

3. 实现思路

3.1 箭头、方向和关卡的表示

箭头用单个字符表示,方向用“方向字符 → 坐标偏移”的字典描述:

DIRECTIONS = {
    "^": (-1, 0),   # 上:行减 1
    "v": (1, 0),    # 下:行加 1
    "<": (0, -1),   # 左:列减 1
    ">": (0, 1),    # 右:列加 1
}

关卡是一个字符矩阵,例如第 1 关(9 个箭头):

LEVEL_1 = [
    ". > . ^ .",
    "> . > . ^",
    ". < . 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):

game_flow

3.4 关卡可解性校验

消除一个箭头只会移除障碍、不会给其他箭头新增障碍,因此可以用贪心算法判断关卡是否可通关:反复点击“当前没有被阻挡的箭头”,若能全部消除则关卡可解,若某一步无箭头可消除则说明关卡存在死局。5 个关卡都已通过该校验;关卡难度通过“箭头密度 + 依赖深度 + 生命值 + 限时”四档控制,其中依赖深度即贪心模拟消除所需轮数,第 5 关达到 7 轮。

为了同时满足“高密度”和“可通关”,第 2~5 关使用“逆向构造法”随机生成:先随机选好 N 个格子和一个消除顺序,再按逆序逐个放置箭头,放置每个箭头时保证其前进方向上不包含“更晚消除”的箭头,这样原消除顺序必然全部有效;生成后再过滤掉“一整排同向”等不美观布局,并用求解器双保险校验。

3.5 限时与星级评分

每关都有限时时长(40~90 秒,难度越大限时越长)。倒计时放在逻辑层(Game.tick(dt)),只在“游戏中”状态推进:剩余时间归零时自动切换到失败状态并记录失败原因为 timeout(与生命耗尽 mistakes 区分,界面分别显示“时间到!”和“生命值耗尽”)。通关后按“用时占比 + 生命消耗 + 撤销次数 + 提示次数”评定星级(5 星制):

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.6 辅助功能:撤销 / 提示 / 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.7 动画与音效

  • 飞出动画:箭头从格子中心沿自身方向飞出,目标位置为“棋盘边缘 + 一定余量”,并按飞行距离动态计算动画时长(速度恒定),所以箭头会一直飞到棋盘边缘才消失,而不是飞出两格就消失。
  • 碰撞反馈:被阻挡的箭头做小幅来回晃动,同时浮出“被挡住了!”红色提示文字(约 0.9 秒后消失)。
  • 音效:用 pygame 的 mixer 合成一段短促的“嗖”声(正弦波 + 快速衰减 + 噪声扫频),每次箭头飞出时播放,不依赖任何外部音频素材。

4. AIGC 使用过程

本次开发全程使用豆包(Doubao)作为 AIGC 编程助手,以下记录 7 次具有代表性的协作过程(均来自真实开发过程):

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
需求分析与代码结构设计 豆包(Doubao) 分析作业要求,提出“逻辑层 game.py + 数据层 levels.py + 界面层 main.py”三层结构,逻辑层不依赖 pygame 以便测试 结构清晰,核心逻辑可以直接编写单元测试 按自己的理解补充了注释,并调整了模块职责划分
路径检测与边界处理 豆包(Doubao) 生成四个方向的路径检测代码,采用“先判越界再访问”的 while 循环 四方向检测与边界情况正确,T03 边界测试通过 为求解器补充了边界校验;测试辅助函数初版把空格也当成了格子,导致测试失败,人工修正为按空格切分
关卡设计与可解性校验 豆包(Doubao) 生成关卡数组并编写贪心求解器校验可解性;后应反馈将关卡迭代为“高密度随机”版本:设计“逆向构造法”随机生成器(先定消除顺序再逆序放箭头),自动过滤“一整行同向”等规律布局,并校验全部可解 初版部分关卡存在死局或难度过低,求解器全部检出;迭代后 5 关全部可解、布局随机且密度递增(9→42 个箭头),后期生命值降为 2 点 人工指定各关密度与依赖深度参数、挑选生成结果,并补充“每关开局必须有可消除箭头”等测试约束
碰撞反馈与动画 豆包(Doubao) 补全箭头晃动、飞出动画和生命值红点显示代码 基本可用,反馈明显;初版飞出动画只移动约 2 格就消失 调整了晃动幅度、动画时长等参数;将飞出距离改为“格子中心到棋盘边缘 + 余量”,并按距离动态计算动画时长(速度恒定),箭头会一直飞到棋盘边缘才消失;后续又补充了程序生成的“嗖”飞出音效
测试用例编写 豆包(Doubao) 编写覆盖 T01–T06 及路径检测的 unittest 用例,且无阻挡/有阻挡箭头由关卡数据自动推导 一次运行全部通过;后续随功能迭代逐步扩充到 T01–T26,共 44 个用例,全部通过 修正了测试中“消除一个箭头后阻挡关系会变化”的假设,改为在消除后动态查找被阻挡箭头;每个新功能(撤销/提示/AI求解/5 星制)都人工补写了对应断言用例
限时与星级评分 豆包(Doubao) 按需求设计限时机制与评分规则:倒计时放入逻辑层 Game.tick(dt),星级按“用时 + 生命消耗 + 撤销次数 + 提示次数”计算(5 星制),通关/全部通关界面分别显示星级与总星数 初版星级计算把“剩余生命值”误当“已消耗生命值”,导致高分关卡被判成低星,被 T08 测试检出后修正;44 个用例全部通过 人工核对测试用例与规则表述,修正生命消耗口径(消耗 = 上限 - 剩余);设定各关限时(40~90 秒)、5 星制的四档扣分阈值(时间 50%/75%、生命/撤销 0/1/≥2、提示 ≥1),并规定“使用 AI 求解直接 1 星”
辅助功能与 HUD 改版 豆包(Doubao) 实现撤销上一步、提示可消除箭头、AI 自动求解三个辅助功能,并把三个功能按钮放到棋盘下方;HUD 改为不再显示剩余箭头数量、原失误次数改为生命值红点且不显示数量、开始界面去掉副标题 三个功能可用且相互配合(AI 求解期间按钮全部置灰、暂停倒计时);测试扩展至 T13–T26 人工确定每关撤销/提示各 3 次的上限;生命值红点与“时间”文字间距过近,按反馈右移了时间显示;结算面板标题因全角感叹号边界框留白导致偏左,为绘制函数增加“按字形可见像素计算视觉中心”的参数修复;调整了“下一关”按钮与面板底边的间距

5. 测试结果

对程序进行了自动化测试(44 个用例,覆盖逻辑层 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 通过
路径检测(6 个用例) 四方向无阻挡 / 有阻挡 / 边缘越界正确 右/左/上/下四方向与边缘用例全部通过 通过
关卡数据校验(7 个用例) 全部关卡可解、矩形、四方向齐全等 5 关全部可解;配置与数据一致;每关都有可消除与可阻挡箭头;求解器顺序有效 通过

自动化测试运行结果(python -m unittest discover -s tests -v):44 个用例全部通过(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. 扩展功能实现说明

对照作业要求中的扩展功能清单,本作业已完成的扩展如下:

扩展功能(作业要求) 状态 对应实现
更多关卡或关卡选择 ✅ 已完成 5 个难度递增关卡(9 / 16 / 18 / 22 / 42 个箭头,最后一关 8×8 共 42 个箭头、接近铺满),支持“下一关 / 查看总星数 / 重新开始 / 返回首页”
得分、计时或星级评价 ✅ 已完成 每关限时倒计时(40~90 秒,≤10 秒变红);通关后按用时、生命消耗、撤销次数、提示次数评定 1~5 颗星(使用 AI 求解直接 1 星),满分 25 星
提示功能 ✅ 已完成 每关最多提示 3 次,金色闪烁边框高亮一个当前可直接消除的箭头,用尽后按钮置灰
撤销上一步 ✅ 已完成 每关最多撤销 3 次:可回滚一次消除(箭头回到原位)或一次失误(生命 +1),生命耗尽失败时也能撤销挽回
随机生成可通关的关卡 ✅ 已完成 `tools/generate_level.py` 逆向构造法随机生成高密度关卡,并用贪心求解器自动校验可通关,方向完全打散
AI 自动求解当前关卡 ✅ 已完成 复用贪心求解器算出通关顺序,界面层每隔 0.35 秒自动点击直到通关(求解期间按钮置灰、暂停倒计时;本关评分直接 1 星)
更流畅的动画和音效 ✅ 已完成 箭头飞出滑行动画(飞到棋盘边缘才消失)、碰撞晃动动画、浮出提示文字,以及程序生成的“嗖”飞出音效(不依赖外部素材)
打包为可执行文件 ✅ 已完成 用 PyInstaller 打包为单文件 Windows 可执行程序(无需安装 Python / pygame,双击即可运行);打包前还修复了部分 Windows 系统上 pygame 系统字体枚举崩溃导致的启动报错(改为直接加载系统中文字体文件)

8. 作业总结

这次作业让我第一次完整经历了“用 AIGC 辅助开发一个小游戏”的过程,收获主要有三点:

  1. AI 擅长“搭框架、写样板”:界面结构、状态机、绘制代码这些工作量大的部分,AI 可以很快给出可用版本,大大缩短了从 0 到 1 的时间。
  2. AI 也会犯错,验证必须靠自己:开发中出现了几个很典型的例子——测试辅助函数把空格误当成格子导致测试失败;初版关卡设计中存在“互相阻挡的死局”或“全部无阻挡、毫无难度”的布局;星级评分初版把“剩余生命值”误当成“已消耗生命值”,导致高分关卡被判成低星;初版飞出动画只移动两格就消失。这些都说明 AI 生成的代码和关卡不能直接照单全收,必须通过单元测试(44 个用例)、可解性求解器和实际试玩去验证。
  3. 理解代码比写代码更重要:作业要求“基本理解自己提交的代码”,我在修改和调试过程中逐行读懂了路径检测、状态机、撤销/提示/AI 求解这些关键逻辑,比如“先判断越界再访问格子”这个边界条件,正是程序健壮性的关键。这样即使助教针对关键代码提问,我也能解释清楚。

总的来说,AIGC 是很好的“结对编程伙伴”,但工程判断、逻辑验证和最终质量把关,仍然需要自己来完成。

posted on 2026-09-17 21:42  OooneCloud  阅读(6)  评论(0)    收藏  举报