讲师中心 微信公众号
AI工具推荐 视频效率加速

使用 JavaScript 构建扫雷游戏:一步步教程

酷婷大大_8181

酷婷大大_8181

发布时间:2025-08-23 17:16:01

|

947人浏览过

|

来源于php中文网

原创

使用 javascript 构建扫雷游戏:一步步教程

本文将指导你使用 JavaScript 构建一个简单的扫雷游戏。我们将从数据结构设计开始,逐步实现游戏初始化、渲染、用户交互、结束条件判断以及错误处理等关键功能。通过本教程,你将掌握使用 JavaScript 构建命令行界面 (CLI) 游戏的基本方法,并了解如何优化游戏性能。

1. 数据结构设计

首先,我们需要设计一个合适的数据结构来表示游戏状态。扫雷游戏的每个单元格可以有以下几种状态:

  • 是否是雷 (isMine): boolean 类型,表示该单元格是否包含地雷。
  • 状态 (state): 字符串类型,可以是 "unopened" (未打开), "opened" (已打开), 或 "flagged" (已标记)。

因此,每个单元格可以用一个对象来表示:

{
   isMine: boolean,
   state: "unopened" | "opened" | "flagged"
}

整个游戏状态可以用一个二维数组来表示,数组中的每个元素都是上述的单元格对象。

2. 初始化游戏状态

游戏初始化包括生成二维数组,并为每个单元格设置初始状态。所有单元格初始状态都为 "unopened",isMine 的值则根据随机算法确定。

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

const generateGrid = (gridSize) => {
  let grid = [];
  for (let i = 0; i < gridSize; i++) {
    grid.push([]);
    for (let j = 0; j < gridSize; j++) {
      grid[i][j] = {
        isMine: isMine(),
        state: "unopened"
      };
    }
  }
  return grid;
};

const isMine = () => Math.random() < 0.5; // 更简洁的随机布尔值生成方式

let grid = generateGrid(9); // 创建一个 9x9 的棋盘

注意: isMine() 函数使用 Math.random()

3. 渲染游戏状态

渲染函数将游戏状态的二维数组转换为人类可读的字符串,以便在控制台中显示。

const render = (grid) => {
  let output = "";
  for (let i = 0; i < grid.length; i++) {
    for (let j = 0; j < grid[i].length; j++) {
      const cell = grid[i][j];
      if (cell.state === "unopened") {
        output += ". "; // 未打开的单元格
      } else if (cell.state === "flagged") {
        output += "F "; // 已标记的单元格
      } else if (cell.isMine) {
        output += "* "; // 地雷
      } else {
        // TODO: 计算并显示周围地雷的数量
        output += "  "; // 已打开的单元格 (无雷)
      }
    }
    output += "\n"; // 换行
  }
  return output;
};

console.log(render(grid));

注意: render 函数需要根据单元格的状态来显示不同的字符。未打开的单元格可以用 "." 表示,已标记的单元格可以用 "F" 表示,地雷可以用 "*" 表示。对于已打开的单元格,你需要计算并显示其周围的地雷数量 (将在后续步骤中实现)。

4. 用户交互

用户可以执行以下两个操作:

AI舌诊面诊问诊医疗系统+诊疗商城系统源码
AI舌诊面诊问诊医疗系统+诊疗商城系统源码

AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。

下载
  • 打开单元格 (open): 改变单元格的状态为 "opened"。如果该单元格是地雷,则游戏结束。如果该单元格周围没有地雷,则需要递归地打开周围的单元格。
  • 标记单元格 (flag): 改变单元格的状态为 "flagged" 或 "unopened" (如果已经标记)。
const open = (grid, row, column) => {
  if (row < 0 || row >= grid.length || column < 0 || column >= grid[0].length) {
    return; // 越界检查
  }

  const cell = grid[row][column];

  if (cell.state !== "unopened") {
    return; // 已经打开或标记的单元格
  }

  cell.state = "opened";

  if (cell.isMine) {
    return "lose"; // 踩到地雷,游戏结束
  }

  // TODO: 如果周围没有地雷,递归打开周围的单元格
  return false;
};

const flag = (grid, row, column) => {
  if (row < 0 || row >= grid.length || column < 0 || column >= grid[0].length) {
    return; // 越界检查
  }
  const cell = grid[row][column];
  if (cell.state === "unopened") {
    cell.state = "flagged";
  } else if (cell.state === "flagged") {
    cell.state = "unopened";
  }
};

注意: open 函数需要进行越界检查,并判断单元格是否已经打开或标记。如果打开的单元格是地雷,则返回 "lose",表示游戏结束。如果周围没有地雷,则需要递归地打开周围的单元格 (这部分逻辑将在后续步骤中实现)。 flag 函数用于在 "unopened" 和 "flagged" 状态之间切换。

5. 结束条件判断

游戏结束的条件有两种:

  • 失败 (lose): 用户打开了一个包含地雷的单元格。
  • 胜利 (win): 用户打开了所有非地雷的单元格。
const checkEnd = (grid) => {
  let allNonMineCellsOpened = true;
  for (let i = 0; i < grid.length; i++) {
    for (let j = 0; j < grid[i].length; j++) {
      const cell = grid[i][j];
      if (!cell.isMine && cell.state !== "opened") {
        allNonMineCellsOpened = false;
        break;
      }
    }
    if (!allNonMineCellsOpened) {
      break;
    }
  }

  if (allNonMineCellsOpened) {
    return "win";
  }

  return false; // 游戏未结束
};

注意: checkEnd 函数需要遍历整个棋盘,判断是否所有非地雷的单元格都已打开。如果是,则返回 "win",表示游戏胜利。

6. 主函数

主函数将所有组件整合在一起,实现游戏循环。

const readline = require('readline').createInterface({
  input: process.stdin,
  output: process.stdout,
});

const main = async () => {
  // 提示用户输入棋盘大小
  let gridSize = 9; // 默认棋盘大小
  // generate grid
  let grid = generateGrid(gridSize);
  console.log(render(grid));
  let endState = false;
  while (!endState) {
    // 提示用户输入操作
    const action = await new Promise((resolve) => {
      readline.question(`Enter action (open/flag row column): `, input => {
        resolve(input);
      });
    });

    // 解析用户输入
    const [command, rowStr, columnStr] = action.split(" ");
    const row = parseInt(rowStr);
    const column = parseInt(columnStr);

    // 执行操作
    if (command === "open") {
      endState = open(grid, row, column);
      if (endState === "lose") {
        break; // 踩到雷,跳出循环
      }
    } else if (command === "flag") {
      flag(grid, row, column);
    }

    console.log(render(grid));
    endState = checkEnd(grid);
  }

  if (endState === "win") {
    console.log("You win!");
  } else {
    console.log("You lose!");
  }

  readline.close();
};

main();

注意: 主函数使用 readline 模块来获取用户输入。用户需要输入操作类型 (open/flag) 以及行和列的坐标。然后,主函数调用相应的函数来执行操作,并渲染游戏状态。循环直到游戏结束 (win/lose)。

7. 错误处理

在游戏开发过程中,需要考虑各种可能的错误情况,并进行处理。例如:

  • 用户输入无效的坐标 (超出范围)。
  • 用户尝试打开已经打开的单元格。
  • 用户输入无效的命令。

在 open 和 flag 函数中添加了越界检查。 可以在主函数中添加输入验证,确保用户输入的坐标是有效的数字。

8. 优化

  • 周围地雷计数: 实现一个函数,计算每个单元格周围的地雷数量,并在 render 函数中显示。
  • 递归打开: 在 open 函数中,如果打开的单元格周围没有地雷,则递归地打开周围的单元格。
  • 性能优化: 避免在 checkEnd 函数中进行 O(N^2) 的检查。可以使用额外的变量来跟踪游戏状态,并在 open 函数中更新这些变量。

9. 总结

通过本教程,你学习了如何使用 JavaScript 构建一个简单的扫雷游戏。 你了解了数据结构设计、游戏初始化、渲染、用户交互、结束条件判断以及错误处理等关键步骤。你还学习了如何优化游戏性能。 这个简单的CLI扫雷游戏为你提供了一个良好的起点,你可以继续扩展它的功能,例如添加图形界面、不同的难度级别等等。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

2150

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

163

2025.11.30

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1858

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

3004

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6284

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

6249

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

7814

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

11914

2024.04.29

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

0

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn