实验报告:用 Python + AIGC 开发「一箭又一箭」风格小游戏

作业基本信息

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/16717
这个作业的目标 使用 Python 和 AIGC 完成「一箭又一箭」小游戏
学号 102401404
GitHub 仓库 https://github.com/Meng-tao123/sodaworld-arrow_puzzle-

说明:本次作业的核心玩法完全按照「一箭又一箭」基础版实现(单格方向、同行同列路径检测、失误机制、关卡流程)。
美术上把箭头造型换成了汽水瓶,并把「箭头方向」表达为瓶口朝向,规则与判定与箭头版完全一致;
这一改动只影响 BottleArt 的绘制部分,路径检测、状态机、关卡数据都不受影响。


我认为箭头看起来有些人机,然后参考了以前玩过的游戏——苏打世界,把箭头改成汽水瓶,感觉更有趣一些 OvO

一、项目展示

1. 运行演示(GIF)

游戏演示

动图内容依次为:标题界面 → 点击一个被阻挡的瓶子(瓶身晃动闪红、红色虚线标出阻挡者、失误 5→4)→ 按正确顺序点击瓶子飞出(尾部拖出苏打气泡)→ 清空后进入「关卡通过」→ 点击「下一关」进入第 2 关。

2. 开始界面

开始界面

3. 游戏界面

游戏界面

顶部依次是「关卡 1/4」「剩余汽水瓶 6」「剩余失误 5/5」,中间是居中排布的棋盘网格,底部是「重新开始」按钮与操作提示。

4. 飞出与碰撞反馈

飞出与气泡拖尾

碰撞反馈

左图:瓶子沿瓶口方向飞出棋盘,尾部持续生成白色半透明气泡拖尾;
右图:点到被阻挡的瓶子时瓶身晃动并变红,同时用红色虚线 + 叉号指出是哪一瓶挡住了它。

5. 通关 / 失败界面

通关界面显示「关卡通过」与「下一关」按钮;失误耗尽时显示「挑战失败」与「重新开始」按钮;打完最后一关显示「全部通关」与「再玩一次」。
image


二、项目介绍

1. 游戏规则

  1. 棋盘是网格,每格最多放一个汽水瓶,瓶口只有上、下、左、右四个朝向,瓶口朝向 = 飞行方向。
  2. 点击某个瓶子时,程序沿瓶口方向在同一行或同一列一直检查到棋盘边界:
    • 一路没有任何瓶子 → 瓶子沿该方向飞出棋盘并消失;
    • 路上还有别的瓶子 → 瓶子不能消失,给出碰撞反馈,并消耗 1 次失误机会。
  3. 清空本关全部瓶子 → 通关,点击「下一关」继续。
  4. 失误次数耗尽 → 本关失败,可以重新开始。

2. 界面设计

界面 内容
开始界面 游戏标题、副标题、四个朝向的瓶子示意、玩法提示、「开始游戏」按钮
游戏界面 顶部三块信息面板(关卡 / 剩余瓶子 / 剩余失误)、中间棋盘、底部「重新开始」按钮与提示条
结算界面 半透明遮罩 + 居中面板:「关卡通过」+「下一关」/「挑战失败」+「重新开始」/「全部通关」+「再玩一次」

3. 主要功能

  • 四种方向齐全,鼠标点击选择瓶子;路径检测与边界处理正确;
  • 飞出:加速飞离棋盘 + 苏打气泡拖尾(气泡逐渐变大、变淡、上浮飘散,出屏回收);
  • 碰撞:瓶身沿垂直方向晃动、短暂变红,并用红色虚线 + 叉号标出阻挡者;
  • 失误机制:界面实时显示剩余失误,耗尽后进入失败界面;
  • 关卡流程:4 个关卡,通关自动进入下一关,失败可重开,全部通关有最终提示;
  • 重新开始:底部按钮或 R 键都能让当前关卡布局与失误次数完全复原;
  • 音效:开瓶「噗」声、碰撞「咚」声、通关三音,全部由代码合成,也支持替换成音频文件。

4. 项目特色

  1. 零素材依赖:所有美术(汽水瓶、瓶盖、标签、气泡、界面)都用 Pygame 基础图形绘制,音效由代码合成,仓库里不需要任何图片 / 音频文件就能运行。
  2. 关卡可解性有保证:4 个关卡都通过内置求解器校验,python soda_bottle_puzzle.py --selftest 可以随时复检并打印一条参考解法。
  3. 自带诊断能力:--check 可以一键打印 Python / Pygame / 显示驱动 / 字体 / 音效状态,并开窗 6 秒统计实际帧数与鼠标点击数,方便排查「窗口没出现」「点击没反应」这类环境问题。
  4. 动画与音效的工程化处理:旋转贴图按 (尺寸, 方向, 配色) 缓存、气泡贴图按半径缓存、渐变背景只生成一次、粒子数量设上限,保证低开销稳定 60 FPS。

三、实现思路

1. 方向与箭头的表示

方向用四个字符表示,并配两套向量常量——这是本项目一个关键设计点:

DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT = "^", ">", "v", "<"

# 行列空间:(行增量, 列增量),只用于棋盘逻辑
DIR_VECTORS = {DIR_UP: (-1, 0), DIR_RIGHT: (0, 1), DIR_DOWN: (1, 0), DIR_LEFT: (0, -1)}

# 像素空间:(x 增量, y 增量),只用于飞行动画与气泡
DIR_PIXELS = {DIR_UP: (0, -1), DIR_RIGHT: (1, 0), DIR_DOWN: (0, 1), DIR_LEFT: (-1, 0)}

棋盘数据用二维数组存方向字符,空格用 None(布局文本里写 .):

self.grid[row][col] = "^" | "v" | "<" | ">" | None

为什么两套向量必须分开:行列坐标是「(行, 列)」,像素坐标是「(x, y)」,两者正好差 90°。
开发中真的踩到了这个坑——动画层直接用了行列向量,结果瓶子朝右侧飞时却是向下飞(详见第四节 AIGC 记录 3)。

2. 关卡的表示

每个关卡是一个字典,布局用字符串列表书写,可读性远好于纯数字数组:

{
    "name": "第 1 关",
    "cols": 5,
    "lives": 5,                 # 失误次数上限
    "layout": [
        "...<.",
        "^...v",
        "...^.",
        "..v..",
        ".>...",
    ],
}

字符含义:^ 上、v 下、< 左、> 右、. 空格。行数由字符串个数决定,列数由 cols 声明并在加载时校验。

3. 路径检测(核心)

这是整个作业最核心的算法。做法是:从被点击格子的相邻格开始,沿瓶口方向一格一格前进,直到走出棋盘;只要途中遇到任何瓶子就算被阻挡。

def scan_path(self, row, col):
    """返回 (是否畅通, 第一个阻挡瓶子坐标或 None)"""
    direction = self.bottle_at(row, col)
    if direction is None:
        return False, None
    dr, dc = DIR_VECTORS[direction]
    r, c = row + dr, col + dc          # 从相邻格开始,起点自身不算阻挡
    while 0 <= r < self.rows and 0 <= c < self.cols:
        if self.grid[r][c] is not None:
            return False, (r, c)       # 被这个瓶子挡住
        r += dr
        c += dc
    return True, None                  # 一路走到边缘,可以飞出

这段代码同时解决了作业里特别强调的两件事:

  • 边界处理:while 0 <= r < rows and 0 <= c < cols 本身就是边界判断。循环因为越界而结束时,正说明路径已经走到棋盘边缘,直接判定为“畅通”;不需要为四个方向分别写四套边界条件,也不可能出现数组越界。
  • 只查同行同列:每一步只沿 (dr, dc) 前进,向上/向下时列不变、向左/向右时行不变,天然满足“只判断同一行或同一列”。

函数还顺手返回第一个阻挡者的坐标,界面据此画出红色虚线与叉号,玩家能立刻明白“为什么飞不出去”。

4. 碰撞与飞出动画

点击后分两条分支:

clear, blocker = self.board.scan_path(row, col)
if clear:
    self.launch_bottle(row, col, direction)     # 从棋盘移除 + 生成飞出动画 + 播开瓶音效
else:
    self.blocked_feedback(row, col, direction, blocker)   # 扣失误 + 晃动闪红 + 标出阻挡者
  • 飞出:逻辑上立即把瓶子从 grid 移除,同时创建一个 FlyingBottle 对象,速度从 320 px/s 按 1500 px/s² 加速到 2100 px/s 上限飞出屏幕;每 10 ms 在瓶底位置喷出气泡,气泡带反向初速度、随机横向漂散、向上浮力,半径持续变大、透明度按寿命衰减,出屏后自动回收(粒子总数设了上限,长时间游玩不会卡顿)。
  • 碰撞:加入一个 ShakeAnim,位移方向垂直于瓶口方向(也就是瓶身的左右方向),振幅随时间衰减,并在动画前 75% 的时间把配色切成偏红的 "hit" 调色板,实现“晃动 + 闪红”;同时用 BlockedMarker 画红色虚线与叉号。
  • 结算延迟:清空棋盘或失误耗尽时,不立刻弹结算面板,而是设置 0.55 s / 0.8 s 的延迟,让玩家先看完飞行动画或晃动反馈,再切到结算界面。

5. 汽水瓶的绘制与旋转

瓶子只按「瓶口朝上」画一次(矩形圆角瓶身 + 多边形肩部 + 瓶颈 + 瓶盖 + 液面 + 标签 + 高光),再用 pygame.transform.rotate 旋转到目标方向,并按 (尺寸, 方向, 配色) 缓存:

DIR_ANGLES = {"^": 0, ">": -90, "v": 180, "<": 90}

base = self._render_up(size, palette)          # 只画一次朝上的瓶子
image = base if angle == 0 else pygame.transform.rotate(base, angle)
self._cache[(size, direction, palette_name)] = image

90° 的整数倍旋转不会改变 Surface 尺寸,所以瓶子永远精确居中;缓存之后每帧只做一次 blit,几乎零开销。

6. 游戏状态管理

用状态机串起整个流程:

START(标题) → PLAYING(进行中) → CLEAR(本关通过) → 下一关 / ALL_CLEAR(全部通关)
                         └→ FAIL(失误耗尽) → 重新开始本关

主循环固定 60 FPS,每帧计算 dt 并限制在 50 ms 以内(防止拖动窗口后动画“跳帧”),依次执行:处理事件 → 更新动画与粒子 → 绘制 → flip()。

7. 关卡为什么一定可以通关

本项目所有关卡都不是“随手摆”的,而是先由程序逆向构造再由求解器校验:按“消失顺序的逆序”往空棋盘上放瓶子,每次放入时都要求该方向的路径是空的,这样天然保证存在通关顺序。

另外还有一个很好的性质:移除瓶子只会让其他瓶子的路径变得更空,不会制造新的阻挡。所以只要关卡存在一条清空顺序,玩家每次点击“当前能飞的瓶子”都不会走进死局——这也解释了为什么“看清瓶口方向、只点能飞的瓶子”一定能赢,失误只来自点错。


四、AIGC 使用过程

本次开发全程使用 Codex(OpenAI 的编码智能体) 作为主要 AIGC 工具:由我提出需求与验收标准,AI 负责查资料、写代码、生成测试脚本与排查 Bug,我再逐项运行验证并做修改。

4.1 AIGC 使用一览

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果 如何人工修改
关卡设计 Codex 生成逆向构造算法 + 求解器校验脚本 一开始手工设计的关卡实际不可通关,改用程序生成后 4 关全部可解 手工挑选布局、设置每关失误上限、用 --selftest 复检
路径检测 Codex 生成 scan_path() 四方向检测与边界处理代码 一次通过,未出现越界 逐条核对边界条件,补充注释说明 while 条件即边界判断
飞行动画 Codex 生成加速飞行与气泡拖尾代码 瓶子却朝侧面飞出(偏 90°) 定位到行列向量/像素向量混用,拆成 DIR_VECTORS 与 DIR_PIXELS
汽水瓶绘制 Codex 用基础图形绘制瓶子 + rotate 旋转 + 缓存 四方向朝向正确、帧率稳定 建立像素级校验脚本逐格验证 46 个瓶子;测试脚本自身的坐标轴写法也修正了一次
音效 Codex 纯 Python 合成开瓶/碰撞/通关音 + 外部文件优先加载 无需素材即可出声,可替换为 wav 调整音量与包络、增加无声卡静音降级与 UTF-8 日志
环境排查 Codex 增加 --check 运行环境自检模式、一键启动脚本 定位到“命令被转义”“Ctrl+C 误报”两类问题 重写启动脚本的退出码判断,并强制日志 UTF-8

4.2 记录一:关卡设计——AI 生成的布局,真的可能无法通关

我的要求:先帮我设计 3~4 个逐步变难的关卡,并确保它们都能通关。

AI 做了什么:先给了两版“看起来很像原游戏”的手工布局。我没有直接采用,而是让 AI 写了一个求解器:用深度优先搜索枚举所有“能飞的瓶子”的点击顺序,看能否把棋盘清空。

实际效果:求解器一眼判定——第 1 关无法通关(初始状态可点击的瓶子数为 0,也就是所有瓶子互相挡死),第 2 关也只有 1 个可点瓶子且会走进死局。如果不做这步校验,这两关会直接踩中作业里“关卡实际上无法通关”的扣分项。

人工修改:改为程序化生成——按“消失顺序的逆序”往空棋盘上放瓶子,每次放入时要求该方向路径为空,这样天然保证可解;然后从大量候选中按“初始可点击数量、全程平均可点击数量、布局分散度、四个方向是否齐全”挑选,最后人工确定 4 关:

关卡 棋盘 瓶子 失误上限 初始可点击
第 1 关 5×5 6 5 5
第 2 关 6×6 10 4 5
第 3 关 6×6 14 3 5
第 4 关 7×7 16 3 7

同时把校验能力做进程序:--selftest 会逐关验证并打印一条参考解法,方便我每次改关卡后立刻复检。

4.3 记录二:路径检测——一次写对边界,但要自己核验

我的要求:按“同行或同列、从当前位置到棋盘边界之间是否有其他瓶子”实现检测,注意四个方向的边界,不许出现数组越界。

AI 做了什么:给出 scan_path()(见第三节代码),核心是从相邻格开始扫描,并用一个 while 0 <= r < rows and 0 <= c < cols 作为唯一循环条件;返回布尔值的同时返回第一个阻挡者坐标,供界面画提示线。

实际效果:一次运行通过,没有出现越界;四个方向的判定都正确。

人工修改与核验:我逐条推演了四个方向的边界情况(例如最上一行朝上、最右一列朝右时应立即判定畅通),并确认“起点自身不算阻挡”这一点是从 row + dr 开始的关键原因;另外补了注释,把这个技巧写清楚便于答辩讲解。为了可验证,我还写了一个像素级脚本:渲染每个瓶子后统计红色瓶盖的质心相对瓶身中心的偏移,逐一比对布局数据,46 个瓶子全部吻合。

4.4 记录三:一个真 Bug——瓶子朝右飞,却飞向了下方

我的要求:让瓶子沿瓶口方向飞出,并在尾部拖出气泡。

AI 做了什么:实现了 FlyingBottle(加速飞行、尾部定时喷气泡)与气泡粒子系统,代码看起来完全正常,画面截图也看不出问题。

实际效果:我让 AI 打印瓶子每 1/60 秒的位置,结果发现方向不对——朝右飞时 y 在增加(向下飞),也就是说飞行动画整体偏了 90°。

原因与人工修改:棋盘逻辑用的是「行列向量」(行增量, 列增量),而动画层把它直接当成了像素向量 (x, y),两者恰好差 90°。修复方案是拆成两套常量——DIR_VECTORS(行列,供棋盘逻辑)与 DIR_PIXELS(像素,供动画与气泡),并在文件头和 README 里写明“两者不可混用”。随后补了一条回归测试:对四个方向分别点击并累积位移,断言“沿瓶口方向的位移为正、垂直方向的偏移接近 0”,四个方向全部通过。

这个 Bug 也说明:AI 生成的代码“能跑”不等于“对了”,必须设计能暴露错误的验证手段(这里是数值断言,而不是肉眼看截图)。

4.5 记录四:汽水瓶绘制与旋转(连测试脚本本身也修了一次)

我的要求:用 Pygame 基础图形画一个简约汽水瓶,支持四个方向旋转,不要用外部图片,并且性能要好。

AI 做了什么:把瓶子按“瓶口朝上”画在一张透明 Surface 上(圆角瓶身、多边形肩部、瓶颈、瓶盖、液面、标签、高光),再用 pygame.transform.rotate 按 0 / -90 / 180 / 90 度旋转,结果按 (尺寸, 方向, 配色) 缓存,并额外维护一套偏红的 "hit" 调色板用于碰撞闪红。

实际效果:画面正常、60 FPS 稳定;但第一次跑像素级校验时,脚本报告“四个方向全部不符”。

人工修改:排查后发现问题在我的校验脚本——pygame.surfarray.array3d 返回的数组索引是 [x][y],我却按 [y][x] 取了坐标,等于把 x/y 轴写反了。修正脚本后,四个方向的瓶盖朝向全部正确。这件事提醒我:自动化测试报错时,先确认测试本身是否正确,否则会把好的代码改坏。

4.6 记录五:音效——没有素材也要能出声

我的要求:飞出播放“开汽水瓶”的音效、碰撞播放短促提示音;可以代码生成,也可以预留音频文件接口。

AI 做了什么:用标准库 array 手工合成 16bit 双声道 PCM 波形,交给 pygame.mixer.Sound(buffer=...) 播放:开瓶声是“高频噪声爆点 + 音高快速下滑的阻尼音调”,碰撞声是低频短促“咚”,通关是三音上行小叮咚;同时约定 assets/sounds/ 下同名 wav 文件优先加载,找不到才用合成音,并在没有音频设备时自动静音降级(不抛异常、不影响玩法)。

实际效果:实测三段音效时长分别为 0.24 / 0.14 / 0.60 秒,峰值约 0.6 满量程、无削波;开瓶音前 20% 的平均能量明显高于后段(说明“噗”的瞬态存在);把一段 0.5 秒的测试音频放到约定路径后,程序确实改为加载外部文件。

人工修改:我调整了音量系数与包络参数,让声音更接近“开瓶”的听感;并补充了“音频设备不可用则静音”的兜底分支。

4.7 记录六:排查“运行没反应”——把经验固化成工具

我的要求:程序要能在同学的电脑上按 README 直接跑起来。

遇到的实际问题:一次运行中,终端显示 [ERROR] The game exited with an error,同时出现 Terminate batch job (Y/N)?。

AI 做了什么:分析后确认这是在命令行按了 Ctrl+C 造成的——Ctrl+C 的退出码不是 0,被启动脚本误判成“程序崩溃”;另外还发现从聊天窗口复制命令时,路径里的下划线被转义成了 \_,导致文件名错误、命令根本没执行。

人工修改:把这两条经验固化进项目——给启动脚本加退出码判断(Ctrl+C 提示“Interrupted by Ctrl+C”,不再误报为崩溃)、把运行日志强制为 UTF-8(记事本打开不乱码);再给游戏加一个 --check 自检模式,一条命令就能打印 Python / Pygame / 显示驱动 / 窗口尺寸 / 字体 / 音效,并开窗 6 秒统计真实渲染帧数与鼠标点击数。实测在这台机器上输出为:视频驱动 windows、窗口 800×600、约 60 FPS、字体 msyh.ttc、音效已启用。


五、测试结果

5.1 作业要求的六项测试

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 瓶子沿瓶口方向加速飞出屏幕,剩余数量减 1,尾部有气泡拖尾 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 瓶子留在原地并晃动闪红,红色虚线与叉号标出阻挡者,失误 5→4 通过
T03 点击位于边缘且朝向棋盘外的箭头 正常消失,不发生越界错误 上/下/左/右四个方向分别测试,均立即飞出且无越界异常 通过
T04 消除本关全部箭头 显示通关并进入下一关 清空后 0.55 秒显示「关卡通过」,点「下一关」进入下一关;4 关用求解器给出的顺序全部走通 通过
T05 失误次数耗尽 显示失败并允许重新开始 第 5 次误点后显示「挑战失败」,点「重新开始」回到初始布局 通过
T06 游戏进行中重新开始 箭头布局和失误次数恢复 按钮与 R 键均可:瓶子数回到 6、失误回到 0/5 通过

5.2 补充的自动化测试

编号 测试内容 方法 结果
A01 关卡可解性 python soda_bottle_puzzle.py --selftest(内置求解器) 4 关全部「可通关 OK」,并给出参考解法
A02 朝向渲染正确性 渲染每个瓶子后统计红色瓶盖质心相对瓶身中心的偏移 4 个方向正确;4 关共 46 个瓶子与布局数据逐一吻合
A03 飞行动画方向 四方向各点击一次,累积位移做断言 沿瓶口方向位移为正、垂直偏移 ≈ 0;气泡拖尾位于瓶身后方;出屏后回收
A04 音效 读取波形统计时长 / 峰值 / 前后段能量;替换外部文件后再测 时长 0.24/0.14/0.60 s,无削波,瞬态明显,外部文件优先加载生效
A05 输入链路 向 pygame 事件队列投递真实 MOUSEBUTTONDOWN / KEYDOWN 按钮、瓶子、棋盘外点击、R/ESC 快捷键全部符合预期
A06 状态机健壮性 6000 次随机乱点(含棋盘外、结算面板、快捷键) 0 异常:状态始终合法、失误不超上限、棋盘清空必定进入结算流程
A07 完整流程 自动走完「标题 → 逐关通关 → 全部通关 → 再玩一次」 76 项断言全部通过
A08 真机冒烟 真实显示驱动 + 真实音频设备运行 视频驱动 windows,窗口 800×600,约 60 FPS,音频初始化成功

5.3 测试中发现并修复的问题

问题 现象 原因 修复
关卡不可通关 第 1 关初始可点瓶子数为 0 手工布局互相挡死 改为逆向构造 + 求解器校验
飞行动画偏 90° 朝右的瓶子向下飞 行列向量被当作像素向量使用 拆分 DIR_VECTORS / DIR_PIXELS 并加回归测试
校验脚本误报 四个方向全部“朝向不符” 测试里 surfarray 的 x/y 索引写反 修正测试脚本后全部通过
启动器误报崩溃 Ctrl+C 中断被当成程序出错 只看“退出码是否为 0” 单独识别中断退出码,并输出 UTF-8 日志
复制命令无法执行 路径下划线被转义成 \_ 从聊天窗口复制带入转义 文档改用 python soda*.py 通配符写法

六、PSP 表格

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

差异分析:图形库学习与界面实现比预期顺利(AI 直接给出了可运行的骨架);而关卡设计与测试修改都超时——关卡要保证可通关、动画要逐方向验证、音效与输入链路都要实测,这些“看不见的工作”占用了更多时间。


七、心得体会

1. AI 让“从零到能跑”变得非常快,但不会自动保证正确。
这次最典型的两个例子:AI 给出的手工关卡布局看起来完全合理,却根本无解;AI 写的飞行动画代码能跑、截图也看不出问题,实际却偏了 90°。它们都是靠“求解器校验”和“打印坐标做断言”才暴露出来的。所以我把这次作业的关键经验总结为一句话:让 AI 写代码的同时,也让它写能证伪这段代码的检查。

2. 需求描述越具体,AI 的产出越可用。
例如把“路径检测要正确处理边界”具体成“只检查同行同列、从当前位置到棋盘边界、不能越界”,AI 给出的 scan_path() 就一次写对了;而只说“做个好玩的小游戏”时,产出的东西往往需要大量返工。

3. 自动化测试救了我。
项目里最终留下了 4 类可重复运行的检查:关卡可解性自检(--selftest)、朝向像素级校验、飞行动画方向回归测试、6000 次随机乱点压力测试。每次改动画参数或换关卡,跑一遍就能确认没有把已经好的功能改坏——这也是我能放心重构动画层的前提。

4. 对“边界处理”的理解更扎实了。
以前写这类四方向扫描,第一反应是给四个方向各写一套边界判断。这次学到一个更简洁的写法:用统一的方向向量配合 while 0 <= r < rows and 0 <= c < cols,循环因越界而结束本身就代表“到达棋盘边缘”。代码短、不易漏分支,也好讲清楚。

5. 关于“额外功能”的取舍。
作业强调基础功能的完整与正确优先。所以我把精力放在“规则一定正确、关卡一定能通关、异常情况一定有反馈”上;汽水瓶造型、气泡拖尾、合成音效这些属于美化与体验,但都建立在核心玩法正确的基础上。若继续迭代,我会考虑:关卡选择与星级评价、提示功能、撤销上一步、保存进度,以及用 PyInstaller 打包成 exe 方便同学直接试玩。

6. 对“AI 生成代码”的态度。
AI 写出的代码进入项目后由我负责,所以我坚持两条:一是每一处关键逻辑我都能讲清楚(路径检测、向量拆分、状态机、可解性原理都写在注释和 README 里);二是不把没验证过的代码当成完成品,宁可多写几个测试脚本。这样即使在答辩时被追问细节,也能解释清楚。


 posted on 2026-09-22 21:28  明晚桃  阅读(13)  评论(0)    收藏  举报