You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:实现广度优先洪水填充搜索并返回首个匹配位置

广度优先洪水填充搜索函数修复方案

问题背景

需要实现一个函数,以广度优先的洪水填充模式在0,0至49,49的网格中搜索,找到能容纳指定size结构的首个RoomPosition类型位置并返回。现有代码存在崩溃或无限循环问题,无法正常返回结果。

原问题代码

function floodFillSearch(room: Room, startPosition: RoomPosition, structure: StampType, plannedPositions: RoomPosition[]): RoomPosition | undefined {
    Logger.log(`Start Position: ${startPosition.x}, ${startPosition.y}`, LogLevel.DEBUG)
    let x = startPosition.x
    let y = startPosition.y

    if (x > 49 || y > 49 || x < 0 || y < 0) { return }
    if (x + 1 > 49 || y + 1 > 49 || x - 1 < 0 || y - 1 < 0) { return }

    Logger.log(`Searching for ${structure} at ${x},${y}`, LogLevel.DEBUG)

    if (doesStampFitAtPosition(startPosition.x, startPosition.y, room, structure, plannedPositions)) {
        return new RoomPosition(startPosition.x, startPosition.y, startPosition.roomName)
    }

    let rightResult = floodFillSearch(room, new RoomPosition(startPosition.x + 1, startPosition.y, room.name), structure, plannedPositions, visited)
    let leftResult = floodFillSearch(room, new RoomPosition(startPosition.x - 1, startPosition.y, room.name), structure, plannedPositions, visited)
    let topResult = floodFillSearch(room, new RoomPosition(startPosition.x, startPosition.y + 1, room.name), structure, plannedPositions, visited)
    let bottomResult = floodFillSearch(room, new RoomPosition(startPosition.x, startPosition.y - 1, room.name), structure, plannedPositions, visited)

    if (rightResult) { return rightResult }
    if (leftResult) { return leftResult }
    if (topResult) { return topResult }
    if (bottomResult) { return bottomResult }
    return
}

补充说明:doesStampFitAtPosition函数用于检查起始位置的相邻n size区域是否符合预设条件,返回布尔值。需采用广度优先搜索实现。

问题分析

  • 搜索模式错误:原代码采用递归式深度优先搜索,不符合广度优先的要求,且递归深度过大时会触发栈溢出崩溃。
  • 无已访问记录:未标记已遍历的坐标,导致重复访问同一位置,引发无限循环。
  • 边界判断错误:提前排除了网格边缘的合法位置(比如x=49时直接返回,但该位置可能完全符合结构放置条件)。
  • 未定义变量:递归调用时传入了未声明的visited参数,直接导致运行报错。

修复后的代码

function floodFillSearch(room: Room, startPosition: RoomPosition, structure: StampType, plannedPositions: RoomPosition[]): RoomPosition | undefined {
    // 初始化队列,存储待搜索的位置
    const queue: RoomPosition[] = [startPosition];
    // 记录已访问的坐标,避免重复遍历
    const visited = new Set<string>();
    // 标记起始位置为已访问
    visited.add(`${startPosition.x},${startPosition.y}`);

    // 定义四个方向的偏移量
    const directions = [
        { x: 1, y: 0 },   // 右
        { x: -1, y: 0 },  // 左
        { x: 0, y: 1 },   // 上
        { x: 0, y: -1 }   // 下
    ];

    while (queue.length > 0) {
        const currentPos = queue.shift()!;
        const x = currentPos.x;
        const y = currentPos.y;

        Logger.log(`Searching for ${structure} at ${x},${y}`, LogLevel.DEBUG);

        // 检查当前位置是否能放置结构
        if (doesStampFitAtPosition(x, y, room, structure, plannedPositions)) {
            return new RoomPosition(x, y, room.name);
        }

        // 遍历四个方向
        for (const dir of directions) {
            const newX = x + dir.x;
            const newY = y + dir.y;
            // 检查新坐标是否在网格范围内
            if (newX >= 0 && newX <= 49 && newY >= 0 && newY <= 49) {
                const key = `${newX},${newY}`;
                // 未访问过的位置加入队列
                if (!visited.has(key)) {
                    visited.add(key);
                    queue.push(new RoomPosition(newX, newY, room.name));
                }
            }
        }
    }

    // 遍历完所有位置都没找到,返回undefined
    return undefined;
}

修复说明

  • 改用队列实现BFS:通过队列按顺序遍历每个位置,保证广度优先的搜索顺序,避免递归栈溢出。
  • 添加已访问集合:用字符串格式的坐标作为键,记录已遍历的位置,彻底解决无限循环问题。
  • 修正边界判断:仅排除网格外的坐标,保留边缘合法位置的搜索资格。
  • 移除无效递归参数:删除原代码中未定义的visited参数,改用局部集合管理访问状态。

内容的提问来源于stack exchange,提问作者xTwisteDx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:03:19