像素网格递归填充函数实现方案咨询
嘿,我来帮你搞定这个像素填充的需求!这本质上是简化版的洪水填充算法,正好匹配你描述的逻辑——点击一个像素,然后把相邻同色的都改成黑色,碰到不同颜色就停。下面我会结合两种常见的像素存储方式,给出具体实现方案:
核心实现思路
不管像素是怎么存储的,核心逻辑都一致:
- 先记录被点击像素的原始颜色,如果它已经是黑色,直接终止操作(避免无意义循环)
- 检查当前像素是否在网格范围内,且颜色和原始颜色一致
- 符合条件就把它改成黑色,然后继续处理上下左右四个相邻像素
- 如果像素颜色和原始颜色不同,或者超出网格边界,就停止当前分支的遍历
1. 基于二维数组的实现(最直观)
如果你的像素网格是用二维数组存储的(比如grid[y][x]对应坐标(x,y)的像素颜色),可以用下面的递归版本快速实现:
示例网格与函数代码
// 示例:3x3的像素网格,中间是红色,其余是蓝色 const pixelGrid = [ ["blue", "blue", "blue"], ["blue", "red", "blue"], ["blue", "blue", "blue"] ]; function fillPixelGrid(grid, startX, startY) { const originalColor = grid[startY][startX]; // 已经是黑色就直接返回 if (originalColor === "black") return; // 递归处理单个像素的函数 function fill(x, y) { // 边界检查:超出网格范围就终止 if (x < 0 || x >= grid[0].length || y < 0 || y >= grid.length) return; // 颜色不同,终止当前分支 if (grid[y][x] !== originalColor) return; // 修改为黑色 grid[y][x] = "black"; // 递归遍历上下左右 fill(x - 1, y); // 左 fill(x + 1, y); // 右 fill(x, y - 1); // 上 fill(x, y + 1); // 下 } // 启动填充 fill(startX, startY); }
使用方式
// 点击中间的红色像素(坐标x=1, y=1) fillPixelGrid(pixelGrid, 1, 1); console.log(pixelGrid); // 输出结果:中间的红色会被改成黑色,周围蓝色保持不变
2. 基于像素对象数组的实现
如果你的像素是存储在一维对象数组里(每个像素结构类似{ x: 0, y: 0, color: "#ff0000" }),可以先建立一个坐标映射表,方便快速查找相邻像素:
示例数据与函数代码
// 示例:一维像素对象数组 const pixels = [ { x: 0, y: 0, color: "blue" }, { x: 1, y: 0, color: "blue" }, { x: 2, y: 0, color: "blue" }, { x: 0, y: 1, color: "blue" }, { x: 1, y: 1, color: "red" }, { x: 2, y: 1, color: "blue" }, { x: 0, y: 2, color: "blue" }, { x: 1, y: 2, color: "blue" }, { x: 2, y: 2, color: "blue" } ]; // 建立「x-y坐标」到像素对象的映射,方便快速查找 const pixelMap = {}; pixels.forEach(pixel => { pixelMap[`${pixel.x}-${pixel.y}`] = pixel; }); function fillPixelObjects(pixelMap, startX, startY) { const startPixel = pixelMap[`${startX}-${startY}`]; if (!startPixel) return; // 找不到起始像素,直接终止 const originalColor = startPixel.color; if (originalColor === "black") return; function fill(x, y) { const currentPixel = pixelMap[`${x}-${y}`]; // 像素不存在或颜色不符,终止当前分支 if (!currentPixel || currentPixel.color !== originalColor) return; // 修改为黑色 currentPixel.color = "black"; // 遍历上下左右 fill(x - 1, y); fill(x + 1, y); fill(x, y - 1); fill(x, y + 1); } fill(startX, startY); }
使用方式
// 点击中间的红色像素(坐标x=1, y=1) fillPixelObjects(pixelMap, 1, 1); console.log(pixels); // 输出结果:中间的红色像素会被改为黑色
进阶优化:避免递归栈溢出
如果你的像素网格特别大,递归版本可能会触发栈溢出问题。这时候可以改用迭代+队列的方式实现,逻辑和递归完全一致,但更稳定:
// 迭代版本的二维数组填充函数 function fillPixelGridIterative(grid, startX, startY) { const originalColor = grid[startY][startX]; if (originalColor === "black") return; // 用数组模拟队列,存储待处理的像素坐标 const queue = [[startX, startY]]; // 标记已处理的像素,避免重复入队 const processed = new Set(); processed.add(`${startX}-${startY}`); while (queue.length > 0) { const [x, y] = queue.shift(); grid[y][x] = "black"; // 定义四个方向的偏移量 const directions = [[-1,0], [1,0], [0,-1], [0,1]]; for (const [dx, dy] of directions) { const newX = x + dx; const newY = y + dy; const key = `${newX}-${newY}`; // 检查边界、颜色、是否已处理 if ( newX >=0 && newX < grid[0].length && newY >=0 && newY < grid.length && grid[newY][newX] === originalColor && !processed.has(key) ) { processed.add(key); queue.push([newX, newY]); } } } }
内容的提问来源于stack exchange,提问作者saricden
相关产品推荐
相关产品推荐

