扫雷 Minesweeper
2026-08-10 15:07:13
发布于:江苏
HTML版的简易扫雷
左键翻开格子,右键标旗,左键 + 右键数字翻开它周围的方格
调整数值需更改第300行,格式为const game = new Minesweeper(行数, 列数, 雷数);
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minesweeper</title>
<style>
.container {
display: flex;
justify-content: center;
}
</style>
</head>
<body>
<div class="container ">
<canvas id="canvas" width="480" height="480"></canvas>
</div>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let mouseX = 0;
let mouseY = 0;
let isLeftDown = false;
let isRightDown = false;
let isLastLeftDown = false;
let isLastRightDown = false;
let isLastLeftRightDown = false;
canvas.addEventListener("mousedown", function (e) {
if (e.button === 0) {
isLeftDown = true;
}
if (e.button === 2) {
isRightDown = true;
}
});
canvas.addEventListener("mouseup", function (e) {
if (e.button === 0) {
isLeftDown = false;
}
if (e.button === 2) {
isRightDown = false;
}
});
canvas.addEventListener("mousemove", function (e) {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = (e.clientX - rect.left) * scaleX;
const y = (e.clientY - rect.top) * scaleY;
mouseX = Math.floor(x / 16);
mouseY = Math.floor(y / 16);
});
canvas.addEventListener("contextmenu", function (e) {
e.preventDefault();
});
</script>
<script>
class Minesweeper {
constructor(rows, cols, mines) {
canvas.height = rows * 16;
canvas.width = cols * 16;
this.rows = rows;
this.cols = cols;
this.mines = mines;
this.board = [];
this.gameOver = false;
this.gameWon = false;
this.firstClick = true;
this.preview = [];
this.init();
}
init() {
this.gameOver = false;
this.gameWon = false;
this.firstClick = true;
this.board = Array.from({ length: this.rows }, () => Array.from({ length: this.cols }, () => ({ content: 0, opened: false, flag: false })));
}
placeMines(firstRow, firstCol) {
let minesPlaced = 0;
while (minesPlaced < this.mines) {
const row = Math.floor(Math.random() * this.rows);
const col = Math.floor(Math.random() * this.cols);
if (Math.abs(row - firstRow) <= 1 && Math.abs(col - firstCol) <= 1) {
continue;
}
if (this.board[row][col].content !== 13) {
this.board[row][col].content = 13;
minesPlaced++;
}
}
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
if (this.board[i][j].content !== 13) {
this.board[i][j].content = this.countNeighborMines(i, j);
}
}
}
}
countNeighborMines(row, col) {
let count = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
const newRow = row + i;
const newCol = col + j;
if (newRow >= 0 && newRow < this.rows &&
newCol >= 0 && newCol < this.cols &&
this.board[newRow][newCol].content === 13) {
count++;
}
}
}
return count;
}
revealCell(row, col) {
if (this.gameOver || this.gameWon) return;
if (row < 0 || row >= this.rows || col < 0 || col >= this.cols) return;
const cell = this.board[row][col];
if (cell.opened || cell.flag) return;
if (this.firstClick) {
this.firstClick = false;
this.placeMines(row, col);
}
cell.opened = true;
if (cell.content === 13) {
this.gameOver = true;
this.revealAllMines();
this.board[row][col].content = 11;
} else {
if (cell.content === 0) {
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
this.revealCell(row + i, col + j);
}
}
}
this.checkWin();
}
}
toggleFlag(row, col) {
if (this.gameOver || this.gameWon) return;
const cell = this.board[row][col];
if (cell.opened) return;
cell.flag = !cell.flag;
}
revealAllMines() {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
if (this.board[i][j].content === 13 && !this.board[i][j].flag) {
this.board[i][j].opened = true;
}
if (this.board[i][j].content !== 13 && this.board[i][j].flag) {
this.board[i][j].content = 12;
this.board[i][j].opened = true;
this.board[i][j].flag = false;
}
}
}
}
checkWin() {
let allRevealed = true;
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
if (this.board[i][j].content !== 13 && !this.board[i][j].opened) {
allRevealed = false;
break;
}
}
}
if (allRevealed) {
this.gameWon = true;
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
if (this.board[i][j].content === 13) {
this.board[i][j].flag = true;
}
}
}
}
}
renderBoard() {
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
let frame;
if (!this.board[i][j].opened && !this.board[i][j].flag && this.preview.some(subArray => JSON.stringify(subArray) === JSON.stringify([i, j]))) {
frame = frames[0];
} else if (this.board[i][j].flag) {
frame = frames[10];
} else if (!this.board[i][j].opened) {
frame = frames[9];
} else {
frame = frames[this.board[i][j].content];
}
ctx.drawImage(sprite, frame.sx, frame.sy, frame.w, frame.h, j * 16, i * 16, frame.w, frame.h);
}
}
}
update() {
this.preview = [];
if (this.gameOver || this.gameWon) return;
if (!isLeftDown && isLastLeftDown && !isRightDown) {
this.revealCell(mouseY, mouseX);
}
if (isRightDown && !isLastRightDown && !isLeftDown) {
this.toggleFlag(mouseY, mouseX);
}
if (isLeftDown) {
this.preview = [[mouseY, mouseX]];
}
if (isLeftDown && isRightDown) {
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
this.preview.push([mouseY + i, mouseX + j]);
}
}
} else if (isLastLeftRightDown) {
let count = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
const newRow = mouseY + i;
const newCol = mouseX + j;
if (newRow >= 0 && newRow < this.rows &&
newCol >= 0 && newCol < this.cols &&
this.board[newRow][newCol].flag) {
count++;
}
}
}
if (count === this.board[mouseY][mouseX].content) {
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
this.revealCell(mouseY + i, mouseX + j);
}
}
}
}
isLastLeftDown = isLeftDown;
isLastRightDown = isRightDown;
isLastLeftRightDown = isLeftDown && isRightDown;
}
}
function gameLoop() {
game.update();
game.renderBoard();
requestAnimationFrame(gameLoop);
}
const sprite = new Image();
sprite.src = "data:image/png;base64,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";
const frames = [
{ sx: 0, sy: 23, w: 16, h: 16 },
{ sx: 16, sy: 23, w: 16, h: 16 },
{ sx: 32, sy: 23, w: 16, h: 16 },
{ sx: 48, sy: 23, w: 16, h: 16 },
{ sx: 64, sy: 23, w: 16, h: 16 },
{ sx: 80, sy: 23, w: 16, h: 16 },
{ sx: 96, sy: 23, w: 16, h: 16 },
{ sx: 112, sy: 23, w: 16, h: 16 },
{ sx: 128, sy: 23, w: 16, h: 16 },
{ sx: 0, sy: 39, w: 16, h: 16 },
{ sx: 16, sy: 39, w: 16, h: 16 },
{ sx: 32, sy: 39, w: 16, h: 16 },
{ sx: 48, sy: 39, w: 16, h: 16 },
{ sx: 64, sy: 39, w: 16, h: 16 }
];
const game = new Minesweeper(16, 16, 40);
gameLoop();
</script>
</body>
</html>
这里空空如也













有帮助,赞一个