Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
JavaScript扫雷游戏开发:精确处理边界单元格的算法与优化_创想鸟

JavaScript扫雷游戏开发:精确处理边界单元格的算法与优化

JavaScript扫雷游戏开发:精确处理边界单元格的算法与优化

本文旨在解决在JavaScript扫雷游戏开发中,单元格状态判断(如邻近炸弹的“绿色”或“蓝色”单元格)在网格边界处出现错误的问题。核心在于利用模运算精确判断单元格是否位于网格的左右边界,从而避免跨越边界进行错误的邻近单元格计算。文章将详细阐述如何通过边界条件检查优化算法,并提供示例代码,以确保游戏逻辑的准确性与鲁棒性。

在开发基于网格的游戏,特别是像扫雷这样的项目时,一个常见的挑战是正确处理网格的边界条件。当计算一个单元格的邻居时,如果简单地通过索引加减来确定,当单元格位于网格边缘时,这些操作可能会导致索引超出边界,甚至“环绕”到网格的另一侧,从而产生错误的邻居判断。本教程将详细探讨如何通过引入边界检查逻辑,精确地确定单元格的邻居,并应用于扫雷游戏的“绿色”和“蓝色”单元格标记。

1. 问题背景:边界效应的产生

在扫雷游戏中,我们需要根据炸弹的位置来标记其周围的单元格。例如,紧邻炸弹的单元格可能被标记为“绿色”,而距离炸弹稍远的单元格可能被标记为“蓝色”。通常,我们会通过计算当前单元格索引的x+1(右邻)、x-1(左邻)、x+gridLength(下邻)、x-gridLength(上邻)以及对应的对角线邻居来判断。

然而,这种简单的加减法在遇到网格边界时会失效。例如,在一个10×10的网格中,如果单元格50(右边界)的右邻是51,但实际上51是下一行的第一个单元格,这就会导致逻辑错误。同样,单元格51的左邻是50,但如果它位于左边界,其左邻应该是上一行的最后一个单元格,而不是当前行的前一个单元格。

// 原始的错误判断逻辑示例// 假设cellNumb从1开始计数,gridLength为网格边长if (bombsArray.includes(cellNumb - 1) // 左侧    || bombsArray.includes(cellNumb + 1) // 右侧    || bombsArray.includes(cellNumb - gridLength) // 上方    || bombsArray.includes(cellNumb + gridLength) // 下方    || bombsArray.includes(cellNumb - gridLength - 1) // 左上    || bombsArray.includes(cellNumb - gridLength + 1) // 右上    || bombsArray.includes(cellNumb + gridLength - 1) // 左下    || bombsArray.includes(cellNumb + gridLength + 1) // 右下) {    singleCell.classList.add('green');}

上述代码没有考虑边界,当cellNumb在左边界时,cellNumb – 1会指向上一行的末尾;当cellNumb在右边界时,cellNumb + 1会指向下一行的开头。对角线邻居的计算也存在类似问题。

2. 解决方案:引入模运算进行边界判断

解决边界效应的关键在于使用模运算(%)来确定单元格是否位于特定边界。由于本案例中的单元格编号从1开始(而不是0),我们需要对模运算的逻辑进行相应调整。

立即学习“Java免费学习笔记(深入)”;

假设gridLength是网格的边长,cellNumb是当前单元格的编号(1-indexed)。

判断是否在右边界: 如果一个单元格编号能被gridLength整除,则它位于该行的最右侧。const atRightSide = cellNumb % gridLength === 0;判断是否在左边界: 如果一个单元格编号除以gridLength的余数为1,则它位于该行的最左侧。const atLeftSide = cellNumb % gridLength === 1;

有了这两个布尔变量,我们就可以在判断邻居时,排除那些会跨越边界的非法操作。

2.1 标记“绿色”单元格(直接邻居)

“绿色”单元格是与炸弹直接相邻的单元格(上下左右及对角线)。在判断这些邻居时,我们需要确保操作不会跨越左右边界。

// 获取网格边长和当前单元格编号let gridLength = Math.sqrt(numbOfCells);const cellNumb = Number(singleCell.textContent);// 判断当前单元格是否位于左右边界(1-indexed)const atRightSide = cellNumb % gridLength === 0;const atLeftSide = cellNumb % gridLength === 1;// 检查当前单元格是否为炸弹if (bombsArray.includes(cellNumb)) {    singleCell.classList.add('bomb');}// 检查是否为绿色单元格else if (    // 左侧邻居:如果不在左边界,则检查 cellNumb - 1    (!atLeftSide && bombsArray.includes(cellNumb - 1)) ||    // 右侧邻居:如果不在右边界,则检查 cellNumb + 1    (!atRightSide && bombsArray.includes(cellNumb + 1)) ||    // 上方邻居:始终可以检查    bombsArray.includes(cellNumb - gridLength) ||    // 下方邻居:始终可以检查    bombsArray.includes(cellNumb + gridLength) ||    // 左上对角线邻居:如果不在左边界,则检查 cellNumb - gridLength - 1    (!atLeftSide && bombsArray.includes(cellNumb - gridLength - 1)) ||    // 右上对角线邻居:如果不在右边界,则检查 cellNumb - gridLength + 1    (!atRightSide && bombsArray.includes(cellNumb - gridLength + 1)) ||    // 左下对角线邻居:如果不在左边界,则检查 cellNumb + gridLength - 1    (!atLeftSide && bombsArray.includes(cellNumb + gridLength - 1)) ||    // 右下对角线邻居:如果不在右边界,则检查 cellNumb + gridLength + 1    (!atRightSide && bombsArray.includes(cellNumb + gridLength + 1))) {    singleCell.classList.add('green');    singleCell.addEventListener('click', function () {        addGreenPoints();    });}

通过在每个可能跨越左右边界的判断前加上!atLeftSide或!atRightSide条件,我们确保了只有在有效范围内才进行邻居检查。

2.2 标记“蓝色”单元格(二级邻居)

“蓝色”单元格代表距离炸弹更远的区域,通常是距离炸弹两格的单元格。这需要更复杂的边界判断,因为涉及的偏移量更大。

首先,我们需要定义二级边界条件:

判断是否在右侧两列内:const twoRightSide = cellNumb % gridLength === 0 || (cellNumb + 1) % gridLength === 0;这意味着当前单元格在最右列,或者其右侧的单元格在最右列(即当前单元格在倒数第二列)。判断是否在左侧两列内:const twoLeftSide = cellNumb % gridLength === 1 || cellNumb % gridLength === 2;这意味着当前单元格在最左列,或者其右侧的单元格在最左列(即当前单元格在第二列)。

然后,将这些条件应用到“蓝色”单元格的判断逻辑中。由于“蓝色”单元格的判断涉及更多的偏移量(例如cellNumb – 2、cellNumb + 2、cellNumb – (gridLength * 2)等),每个涉及到左右移动的条件都需要相应的!twoLeftSide或!twoRightSide检查。

// ... (之前的atRightSide, atLeftSide, twoRightSide, twoLeftSide 定义)// ... (炸弹和绿色单元格的判断)// 检查是否为蓝色单元格else if (    // 左侧二级邻居:如果不在左侧两列内,则检查 cellNumb - 2    (!twoLeftSide && bombsArray.includes(cellNumb - 2)) ||    // 右侧二级邻居:如果不在右侧两列内,则检查 cellNumb + 2    (!twoRightSide && bombsArray.includes(cellNumb + 2)) ||    // 上方二级邻居:始终可以检查    bombsArray.includes(cellNumb - (gridLength * 2)) ||    // 下方二级邻居:始终可以检查    bombsArray.includes(cellNumb + (gridLength * 2)) ||    // ↖↖ 左上左二级对角线:如果不在左侧两列内,则检查 cellNumb - (gridLength * 2) - 2    (!twoLeftSide && bombsArray.includes(cellNumb - (gridLength * 2) - 2)) ||    // ↖ 左上对角线:如果不在左边界,则检查 cellNumb - (gridLength * 2) - 1    (!atLeftSide && bombsArray.includes(cellNumb - (gridLength * 2) - 1)) ||    // ↗ 右上对角线:如果不在右边界,则检查 cellNumb - (gridLength * 2) + 1    (!atRightSide && bombsArray.includes(cellNumb - (gridLength * 2) + 1)) ||    // ↗↗ 右上右二级对角线:如果不在右侧两列内,则检查 cellNumb - (gridLength * 2) + 2    (!twoRightSide && bombsArray.includes(cellNumb - (gridLength * 2) + 2)) ||    // ➡ 右侧一级对角线(水平偏移2):如果不在右侧两列内,则检查 cellNumb - gridLength + 2    (!twoRightSide && bombsArray.includes(cellNumb - gridLength + 2)) ||    // ⬅ 左侧一级对角线(水平偏移2):如果不在左侧两列内,则检查 cellNumb - gridLength - 2    (!twoLeftSide && bombsArray.includes(cellNumb - gridLength - 2)) ||    // ↘ 右下二级对角线(水平偏移2):如果不在右侧两列内,则检查 cellNumb + gridLength + 2    (!twoRightSide && bombsArray.includes(cellNumb + gridLength + 2)) ||    // ↙ 左下二级对角线(水平偏移2):如果不在左侧两列内,则检查 cellNumb + gridLength - 2    (!twoLeftSide && bombsArray.includes(cellNumb + gridLength - 2)) ||    // ↘↘ 右下右二级对角线:如果不在右侧两列内,则检查 cellNumb + (gridLength * 2) + 2    (!twoRightSide && bombsArray.includes(cellNumb + (gridLength * 2) + 2)) ||    // ↙ 左下对角线:如果不在左边界,则检查 cellNumb + (gridLength * 2) - 1    (!atLeftSide && bombsArray.includes(cellNumb + (gridLength * 2) - 1)) ||    // ↗ 右下对角线:如果不在右边界,则检查 cellNumb + (gridLength * 2) + 1    (!atRightSide && bombsArray.includes(cellNumb + (gridLength * 2) + 1)) ||    // ↙↙ 左下左二级对角线:如果不在左侧两列内,则检查 cellNumb + (gridLength * 2) - 2    (!twoLeftSide && bombsArray.includes(cellNumb + (gridLength * 2) - 2))) {    singleCell.classList.add('blue');    singleCell.addEventListener('click', function () {        addBluePoints();    });}

请注意,对于垂直方向(gridLength的倍数)的偏移,不需要额外的左右边界检查,因为它们只影响行,不影响列的环绕问题。然而,对于结合了垂直和水平偏移的对角线情况,则需要根据水平偏移的距离应用atLeftSide/atRightSide或twoLeftSide/twoRightSide。

3. 注意事项与优化建议

拼写规范: 在代码中,gridLenght应更正为gridLength,保持变量命名的一致性和准确性。

数据结构优化: bombsArray(炸弹位置数组)在每次判断单元格时都会使用includes()方法进行查找。对于大型网格,includes()的性能是O(n),效率较低。建议将bombsArray转换为Set数据结构。Set.has()方法的平均时间复杂度是O(1),这将显著提高查找效率。

// 初始化时const bombsSet = new Set(bombsArray);// 检查时if (bombsSet.has(cellNumb)) { /* ... */ }else if (bombsSet.has(cellNumb - 1) || /* ... */ ) { /* ... */ }

0-indexed vs. 1-indexed: 本教程的边界判断逻辑是基于单元格编号从1开始的情况。如果你的网格单元格编号从0开始,那么边界判断的模运算会有所不同:

右边界:cellNumb % gridLength === gridLength – 1;左边界:cellNumb % gridLength === 0;请务必根据你的实际编号方式进行调整。

4. 总结

通过在扫雷游戏单元格状态判断中引入精确的边界条件检查,我们可以有效避免因索引越界或环绕导致的逻辑错误。利用模运算判断单元格的左右边界位置,并将其整合到邻居判断逻辑中,是构建鲁棒性网格游戏的关键一步。同时,结合代码规范和数据结构优化,可以进一步提升代码质量和游戏性能。

以上就是JavaScript扫雷游戏开发:精确处理边界单元格的算法与优化的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1509059.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
JavaScript的debugger语句是什么?如何调试代码?
上一篇 2025年12月20日 05:14:53
JavaScript扫雷游戏:边界单元格逻辑处理与优化指南
下一篇 2025年12月20日 05:15:02

相关推荐

  • 绘蛙AI修图怎样优化旅游照片?旅行社合作方案

    绘蛙ai修图的核心优势在于智能识别与校正,能自动调整白平衡、曝光和色彩饱和度,解决光线不佳或色彩偏差问题;2. 提供一键美化与风格化处理,内置“电影感”“清新自然”等风格,综合调整光影、对比度与锐度,提升照片视觉质感;3. 具备细节增强与瑕疵修复能力,可智能去除背景杂物、降噪、锐化,并自然修复人像瑕…

    2026年9月23日
    000
  • laravel怎么进行数据库迁移(migrate)

    laravel是一种免费开源的php web应用程序框架,它采用了model-view-controller(mvc)设计模式,并提供了许多内置功能,使开发web应用程序变得更加容易。其中,laravel migrate是一种用于数据库迁移的工具,它提供了一种简单的方法,用于通过命令行来管理数据库表…

    用户投稿 2026年9月23日
    000
  • 谷歌浏览器如何将网页添加到阅读清单_谷歌浏览器添加网页到阅读清单方法

    谷歌浏览器支持通过地址栏按钮、右键菜单、主菜单和快捷键四种方式将网页添加到阅读清单。1、点击地址栏右侧“添加到阅读清单”图标即可保存;2、在页面空白处右键选择“添加页面到阅读清单”;3、通过三点菜单进入书签子菜单选择“添加到阅读清单”;4、使用Command+Shift+D(Mac)或Ctrl+Sh…

    2026年9月23日
    000
  • 小红书店铺怎么同步淘宝商品?小红书店铺商品合集怎么弄

    随着电商行业的不断发展,小红书与淘宝作为国内热门的电商平台,吸引了大量用户。如何将小红书店铺中的商品与淘宝实现同步,成为众多商家关注的问题。本文将详细讲解小红书与淘宝商品同步的操作方法,帮助商家提升运营效率。 一、小红书与淘宝商品同步的优势 1.流量互导:通过同步商品,可以借助两个平台的用户基础,吸…

    2026年9月23日
    000
  • 【Linux】初识线程

    【Linux】初识线程【Linux】初识线程【Linux】初识线程【Linux】初识线程

    一、线程的概念 线程是操作系统能够进行运算调度的基本单位,它被包含在进程之中,是进程中的实际运作单位。 定义与基本特征 轻量级实体:线程是比进程更小的可独立运行的基本单位,也被称为轻量级进程。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等,但每个线程都有自己独立的程序计数…

    2026年9月23日 • 用户投稿
    000
  • vscode如何自定义状态栏 vscode底部栏的调整方法

    vscode如何自定义状态栏 vscode底部栏的调整方法vscode如何自定义状态栏 vscode底部栏的调整方法vscode如何自定义状态栏 vscode底部栏的调整方法vscode如何自定义状态栏 vscode底部栏的调整方法

    要自定义vs code状态栏,可从显示内容、顺序及颜色等方面入手。1. 调整显示内容:通过设置界面或编辑settings.json文件,控制特定元素如git信息的显示与隐藏;2. 添加自定义指示器:安装扩展并按文档配置,在状态栏展示构建状态等个性化信息;3. 自定义颜色:在settings.json…

    2026年9月23日 • 用户投稿
    000
  • 智界R7用户调研报告出炉:年均收入36.5万 平均32.4岁

    智界R7用户调研报告出炉:年均收入36.5万 平均32.4岁智界R7用户调研报告出炉:年均收入36.5万 平均32.4岁智界R7用户调研报告出炉:年均收入36.5万 平均32.4岁智界R7用户调研报告出炉:年均收入36.5万 平均32.4岁

    8月4日,一份关于智界r7的用户调研报告正式发布。数据显示,在2024年12月至2025年6月期间开展的两轮调研中,该车型车主的平均年龄由30.6岁上升至32.4岁,家庭年均收入达到36.5万元,显著高于行业平均水平。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepS…

    2026年9月23日 • 用户投稿
    100
  • 图片库空间不足怎么办_图片库空间不足如何压缩图片详细步骤

    压缩图片可有效节省空间,推荐使用TinyPNG等在线工具批量处理,或用Photoshop、XnConvert进行精准控制,手机用户可通过专用App或快捷指令一键压缩,配合云存储与格式转换更高效。 图片库空间不足时,压缩图片是节省空间最直接有效的方法。不需要删除照片,通过合理压缩,既能保留视觉质量,又…

    2026年9月23日
    100
  • 《空洞骑士:丝之歌》评价吓到外媒编辑:害怕太难不敢开坑

    外媒TheGamer近日发表文章指出,《空洞骑士:丝之歌》在上周正式发售后,因其极高的难度在玩家社区中引发广泛讨论,不少玩家直言“相比前作显得更加不友好”。文中作者坦承,自己至今仍未完成初代《空洞骑士》,而面对《丝之歌》当前的风评,更是感到畏惧,迟迟不敢入手。 据玩家反馈,本作几乎所有的Boss以及…

    2026年9月23日
    000
  • Win10系统如何删除用户配置文件?

    Win10系统如何删除用户配置文件?Win10系统如何删除用户配置文件?Win10系统如何删除用户配置文件?Win10系统如何删除用户配置文件?

    win10电脑在运行时,许多用户会选择创建个人账户,每个账户都会保存一些配置数据,这类数据可能会占用较多的系统资源。当账户数量增多时,可能会导致系统运行变慢,因此可以考虑移除不常使用的用户配置文件。下面将详细介绍如何在win10中删除用户配置文件。 具体步骤如下: 1、双击桌面上的“此电脑”图标。 …

    2026年9月23日 • 用户投稿
    100
  • 苹果手机官网查询门户 苹果查询官网手机入口

    苹果查询官网手机入口是https://www.apple.com.cn,用户可通过该网站查询设备信息、技术支持及配件服务,包括序列号验证、保修状态、维修预约和原厂配件真伪核验等功能。 苹果手机官网查询门户在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来苹果查询官网手机入口,感兴趣的网友一起…

    2026年9月23日
    000
  • 支持多种CPU调整外频!微星B850MPOWER主板图赏

    支持多种CPU调整外频!微星B850MPOWER主板图赏支持多种CPU调整外频!微星B850MPOWER主板图赏支持多种CPU调整外频!微星B850MPOWER主板图赏支持多种CPU调整外频!微星B850MPOWER主板图赏

    10月9日最新消息,微星b850m power主板已正式上市,定价为1599元,首发时迅速售罄,目前仍处于供不应求状态,需参与抢购才能入手。 这款热门新品现已抵达我们评测室,接下来为大家带来详细的图赏内容。 微星B850M POWER主板采用高端的8层服务器级PCB设计,配备双8PIN供电接口,并使…

    2026年9月23日 • 用户投稿
    000
  • Linux系统-单用户模式

    Linux系统-单用户模式Linux系统-单用户模式Linux系统-单用户模式Linux系统-单用户模式

    作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 这是Linux进阶部分的最后一大章。讲完这一章以后,我们Linux进阶部分讲完以后,我们的Linux操作部分就算讲完了,后面的讲解就主要是Linux上的应用软件的…

    2026年9月23日 • 用户投稿
    000
  • iphone15promax怎么清理缓存?

    如何清理iPhone 15 Pro Max的缓存? 1、进入手机设置界面,选择【通用】选项。 2、点击进入【iPhone储存空间】。 3、在列表中查看各个应用所占用的存储情况,找到占用较大的应用后,逐个进入应用进行缓存清理。 关闭iCloud云盘的操作步骤: 1、在设置界面中点击顶部的【Apple …

    2026年9月23日
    000
  • Django运行migrate报错“django.db.utils.OperationalError”:如何解决SSL连接错误?

    django运行migrate报错“django.db.utils.operationalerror”的解决方法 在使用django项目的过程中,有时候在命令行中运行“python manage.py migrate”命令时会遇到“django.db.utils.operationalerror”的…

    2026年9月23日
    000
  • LINUX下如何安装输入法_LINUX安装中文输入法(搜狗/Fcitx)教程

    首先安装Fcitx输入法框架并切换默认输入法为Fcitx,接着添加中文语言支持并配置区域选项,然后下载并安装搜狗输入法Linux版,再通过启动应用程序设置Fcitx随系统自启,最后重启会话并在Fcitx配置中添加搜狗拼音输入法。 如果您在使用Linux系统时需要输入中文,但默认环境下缺少可用的中文输…

    2026年9月23日
    200
  • Deepseek 满血版联动 Typinator Pro,创建复杂文本模板​

    Deepseek 满血版联动 Typinator Pro,创建复杂文本模板​Deepseek 满血版联动 Typinator Pro,创建复杂文本模板​Deepseek 满血版联动 Typinator Pro,创建复杂文本模板​Deepseek 满血版联动 Typinator Pro,创建复杂文本模板​

    将 ai 与 typinator 联动可打造高效文本模板系统。1. 使用 deepseek 等 ai 工具生成结构化内容,如邮件草稿;2. 将生成内容调整为 typinator 变量格式(如 %|name%);3. 导入 typinator 并设置快捷短语,实现一键插入。典型场景包括批量写邮件、报告…

    2026年9月23日 • 用户投稿
    000
  • 总结laravel中JSON格式的转换方法

    laravel 是一款流行的 php web 开发框架,它提供了很多开箱即用的功能,包括对 json 数据的支持。本文将介绍如何在 laravel 中转换 json。 JSON 简介 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于 JavaScri…

    用户投稿 2026年9月23日
    100
  • Vscode怎么批量修改变量?Vscode变量重命名操作指南

    Vscode怎么批量修改变量?Vscode变量重命名操作指南Vscode怎么批量修改变量?Vscode变量重命名操作指南Vscode怎么批量修改变量?Vscode变量重命名操作指南Vscode怎么批量修改变量?Vscode变量重命名操作指南

    vscode批量修改变量的方法是选中变量按f2输入新名回车,但要更精确控制重命名范围可采取以下措施:1.使用“查找和替换”功能(ctrl+h),结合正则表达式限定匹配范围;2.使用语言支持的“重构”功能(右键→重构→重命名),基于语义分析避免误改;3.安装增强重命名插件提升功能;4.利用静态代码分析…

    2026年9月23日 • 用户投稿
    000
  • Java中用户输入验证:正确使用equals()或转换为整数进行比较

    本教程详细阐述了Java中用户输入字符串(如菜单选项)验证的正确方法。针对==运算符在字符串比较中的局限性,文章介绍了两种解决方案:一是使用String.equals()方法进行内容比较,二是将字符串输入解析为整数后进行数值比较。通过代码示例,帮助开发者避免常见的字符串比较错误,确保程序逻辑的健壮性…

    2026年9月23日
    000

发表回复

登录后才能评论
关注微信