该游戏通过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中进行修改补充。