扫雷小游戏 JS与react实现

该游戏通过JavaScript与React实现。

1.打开VSCode终端,输入:

npx create-react-app .

2.将 src/App.js 中的代码替换成如下代码

import React, { useState, useEffect } from 'react';
import './App.css';

//十行 十列 十枚炸弹
const ROWS = 10;
const COLS = 10;
const MINES = 10;

function App() {
  //Hooks放在最顶层,用来定义和修改状态
  const [grid, setGrid] = useState([]);
  const [gameOver, setGameOver] = useState(false);
  const [win, setWin] = useState(false);

  useEffect(() => {
    // 初始化网格
    const newGrid = [];
    for (let row = 0; row < ROWS; row++) {
      const newRow = [];
      for (let col = 0; col < COLS; col++) {
        newRow.push({
          x: row,
          y: col,
          isMine: false,//是否有地雷
          neighborCount: 0,//周围地雷的数量
          isRevealed: false,//是否被翻开
          isFlagged: false,//是否插旗
        });
      }
      newGrid.push(newRow);
    }

    // 随机放置地雷
    let minesPlaced = 0;
    while (minesPlaced < MINES) {
      const randomRow = Math.floor(Math.random() * ROWS);
      const randomCol = Math.floor(Math.random() * COLS);
      if (!newGrid[randomRow][randomCol].isMine) {
        newGrid[randomRow][randomCol].isMine = true;
        minesPlaced++;
      }
    }

    // 取每个方块周围地雷的数量
    for (let row = 0; row < ROWS; row++) {
      for (let col = 0; col < COLS; col++) {
        if (!newGrid[row][col].isMine) {
          let count = 0;
          /*[-1,-1],[-1,0],[-1,1]
            [0,-1],        [0,1]
            [1,-1],[1,0],[1,1]*/
          for (let i = -1; i <= 1; i++) {
            for (let j = -1; j <= 1; j++) {
              const neighborRow = row + i;
              const neighborCol = col + j;
              if (neighborRow >= 0 &&neighborRow < ROWS &&neighborCol >= 0 &&neighborCol < COLS && newGrid[neighborRow][neighborCol].isMine) {
                count++;
              }
            }
          }
          newGrid[row][col].neighborCount = count;
        }
      }
    }

    setGrid(newGrid);
  }, []);


  //翻牌
  function revealCell(cell) {
    if (gameOver || cell.isFlagged || cell.isRevealed) return;

    const newGrid = [...grid];
    //当失败时,显示点击处方块的地雷
    if (cell.isMine) {
      setGameOver(true);
      const newGrid = [...grid];
      newGrid[cell.x][cell.y].isRevealed = true;
      setGrid(newGrid);
    } 
    else {
      newGrid[cell.x][cell.y].isRevealed = true;
      if (newGrid[cell.x][cell.y].neighborCount === 0) {
        // 如果该方块周围没有地雷,则递归展开周围的方块
        for (let i = -1; i <= 1; i++) {
          for (let j = -1; j <= 1; j++) {
            const neighborRow = cell.x + i;
            const neighborCol = cell.y + j;
            if (neighborRow >= 0 && neighborRow < ROWS && neighborCol >= 0 && neighborCol < COLS) {
              revealCell(newGrid[neighborRow][neighborCol]);
            }
          }
        }
      }
    }
    setGrid(newGrid);
    checkWin();
  }
  
  //设旗
  function flagCell(e, cell) {   
    if (gameOver || cell.isRevealed) return;
    const newGrid = [...grid];
    newGrid[cell.x][cell.y].isFlagged = !newGrid[cell.x][cell.y].isFlagged;
    setGrid(newGrid);
  }

  //检查是否成功
  function checkWin() {
    let win = true;
    for (let row = 0; row < ROWS; row++) {
      for (let col = 0; col < COLS; col++) {
        if (!grid[row][col].isRevealed && !grid[row][col].isMine) {
          win = false;
        }
      }
    }
    if (win) {
      setGameOver(true);
      setWin(true);
    }
  }

  //重新开始游戏,再来一局
  function restartGame() {
    setGameOver(false);
    setWin(false);
    const newGrid = [];
    for (let row = 0; row < ROWS; row++) {
      const newRow = [];
      for (let col = 0; col < COLS; col++) {
        newRow.push({
          x: row,
          y: col,
          isMine: false,
          neighborCount: 0,
          isRevealed: false,
          isFlagged: false,
        });
      }
      newGrid.push(newRow);
    }

    let minesPlaced = 0;
    while (minesPlaced < MINES) {
      const randomRow = Math.floor(Math.random() * ROWS);
      const randomCol = Math.floor(Math.random() * COLS);
      if (!newGrid[randomRow][randomCol].isMine) {
        newGrid[randomRow][randomCol].isMine = true;
        minesPlaced++;
      }
    }

    for (let row = 0; row < ROWS; row++) {
      for (let col = 0; col < COLS; col++) {
        if (!newGrid[row][col].isMine) {
          let count = 0;
          /*[-1,-1],[-1,0],[-1,1]
            [0,-1],        [0,1]
            [1,-1],[1,0],[1,1]*/
          for (let i = -1; i <= 1; i++) {
            for (let j = -1; j <= 1; j++) {
              const neighborRow = row + i;
              const neighborCol = col + j;
              if (neighborRow >= 0 &&neighborRow < ROWS &&neighborCol >= 0 &&neighborCol < COLS && newGrid[neighborRow][neighborCol].isMine) {
                count++;
              }
            }
          }
          newGrid[row][col].neighborCount = count;
        }
      }
    }
    setGrid(newGrid);
  }  

  return (
    <div className = "App">

      <h1>扫雷游戏</h1 > 
       
      <button onClick = {restartGame}>重新开始</button> 

      <div className = "grid-container">
        {grid.map((row, rowIndex) =>
          row.map((cell, colIndex) => (
            <div
              key = {`${rowIndex}-${colIndex}`}
              className = {`cell ${cell.isRevealed ? 'revealed' : ''}`}
              onClick = {() => revealCell(cell)}
              onContextMenu = {(e) => flagCell(e, cell)}
            >
              {cell.isRevealed && !cell.isMine ? (
                // 如果该方块被揭露且不是地雷,则显示周围地雷的数量
                cell.neighborCount !== 0 ? (
                  cell.neighborCount
                ) : (
                  ''
                )
              ) : cell.isFlagged ? (
                // 如果该方块被标记为地雷,则显示一个旗帜
                <span role = "img" aria-label = "flag">
                  🚩
                </span>
              ) : (
                ''
              )}
              {cell.isRevealed && cell.isMine ? (
                // 如果该方块被揭露且是地雷,则显示一个炸弹
                <span role = "img" aria-label = "mine">
                  💣
                </span>
              ) : (
                ''
              )}
            </div>
          ))
        )}
      </div>
      {gameOver && (
        <div className = "result" > {win ? '胜利' : '失败'}</div>
      )}
    </div>
  );
}

export default App;

3.将 src/App.css 中的代码替换成如下代码

.App {
  text-align: center;
}

.grid-container {
  margin: 30px auto;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(10, 1fr);
  grid-gap: 5px;
  width: 500px;
  height: 500px;
}

.cell {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 30px;
  font-weight: bold;
  cursor: pointer;
  background-color: #b5d1c3;
}

.cell.revealed {
  background-color: #d8d8d8;
}

.result {
  margin-top: 20px;
  font-size: 30px;
  font-weight: bold;
}

4.运行,在终端输入:

npm start

或:在浏览器中输入http://localhost:3000/来打开

5.效果图:

6.该游戏仅实现扫雷部分功能,若需升级功能:设置难度,渲染图标等可自行在js和css中进行修改补充。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值