
本文介绍一种健壮、可复用的 TypeScript 方法,用于统计 10×10 网格中某单元格周围(8 邻域)值为 2 的相邻格子数量,特别解决边界越界导致计数错误的问题。
本文介绍一种健壮、可复用的 typescript 方法,用于统计 10×10 网格中某单元格周围(8 邻域)值为 `2` 的相邻格子数量,特别解决边界越界导致计数错误的问题。
在实现扫雷类游戏逻辑时,一个常见需求是:给定坐标 (rowIndex, colIndex),快速、准确地统计其周围 8 个方向(上、下、左、右、四个对角线)中值为 2(代表炸弹)的格子数量。原始手写条件判断(如逐个检查 rowIndex-1, colIndex+1 等)极易因边界处理疏漏(尤其是网格边缘和角落)导致漏判或越界访问,进而引发 undefined 比较错误或运行时异常。
推荐采用通用邻域提取 + 函数式过滤的思路,既提升可读性与可维护性,又彻底规避边界问题。核心分为两步:
✅ 第一步:安全提取所有邻域元素(支持自定义半径)
以下 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>该实现优势显著:</p>
<ul>
<li>✅ <strong>无越界风险</strong>:通过 Math.max/min 限定循环范围,天然适配任意尺寸网格;</li>
<li>✅ <strong>逻辑简洁</strong>:消除深层嵌套 if,大幅降低出错概率;</li>
<li>✅ <strong>可扩展性强</strong>:radius 参数支持未来扩展(如统计 3×3 区域内所有 2);</li>
<li>✅ <strong>类型安全</strong>:泛型 <t> 保证返回数组类型与源数组一致。</t>
</li>
</ul>
<h3>✅ 第二步:精准过滤并计数</h3>
<p>调用 getNeighbors 后,只需一行代码即可获得周围 2 的数量:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7968" title="Galileo TypeScript sdk"><img
src="https://img.php.cn/upload/skill/000/000/081/179178490051362.jpg" alt="Galileo TypeScript sdk" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7968" title="Galileo TypeScript sdk" class="overflowclass">Galileo TypeScript sdk</a>
<p class="overflowclass">完整的Galileo AI平台 TypeScript/JS SDK 参考,用于评估、观察和保护 GenAI 应用。适用于构建 Node.js 或 TypeScript 项目。</p>
</div>
<a rel="nofollow" href="/xiazai/skill7968" title="Galileo TypeScript sdk" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<pre class="brush:php;toolbar:false;">const bombCount = getNeighbors(rowIndex, colIndex, grid)
.filter(value => value === 2)
.length;
⚠️ 注意:务必确保 grid 是当前最新状态(如 React 中需在 useCallback 依赖项中包含 grid,避免闭包捕获旧值)。
? 进阶优化:极致性能版(仅限 8 邻域)
若仅需标准 8 邻域且追求极致性能(如高频调用场景),可使用硬编码偏移 + 可选链(?.)方案,零循环、O(1) 时间复杂度:
function get8Neighbors<t>(rowIndex: number, colIndex: number, grid: Array<t>[]): T[] {
return [
grid[rowIndex - 1]?.[colIndex - 1],
grid[rowIndex - 1]?.[colIndex],
grid[rowIndex - 1]?.[colIndex + 1],
grid[rowIndex]?.[colIndex - 1],
grid[rowIndex]?.[colIndex + 1],
grid[rowIndex + 1]?.[colIndex - 1],
grid[rowIndex + 1]?.[colIndex],
grid[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>
此版本利用 TypeScript 的可选链与非空断言,安全访问所有 8 个可能位置,并通过 filter 剔除 undefined,语义明确且性能最优。
✅ 总结与最佳实践
| 方案 | 适用场景 | 边界安全性 | 可读性 | 扩展性 |
|---|---|---|---|---|
| 通用 getNeighbors | 主流推荐,兼顾鲁棒与清晰 | ✅ 完美 | ✅ 高 | ✅ 支持任意 radius |
| 硬编码 get8Neighbors | 极致性能要求、固定 8 邻域 | ✅ 安全(依赖 ?.) | ⚠️ 中等(偏移需记忆) | ❌ 固化 |
无论选择哪种方案,请始终遵循:
- 在 React 等响应式环境中,确保 grid 状态被正确依赖;
- 单元测试覆盖边界用例(如 (0,0), (0,9), (9,0), (9,9));
- 避免在循环内直接修改 grid,保持函数纯度。
通过结构化抽象邻域逻辑,你将告别“边缘计数不准”的调试噩梦,让扫雷核心逻辑既可靠又优雅。










