软件工程个人作业-2

项目 内容
这个作业属于哪个课程 H202601 软件工程与软件工程实践
这个作业要求在哪里 2026 秋软件工程个人作业(第二次)
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102401335
GitHub 仓库 HangLog-tech/software_engineering_work_2

一、项目展示

1. 开始界面

01_start

2. 游戏过程

demo_level2

09_level6

3. 通关界面

06_win

4. 失败界面

07_fail


二、项目介绍

1. 游戏规则

浏览器/微信中的“一箭又一箭”是一类点击式箭头解谜游戏。本项目实现的是它的基础玩法:

  • 棋盘由网格组成,每格最多一个箭头,方向为上、下、左、右之一;
  • 点击箭头后,程序沿箭头方向直线检测:
    • 前方没有其他箭头阻挡 → 箭头飞出棋盘并消除;
    • 前方存在其他箭头 → 箭头不能消除,抖动、闪红并浮出 -1,失误次数 -1;
  • 清空本关全部箭头即通关并进入下一关;
  • 失误次数耗尽则本关失败,可重新开始。

规则示例:

→  ·  ·  ↑  ·

第一个箭头朝右,右侧仍有箭头阻挡,不能飞出;

↑  ·  ·  ·  →

最后一个箭头朝右,右侧没有箭头,可以飞出棋盘。

2. 界面设计

  • 开始界面:标题、方向箭头装饰、开始游戏 / 继续游戏 / 关卡选择 / 随机关卡 / 退出游戏;
  • 游戏界面:顶部标题与关卡进度;信息栏显示剩余箭头、失误次数、用时;右上角电灯泡提示按钮;中央棋盘;底部撤销 / 重新开始 / 退出关卡;
  • 结算界面:通关时显示用时、本关得分、三星评价与累计总分;失败时显示剩余箭头与用时;
  • 关卡选择界面:按进度解锁 6 个关卡,显示各关最佳星级。

3. 主要功能

基础功能:

  • 四种方向箭头、鼠标点击交互、直线路径阻挡判断;
  • 飞出消除与碰撞反馈(抖动 + 闪红 + 浮字);
  • 失误次数显示与判负、通关切关、重新开始;
  • 6 个经程序验证可通关的关卡。

扩展功能:

  • 计时、得分与三星评价;
  • 撤销上一步;
  • 电灯泡提示:成功消除箭头后 60 秒冷却,冷却结束才可用;
  • 关卡选择、随机关卡(保证可通关);
  • 本地保存进度与未完成对局(支持“继续游戏”);
  • 退出关卡(保留对局进度);
  • 程序合成的简单音效(无外部素材)。

4. 项目特色

  • 关卡可解性有保障:所有固定关卡都通过“贪心消除”程序化验证;随机关卡在生成时反复检测,确保 100% 可通关;
  • 零外部资源:音效由代码合成,不依赖任何图片/音频素材,仓库干净;
  • 可复盘的结构:入口、状态机、游戏逻辑、界面、存档、音效分模块编写,便于测试与迭代;
  • 可持续迭代:提供 17 项 pytest 单元测试,覆盖路径检测、关卡可解性、计分星级与存档恢复等。

5. 运行方式

pip install -r requirements.txt
python main.py

三、实现思路

1. 数据结构:箭头、方向与关卡

方向用四种字符表示,棋盘是一个二维数组(空位为 None,箭头为 "U"/"D"/"L"/"R");关卡数据直接用字符串数组描述,直观且便于手工调整:

DIRS = {"U": (-1, 0), "D": (1, 0), "L": (0, -1), "R": (0, 1)}
DIR_CHARS = {"U": "↑", "D": "↓", "L": "←", "R": "→"}

LEVELS = [{
    "name": "初识箭头",
    "mistakes": 3,
    "grid": [
        "→..↑.",
        ".....",
        "..↓.←",
        ".....",
        "..↓..",
    ],
}]

2. 路径检测

沿箭头方向逐格前进,遇到任意箭头即视为阻挡;循环条件同时检查越界,因此“贴边朝外”的箭头会直接到达边界外,不会数组越界:

def can_fly_out(self, row, col):
    direction = self.board[row][col]
    dr, dc = DIRS[direction]
    r, c = row + dr, col + dc
    while self.in_bounds(r, c):
        if self.board[r][c] is not None:  # 射线上有箭头 → 被阻挡
            return False
        r, c = r + dr, c + dc
    return True                            # 到达边界外 → 可飞出

3. 状态机与模块划分

游戏有四个界面状态:start(开始)、playing(游戏)、win(通关)、fail(失败),另有 level_select(关卡选择)。主循环每帧处理事件 → 更新(计时、动画、胜负判定)→ 绘制。

代码按职责拆分为多个模块:

main.py     程序入口(仅启动应用)
app.py      状态机、事件处理、更新与主循环
game.py     棋盘、路径检测、随机关卡生成与计分
levels.py   6 个关卡数据
ui.py       字体、按钮、箭头绘制与动画
sound.py    程序合成音效
storage.py  本地进度存档(save.json)
tests/      单元测试

4. 动画与反馈

  • 飞出:箭头沿方向平移并渐隐(约 0.28 秒);
  • 碰撞:原位抖动并闪红,同时浮出“-1”提示;
  • 动画期间锁定棋盘输入,避免快速连点导致状态错乱(浮动文字不锁输入)。

5. 计分与星级

本关得分 = 1000 + 剩余失误 × 150 - 用时秒数 × 5(最低 100)
星级:0 失误 = 3 星;失误不超过上限一半 = 2 星;其余 = 1 星

6. 随机关卡的可解性保证

由于“消除只会让路径更通畅”,只要不断消除当前可飞出的箭头,若最终能全部清空则关卡可解。生成随机布局后立即用该方法验证,并优先保留“初始超过一半箭头被阻挡”的布局,避免出现一开局就能无脑全消的关卡:

def greedy_solve(game):
    while not game.cleared:
        cell = find_one_flyable(game)   # 找一个当前可飞出的箭头
        if cell is None:
            return False                # 出现互锁 → 判为不可解
        game.click(*cell)
    return True

四、AIGC 使用过程

以下记录来自真实开发过程,均保留了对 AI 输出的验证与人工修改。

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
需求分析与原型设计 DeepSeek 根据作业要求整理玩法规则、界面线框、关卡设计与测试用例 结构完整,可直接指导开发 逐关检查可解性,发现原设计存在两处“箭头面对面互锁”的死局并重新设计
路径检测与核心逻辑 DeepSeek 生成棋盘、四方向路径检测、失误与关卡管理代码 基本可用,边界情况需验证 补充“失败后不再接受点击”守卫;修正浮动提示文字不应锁住棋盘输入的问题
界面与动画 DeepSeek 生成棋盘绘制、圆角箭头棋子、飞出/抖动动画与按钮 视觉与交互符合预期 大棋盘改为格尺寸自适应;提示改为右上角电灯泡并加冷却倒计时角标
提示冷却、计分与存档 DeepSeek 实现计时计分、星级、进度存档与“继续游戏” 功能完整,状态流转基本正确 修正失败界面“重新开始”语义(应重玩本关而不是回到第 1 关);退出关卡改为保存对局
测试与联调 DeepSeek 编写 pytest 单元测试与无头界面流程测试 能发现真实问题,回归快 解决 Python 3.14 无 pygame 官方安装包的问题(改用 API 兼容的 pygame-ce);修复中文编码与存档隔离问题

几个代表性的人工修改细节:

  1. 死局修正:AI 最初的关卡设计里,同一行存在“→”与“←”相对的情况,二者永远互相阻挡。我编写了贪心求解脚本逐关验证,重新设计后才得到现在 6 个可零失误通关的关卡。
  2. 输入锁定范围:最初“-1”浮动文字动画也会锁住输入,导致点击手感迟滞。我确认该动画只是视觉反馈后,将其从输入锁判定中排除,只保留飞出/碰撞动画锁输入。
  3. 按钮语义:失败界面的“重新开始”最早期实现成重新从第 1 关开始,测试发现后改为重玩当前关。

五、测试结果

1. 单元测试(pytest)

python -m pytest tests -q
# 17 passed

覆盖内容:四方向路径检测、阻挡判定、飞出/失误/重新开始、失误耗尽、6 个固定关卡与随机关卡的可解性、存档快照恢复、计分与星级规则。

2. 功能测试用例

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 与预期一致
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 抖动闪红并浮出“-1”,失误 3→2
T03 点击位于边缘且朝向棋盘外的箭头 箭头正常消失,不发生越界错误 与预期一致,无越界异常
T04 消除本关全部箭头 显示通关并进入下一关 显示“本关通过!”结算面板
T05 失误次数耗尽 显示失败并允许重新开始 显示“挑战失败”,可重新开始本关
T06 游戏进行中重新开始 箭头布局和失误次数恢复 与预期一致
T07 六关依次通关 最终显示全部通关 显示“全部通关!”
T08 四个方向各验证一次阻挡/飞出 判定结果与理论一致 与预期一致
T09 点击空白格 状态无变化 与预期一致,不扣失误
T10 动画播放期间连续点击 不出现重复消除或失误误扣 与预期一致
T11 每关按可解顺序试玩 均可零失误通关,无死局 与预期一致

补充说明:T01~T11 通过“无头自动化流程测试 + 手工试玩”共同验证;自动化测试脚本模拟鼠标点击遍历全部关卡,保证回归时结果稳定。

3. 测试中发现并修复的问题(部分)

  • 提示按钮在成功消除后会重置 60 秒冷却,需在测试中按真实时间推进验证;
  • 动画期间点击二次消除导致连消:通过输入锁修复;
  • 9×9 大棋盘在 800×600 窗口内溢出:改为格尺寸按棋盘规模自适应。

六、PSP 表格

任务 预估耗时(小时) 实际耗时(小时) 差异(小时)
需求分析与游戏设计 2 2 0
Python 与图形库学习 3 4 +1
游戏界面实现 4 4.5 +0.5
路径与碰撞逻辑实现 4 5 1
关卡设计 2 1 -1
AIGC 辅助开发 4 4 0
测试与修改 3 2.5 -0.5
README 与博客撰写 3 2 -1
合计 25 25 25

七、心得体会

这次作业让我第一次完整地用 AIGC 走了一遍“需求分析 → 设计 → 编码 → 测试 → 文档”的流程,感受最深的有三点。

第一,AI 能显著加快起步,但验证必须由人完成。无论是关卡布局、路径检测还是界面绘制,AI 给的初版都能跑,但真正的问题往往藏在细节里:互锁的死局、失败的按钮语义、动画锁输入的范围。这些问题不靠“看起来对”,而要靠写脚本验证、逐关试玩和针对性的测试去发现。

第二,测试是人与 AI 协作的安全网。为 can_fly_out 写的单元测试、对 6 个关卡与随机关卡的贪心可解性验证、模拟点击的无头流程测试,让我在多次重构之后,依然能快速确认没有把功能改坏。AI 可以很快地改代码,但“改完还是对的”要靠测试兜底。

第三,结构清晰才能持续迭代。一开始所有代码都堆在 main.py 里,随着功能变多越来越难改;拆成入口 / 状态机 / 逻辑 / 界面 / 存档后,每次加功能只需要动一两个文件。AI 在重构时非常高效,但前提是我能说清楚“每个模块负责什么”。

最后,AI 生成的代码由我负责。这次我保留了关键修改的过程记录,也尽量让每一段关键代码都能讲清楚“为什么这样写”。这种“AI 产出 + 人工把关”的模式,是这次作业最大的收获。

posted @ 2026-09-17 14:07  月落孤砚  阅读(3)  评论(0)    收藏  举报