一次课堂实验记录:在 10×10 的网格世界里,把一个平均 350 步、60% 通关率的随机机器人,优化到平均 97 步、100% 通关。附带完整的踩坑过程。
文章目录

  1. 游戏规则:GridBot 是什么
  2. Baseline 分析:醉汉机器人为什么烂
  3. 优化思路:三个核心改动
  4. 核心代码解析
  5. 踩坑记录:0 通关到 47 分
  6. 结果对比
  7. 总结与展望
  8. 游戏规则:GridBot 是什么
    GridBot 是一个网格世界实验:机器人出生在 10×10 地图的左上角 (0,0),要走到右下角 (9,9) 的终点,路上散落着金币,还有墙壁挡路。
    机器人的信息获取和动作都受限,这正是「具身智能」的简化模型——只能靠自己的传感器和身体去探索世界:
    类别
    内容
    感知
    只能看到前 / 后 / 左 / 右一格:空地 / 墙壁 / 金币 / 终点 / 边界
    定位
    知道自己的坐标 (x, y)、朝向(北东南西)、终点坐标
    动作
    只有 4 个:前进 / 左转 / 右转 / 后转(转向不移动,移动必须先对准方向)
    记忆
    一个可以自由读写的 memory 列表,每局重置
    每张地图限制 500 步,超时判负。我的实验条件是学号尾号 6 对应的 「最少收集 3 枚金币才能通关」——金币不够时踩到终点格不算赢,这直接决定了策略设计。
  9. Baseline 分析:醉汉机器人为什么烂
    Baseline 的策略简单粗暴:
    def decide(perception):
    front = perception[“front”]
    if front in (“墙壁”, “边界”):
    return random.choice([“左转”, “右转”, “后转”])
    if random.random() < 0.5:
    return “前进”
    return random.choice([“左转”, “右转”, “后转”])
    翻译成人话:能走就有一半概率往前走,另一半概率随机转身;撞墙了就随机换个方向。
    它的问题不是「不会走」,而是「没有目标」:
  • 不知道终点在哪,走位完全靠布朗运动
  • 看到金币也不捡,全靠擦身而过
  • 没有记忆,同一个死胡同能进出八次
    实测平均 350 步到终点,成功率 60%,金币收集率约 50%。
  1. 优化思路:三个核心改动
    3.1 记忆地图
    感知只有一步视野,不记下来就是金鱼。所以每走一步,把前后左右看到的格子类型换算成绝对方位,存进 memory:
    memory[0] = {
    “grid”: {(x,y): “空地”/“墙壁”/“金币”/“终点”}, # 已知地图
    “coins”: {(x,y), …}, # 还没捡的金币
    “visited”: {(x,y), …}, # 走过的格子
    “goalPos”: (x, y), # 当前锁定的目标格
    }
    3.2 锁定下一格
    这是本次实验最重要的设计。第一版我让机器人每一步都重新比较方向,结果它会在相邻两格之间来回震荡——因为转向需要消耗步数,下一步的局势已经变了,它又推翻上一部的决定。
    解决方案:先选定「下一格要去哪」,然后连续执行转向+前进,直到真的踏上那格,才重新规划。
    3.3 先捡金币,再进终点
    针对实验条件的分段策略:
    状态
    行为
    眼前是金币
    直接踩上去
    眼前是终点,金币 ≥ 3
    进去,通关
    眼前是终点,金币 < 3
    绕开,去记忆中最近的一枚金币
    记忆中没有金币了
    去没走过的格子探索扫图
    探索超 120 步还凑不够
    放弃捡币,直奔终点保底

  2. 核心代码解析
    完整代码约 250 行,这里挑三个关键函数。
    4.1 记录地图
    def recordMap(perception):
    store = getStore(perception[“memory”])
    pos = perception[“position”]
    base = CLOCKWISE.index(perception[“direction”]) # 当前朝向

    visited.add(pos) # 踩过的格子
    coins.discard(pos) # 这格的金币已被自动捡走,从待捡列表删掉

    for key in (“front”, “right”, “back”, “left”):
    cell = perception[key]
    # 相对方位 → 绝对方位
    p = neighbor(pos, CLOCKWISE[(base + REL[key]) % 4])
    if cell in BLOCKED:
    grid[p] = cell
    elif p in visited:
    coins.discard§ # 走过的格子不可能是金币
    else:
    grid[p] = cell
    if cell == “金币”:
    coins.add§
    注意 (base + REL[key]) % 4 这一行:感知给的是「前/左/右/后」这种相对方向,要换算成「北东南西」的绝对方向才能存进地图。这个换算错一格,整张地图就全歪了。
    4.2 评分选格子
    def pickNextCell(perception, goal, store):
    best, bestScore = None, 9999
    for d in CLOCKWISE: # 北东南西四个方向都试一遍
    cell = cellAt(perception, d)
    if cell in BLOCKED:
    continue # 墙,跳过
    p = neighbor(pos, d)
    if cell == “终点” and coins < NEED_COINS:
    continue # 金币不够,先不进终点
    score = manhattan(p, goal) # 离目标越近越好
    if p in visited:
    score += 3 # 走过的格子加惩罚
    if cell == “金币”:
    score -= 2 # 顺路金币优先捡
    if score < bestScore:
    bestScore, best = score, p
    return best
    本质是一个单步的代价函数:曼哈顿距离打底,走过的路加罚分,金币减分(鼓励顺路捡)。
    4.3 主决策
    def decide(perception):
    recordMap(perception) # 先记地图
    if perception[“front”] == “金币”:
    return “前进” # 眼前有金币,踩
    if perception[“front”] == “终点” and perception[“coins”] >= 3:
    return “前进” # 条件满足,通关
    goal = nearestCoin(…) if coins < 3 else target
    return walkToCell(perception, pickNextCell(…, goal, …))

  3. 踩坑记录:从 0 通关到 47 分
    这部分是最有意思的,也是报告里最值钱的部分。第一版跑出来:平均 500 步,0 通关。
    坑 1:幽灵金币
    打印每步轨迹,发现机器人在 (9,8) 和 (9,9) 之间来回走,怎么都不进终点。
    排查:把记忆里的待捡金币集合打出来,发现里面有个坐标 (8,8)——但机器人明明已经踩过那里了,金币早捡走了。
    根因:游戏引擎是「踩上去自动捡金币」,但我的记忆里那格还标着「金币」,于是机器人永远认为那里还有一枚,反复回去找。
    修复:维护 visited 集合,凡是走过的坐标,强制从金币集合里删除。就这一行逻辑,通关率从 0% 起死回生。
    坑 2:门口打转
    修完坑 1,机器人在终点门口反复掉头——金币不够 3 枚进不去,记忆里又没有别的金币,它就在原地纠结。
    修复:加「探索模式」——记忆里没金币时,优先走没去过的格子扫图;再给个 120 步上限,超时直接放弃凑金币、保底去终点。
    坑 3:方向震荡
    每步重新规划方向时,机器人在两格之间来回横跳(转向也是要花步数的,世界状态一直在变)。
    修复:见 3.2,锁定目标格直到踏上去。
    三个坑修完,平均步数从 500 降到 97。

  4. 结果对比
    指标
    Baseline
    优化后
    提升
    平均步数
    ~350
    97
    3.6×
    金币收集率
    ~50%
    68%
    1.4×
    通关成功率
    ~60%
    100%(15/15)
    —
    自动评测得分
    —
    47 / 50
    —
    各地图明细(每图跑 3 次):
    地图
    平均步数
    金币收集率
    通关
    地图 1 — 新手村
    140
    100%
    3/3
    地图 2 — 小径
    136
    75%
    3/3
    地图 3 — 花园
    66
    60%
    3/3
    地图 4 — 迷宫入口
    61
    50%
    3/3
    地图 5 — 挑战迷宫
    83
    57%
    3/3

  5. 总结与展望
    收获
    这个实验最直观地展示了「具身智能」的一个核心矛盾:智能体的决策质量,取决于它的世界模型有多完整。感知只有一步视野,就必须靠记忆补全;记忆里错了一笔(幽灵金币),策略就会在物理世界里表现出「鬼打墙」。
    换句话说:机器人不是蠢,是它的地图错了。
    如果继续做

  6. BFS / A* 最短路:现在还是贪心,遇到 U 型墙会绕远路。既然已经有了记忆地图,完全可以在已知地图上做真正的寻路

  7. 金币路线规划:现在是「每次去最近的一枚」,多枚金币的访问顺序是个小型旅行商问题

  8. 传感器容错:实验条件里还有「方向传感器坏了」「GPS 坏了」等变体,可以用动作计数自己做里程计,不依赖引擎给的坐标
    一个课堂实验,代码不到 250 行,但从 0 通关到满分的过程中踩的每一个坑,都是「感知 → 记忆 → 决策」这条链路最真实的注脚。
    (完)
    在这里插入图片描述
    在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐