2026 秋软件工程个人作业(第二次)

2026 秋软件工程个人作业(第二次)

这个作业属于哪个课程 H202601 软件工程与软件工程实践
这个作业要求在哪里 2026 秋软件工程个人作业(第二次)
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102402127
GitHub 仓库 代码在本地仓库 arrow-after-arrow,共六次提交。公开地址还没建好

本次作业我用 Python 和 Pygame 做了一个基础版“一箭又一箭”。路径检测、关卡和截图脚本都是和 Grok Build 一起改出来的。仓库里现在有六次提交,规则测试 19 项通过,六个关卡都能清空。

一、项目展示

开始界面有标题、四条规则和开始按钮。四种方向的箭头只作为装饰放在四角,不参与判定。

开始界面

第一关叫“出门见山”。棋盘是 3×3,四支箭头分别朝上、下、左、右。顶部显示关卡名、剩余箭头、剩余失误和用时。底部有撤销、提示、重新开始和返回菜单。

游戏界面

第二关点中被挡住的右箭头以后,格子变红并晃一下,格子上方浮出 -1,剩余失误从 3 变成 2。箭头还留在原位。

碰撞反馈

清空一关后出现通关卡片,可以进入下一关。

通关界面

失误次数耗尽后出现失败卡片,可以重新挑战本关。棋盘上的箭头不会在失败时被清掉。

失败界面

第六关清空后进入全部通关。

全部通关

第一关的通关过程做成了 GIF,方便核对飞出动画。

演示 GIF

这些画面由 capture_screens.pySDL_VIDEODRIVER=dummy 下直接从 Pygame Surface 导出。第一次导出时,碰撞图漏掉了,全部通关图也是错的。原因写在后面的 AIGC 记录里。

二、项目介绍

2.1 规则

棋盘是矩形网格,一格最多放一支箭头,方向只有上、下、左、右。点击一支箭头以后,程序沿着它的方向看它和棋盘边界之间有没有别的箭头。

作业里的两个例子可以直接对应到代码。

→  ·  ·  ↑  ·

左边这支朝右,右侧还有 ↑,不能飞。

↑  ·  ·  ·  →

右边这支朝右,右侧已经是边界,可以飞出。

贴边朝外的箭头同样可以飞。例如第 0 行的 ↑,下一步已经走出棋盘,路径是空的,判定为畅通。点空格子不会扣失误,也不会写入撤销记录。

本关全部箭头消失后进入下一关。失误次数减到 0 时本关失败,可以重新开始。重新开始会恢复本关的初始布局和失误次数。

2.2 界面和功能

开始、游戏、通关、失败四类界面都有。游戏界面固定显示当前关卡、棋盘、剩余箭头、剩余失误和重新开始。飞出时箭头沿自身方向移出棋盘并淡出。碰撞时变红、左右晃动,并浮出 -1

基础功能之外,我加了三件小东西。

  • 撤销上一步,连一次错误点击也可以收回。
  • 提示,把当前盘面交给求解器,高亮它给出的第一步。
  • 关卡在提交前都用深度优先搜索核过,确认存在清空顺序。

图形全部用 Pygame 画矩形和三角形,没有使用原游戏素材,也没有外部图片或音效文件。

2.3 运行方式

python -m pip install -r requirements.txt
python main.py
python -m unittest -v

本地验证环境是 Python 3.12.12 和 Pygame 2.6.1。中文界面优先加载本机的 Noto Sans CJK。

三、实现思路

规则和画面分成两层。arrow_logic.py 只处理格子、方向和点击结果。game.py 负责绘图、动画和菜单。这样路径对不对可以用单元测试直接核对,不必先打开窗口。

方向用四个字母表示,对应的行列位移写在 DIRS 里。

DIRS = {
    "U": (-1, 0),
    "D": (1, 0),
    "L": (0, -1),
    "R": (0, 1),
}

第 0 行在屏幕上方,所以“向上”是行号减一。关卡数据写成字符串,. 是空格,箭头用 ↑↓←→,读入时再转成 U/D/L/R。手工改关卡时比较直观。

路径检测是整个作业最要紧的一段。扫描从下一格开始,沿方向一格一格走,还在棋盘内就继续,碰到箭头就判定被挡,下一步会走出棋盘就判定畅通。

def can_fly(grid, row, col):
    if grid[row][col] not in DIRS:
        return False
    for nr, nc in ray_cells(grid, row, col):
        if grid[nr][nc] in DIRS:
            return False
    return True

贴边朝外的箭头第一步就越界,循环体一次都不进,返回畅通,不会去读 grid[-1]。点击成功时先把当前棋盘和失误次数压进历史栈,再改状态。动画只是把已经算完的结果演一遍。动画播放期间会挡住新的点击,避免连点把一次碰撞扣成两次。

求解器是带访问记录的深度优先搜索。每次合法点击都会让箭头数量严格减少,状态空间不大。提示按钮直接取解的第一步。六个关卡在测试里都会跑一遍求解器,解完后棋盘必须为空。

四、AIGC 使用过程

开发时用的是 Grok Build。下面三次是开发过程里实际发生过的,写博客时按当时改过的代码和测试回忆。

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
路径检测与规则测试 Grok Build 写出 can_fly、四个方向的位移,以及作业要求的 T01 到 T06 检测函数本身能用。第一版测试把 ←.→ 理解反了,把右侧朝右的箭头当成被挡 按“只看自己朝向的那一侧”改断言。后来补了一组对指布局 →.←↓/↑
关卡设计 Grok Build 先手写“十字路口”“回廊”“夹缝”,又写了一个随机生成器筛可解布局 三个手写关卡都被求解器判成死局。随机生成能出可解盘,但形状比较散 删掉死局。保留“出门见山”“先让路”“让一让”“夹道”,再换上已经解过的“错位”和“绕路”
无窗口截图 Grok Build capture_screens.py,用 dummy 显示驱动从 Surface 导出 PNG 和 GIF 第一关四支箭头都能飞,碰撞图根本没生成。全部通关图用 state = "all_clear" 硬切,画面还停在第二关,文案还写着五关 碰撞改到第二关拍摄。全部通关改成真正打完第六关。通关卡片上的按钮也改成只有点中卡片按钮才切关

这三次里,AI 都能很快给出能跑的草稿。我花时间最多的地方是核对它有没有做对。关卡看起来“像一箭又一箭”,求解器却说死局。截图脚本能出图,图里的状态却和文件名对不上。这些错都是后来用测试和读图发现的。

五、测试结果

规则层用 unittest 跑,当前 19 项全部通过。T01 到 T06 对应作业要求的手工场景,另外还测了路径、撤销、重开和六个关卡的可解性。

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出并消失 kind == "fly",格子变为 . 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误减 1 kind == "blocked",箭头仍在,失误 3 变 2 通过
T03 点击贴边朝外的箭头 正常消失,不越界 第 0 行 ↑ 和第 2 行 ↓ 都能飞出 通过
T04 消除本关全部箭头 报告通关 只剩一支时点击,返回 cleared 通过
T05 失误次数耗尽 报告失败,允许重开 失误上限为 1 时,一次阻挡返回 failed 通过
T06 游戏中途重新开始 布局和失误恢复 reset() 后格子和失误都回到关卡数据 通过

界面层用 capture_screens.py 走了一遍开始、对局、碰撞、通关、失败和全部通关。第一关存在求解器给出的四步清空顺序。第二关用被挡的右箭头验证碰撞和失败。第六关按求解器顺序清空后出现全部通关卡片。

本地跑测试时的输出是这样。

python -m unittest -v
Ran 19 tests in 0.001s
OK

六、PSP 表格

任务 预估耗时(小时) 实际耗时(小时) 差异(小时)
需求分析与游戏设计 0.5 0.4 -0.1
Python 与图形库学习 0.5 0.2 -0.3
游戏界面实现 1.5 0.8 -0.7
路径与碰撞逻辑实现 1.0 0.5 -0.5
关卡设计 0.8 0.6 -0.2
AIGC 辅助开发 1.0 0.8 -0.2
测试与修改 1.0 0.6 -0.4
README 与博客撰写 1.2 0.7 -0.5
合计 7.5 4.6 -2.9

预估按自己从零写一版来算。实际更短,因为界面骨架和测试可以由 AI 先铺出来。时间并没有省在“不用看代码”上,而是省在少写重复的绘制和断言。关卡死局、截图状态错误和测试断言写反,这三处仍然要自己对着棋盘和画面看。

七、心得体会

路径检测写出来只有十几行,错却经常出在“朝哪边看”。AI 第一次给测试时,把同一行里方向相反的两支箭头搞混了。人如果只看代码像不像,也会一起错。后来我把作业原文里的两个例子写成测试,对指的情况再单独测一遍,这块才稳住。

关卡更明显。我让 AI 直接排一个十字和一个回廊,盘面好看,求解器却返回 None。随机生成能保证可解,生成出来的形状又比较乱。最后采用的办法很土,先用手排出前几关,再只收下求解器能走完的布局。作业要求“每个关卡都应由本人实际试玩”,求解器只能证明存在顺序,不能代替自己点一遍。

截图脚本是这次最具体的教训。文件名写着 collision 和 all-clear,图里却可能还是另一关。AI 会为了交文件而直接改状态。后来改成真正去点格子、等动画结束再存盘,图才和规则对上。

AI 在这次作业里适合做三件事。铺 Pygame 窗口和按钮,补边界条件和单元测试,以及根据报错改一处具体代码。它不适合在没有求解器的情况下直接定关卡,也不适合在没有读图的情况下宣称“界面已经拍好”。代码进仓库以后,路径对不对、关卡能不能过、画面是不是当前状态,仍然要由提交的人负责。

posted @ 2026-09-22 23:30  山冇木兮木有枝  阅读(6)  评论(0)    收藏  举报