
本文介绍如何在 10×10 的数字网格中,健壮、简洁、边界安全地统计某单元格周围(8邻域)值为 2 的邻居数量,彻底解决边缘越界导致计数错误的问题,并提供可复用的泛型工具函数与优化实现。
本文介绍如何在 10×10 的数字网格中,**健壮、简洁、边界安全地统计某单元格周围(8邻域)值为 2 的邻居数量**,彻底解决边缘越界导致计数错误的问题,并提供可复用的泛型工具函数与优化实现。
在扫雷类游戏中,常需根据某个格子(如点击位置)快速统计其周围炸弹(此处用数字 2 表示)的数量。原始手动判断上下左右及四个对角共 8 个方向的方式(如 grid[row-1][col]、grid[row+1][col-1] 等)极易因边界检查逻辑疏漏(如遗漏 colIndex - 1 >= 0 && colIndex + 1 抽象“获取所有有效邻居”这一通用行为,再针对性过滤目标值。
✅ 推荐方案:泛型 getNeighbors 工具函数
以下是一个类型安全、边界鲁棒、可复用的邻域提取函数:
function getNeighbors<t>(
rowIndex: number,
colIndex: number,
source: Array<t>[],
radius: number = 1,
): Array<t> {
const neighbors: T[] = [];
if (!source?.length) return neighbors;
const numRows = source.length;
const numCols = source[0].length;
// 预计算合法行列范围,避免重复条件判断
const minRow = Math.max(0, rowIndex - radius);
const maxRow = Math.min(numRows - 1, rowIndex + radius);
const minCol = Math.max(0, colIndex - radius);
const maxCol = Math.min(numCols - 1, colIndex + radius);
for (let r = minRow; r <p>该函数支持任意半径(默认 1 即 3×3 邻域),自动裁剪超出边界的索引,且使用 Math.max/min 提前约束循环范围,比嵌套 if 判断更清晰、高效、不易出错。</p>
<h3>? 使用示例:统计周围 2 的数量</h3>
<p>假设你已通过 useState 初始化了 10×10 网格:</p>
<pre class="brush:php;toolbar:false;">const [grid, setGrid] = useState<number>(() =>
Array.from({ length: 10 }, () => Array(10).fill(0))
);</number>
只需一行即可获得指定 (rowIndex, colIndex) 周围 2 的个数:
完整的Galileo AI平台 TypeScript/JS SDK 参考,用于评估、观察和保护 GenAI 应用。适用于构建 Node.js 或 TypeScript 项目。
const countBombsNearBy = (rowIndex: number, colIndex: number): number => {
return getNeighbors(rowIndex, colIndex, grid)
.filter(value => value === 2)
.length;
};
✅ 优势验证:
- ✅ 边缘安全:(0, 0)(左上角)仅返回 [grid[0][1], grid[1][0], grid[1][1]],无越界;
- ✅ 中心排除:始终忽略自身格子,符合“周围”语义;
- ✅ 类型安全:泛型
支持 number、string 或自定义对象; - ✅ 易扩展:若需统计 2 或 3,仅需改为 .filter(v => v === 2 || v === 3)。
⚡ 进阶优化:极致性能(O(1) 固定邻域)
若严格限定只查 8 个直接邻居(即 radius = 1),可进一步消除循环开销,利用 TypeScript 的可选链(?.)实现零判断开销:
function get8Neighbors<t>(rowIndex: number, colIndex: number, source: Array<t>[]): T[] {
return [
source[rowIndex - 1]?.[colIndex - 1],
source[rowIndex - 1]?.[colIndex],
source[rowIndex - 1]?.[colIndex + 1],
source[rowIndex]?.[colIndex - 1],
source[rowIndex]?.[colIndex + 1],
source[rowIndex + 1]?.[colIndex - 1],
source[rowIndex + 1]?.[colIndex],
source[rowIndex + 1]?.[colIndex + 1],
].filter((v): v is T => v !== undefined); // 类型守卫,剔除 undefined
}
// 使用
const bombCount = get8Neighbors(rowIndex, colIndex, grid).filter(v => v === 2).length;</t></t>
此版本在编译期即确定访问路径,运行时无循环、无 Math 调用,适合高频调用场景(如实时渲染)。
? 注意事项与最佳实践
- 不要在组件渲染中直接调用 getNeighbors:若 grid 是 useState 管理的状态,请确保 countBombsNearBy 函数被 useCallback 缓存,并将 grid 加入依赖数组,避免闭包 stale props;
- 避免重复创建新数组:getNeighbors 每次返回新数组,若仅需计数,可改写为累加器减少内存分配;
- 测试边界用例:务必覆盖 (0,0)、(0,9)、(9,0)、(9,9) 及 (5,5) 等典型位置;
- 语义化命名:建议将 2 封装为常量(如 const BOMB = 2),提升可读性与可维护性。
通过抽象邻域获取逻辑,你不仅解决了当前的计数偏差问题,更获得了一个可在整个游戏逻辑中复用的基础能力——无论是计算提示数字、实现连击检测,还是后续添加“范围爆炸”效果,都由此变得简单而可靠。










