简介
扫雷是经典的单人逻辑游戏,玩家需要根据数字提示推断地雷位置并安全翻开所有非雷格子。游戏厅版本支持三级难度、标旗/翻开两种模式切换,以及胜率统计功能。
数据结构
棋盘生成
使用二维数组存储每个格子的状态:
1var board = []; // board[row][col] = { mine: bool, number: int, revealed: bool, flagged: bool }
2var rows, cols, totalMines;
3
4function initBoard() {
5 board = [];
6 for (var r = 0; r < rows; r++) {
7 board[r] = [];
8 for (var c = 0; c < cols; c++) {
9 board[r][c] = { mine: false, number: 0, revealed: false, flagged: false };
10 }
11 }
12}
难度配置
| 难度 | 行数 | 列数 | 雷数 |
|---|---|---|---|
| 简单 | 9 | 9 | 10 |
| 中等 | 16 | 16 | 40 |
| 困难 | 16 | 30 | 99 |
1var difficulties = {
2 easy: { rows: 9, cols: 9, mines: 10 },
3 medium: { rows: 16, cols: 16, mines: 40 },
4 hard: { rows: 16, cols: 30, mines: 99 }
5};
核心算法
随机布雷
在玩家首次点击后布雷,确保首次点击和周围 8 格不是雷:
1function placeMines(safeRow, safeCol) {
2 var safeZone = [];
3 for (var dr = -1; dr <= 1; dr++)
4 for (var dc = -1; dc <= 1; dc++) {
5 var r = safeRow + dr, c = safeCol + dc;
6 if (r >= 0 && r < rows && c >= 0 && c < cols) safeZone.push([r, c]);
7 }
8
9 var placed = 0;
10 while (placed < totalMines) {
11 var r = Math.floor(Math.random() * rows);
12 var c = Math.floor(Math.random() * cols);
13 if (board[r][c].mine) continue;
14 // 跳过安全区
15 if (safeZone.some(function(s) { return s[0] === r && s[1] === c; })) continue;
16 board[r][c].mine = true;
17 placed++;
18 }
19 calculateNumbers();
20}
数字计算
遍历每个格子,统计周围 8 格的雷数:
1function calculateNumbers() {
2 for (var r = 0; r < rows; r++)
3 for (var c = 0; c < cols; c++) {
4 if (board[r][c].mine) continue;
5 var count = 0;
6 for (var dr = -1; dr <= 1; dr++)
7 for (var dc = -1; dc <= 1; dc++) {
8 if (dr === 0 && dc === 0) continue;
9 var nr = r + dr, nc = c + dc;
10 if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc].mine) count++;
11 }
12 board[r][c].number = count;
13 }
14}
BFS 区域展开
点击数字为 0 的格子时,自动展开周围所有安全区域。使用广度优先搜索(BFS):
1function revealCell(row, col) {
2 if (board[row][col].revealed || board[row][col].flagged) return;
3 board[row][col].revealed = true;
4
5 if (board[row][col].mine) {
6 gameOver(false);
7 return;
8 }
9
10 if (board[row][col].number === 0) {
11 var queue = [[row, col]];
12 var visited = {};
13 visited[row + ',' + col] = true;
14
15 while (queue.length > 0) {
16 var cur = queue.shift();
17 for (var dr = -1; dr <= 1; dr++)
18 for (var dc = -1; dc <= 1; dc++) {
19 var nr = cur[0] + dr, nc = cur[1] + dc;
20 if (nr < 0 || nr >= rows || nc < 0 || nc >= cols) continue;
21 if (visited[nr + ',' + nc]) continue;
22 visited[nr + ',' + nc] = true;
23 if (board[nr][nc].mine || board[nr][nc].flagged) continue;
24 board[nr][nc].revealed = true;
25 if (board[nr][nc].number === 0) queue.push([nr, nc]);
26 }
27 }
28 }
29 checkWin();
30}
胜利判定
所有非雷格子都被翻开即为胜利:
1function checkWin() {
2 for (var r = 0; r < rows; r++)
3 for (var c = 0; c < cols; c++)
4 if (!board[r][c].mine && !board[r][c].revealed) return false;
5 return true;
6}
交互设计
标旗/翻开模式切换
提供两种操作模式的按钮切换:
- 翻开模式:左键点击翻开格子
- 标旗模式:左键点击插旗/取消旗子
1var mode = 'reveal'; // 'reveal' | 'flag'
2
3function toggleMode() {
4 mode = mode === 'reveal' ? 'flag' : 'reveal';
5 updateModeButton();
6}
右键标旗
右键点击始终执行标旗/取消操作,不受模式影响:
1cell.addEventListener('contextmenu', function(e) {
2 e.preventDefault();
3 toggleFlag(row, col);
4});
双击快速展开
在已翻开的数字格子上双击,如果周围旗子数等于数字,自动翻开周围未标记的格子:
1function chordReveal(row, col) {
2 if (!board[row][col].revealed || board[row][col].number === 0) return;
3 var flagCount = countFlagsAround(row, col);
4 if (flagCount !== board[row][col].number) return;
5 for (var dr = -1; dr <= 1; dr++)
6 for (var dc = -1; dc <= 1; dc++)
7 revealCell(row + dr, col + dc);
8}
胜率统计
使用 localStorage 记录游戏次数和胜利次数:
1function recordGame(won) {
2 var stats = JSON.parse(localStorage.getItem('minesweeper-stats') || '{"played":0,"won":0}');
3 stats.played++;
4 if (won) stats.won++;
5 localStorage.setItem('minesweeper-stats', JSON.stringify(stats));
6 updateStatsDisplay(stats);
7}
数字颜色
不同数字使用不同颜色,方便快速识别:
1.mine-cell.n1 { color: #0000ff; } /* 1 - 蓝 */
2.mine-cell.n2 { color: #008000; } /* 2 - 绿 */
3.mine-cell.n3 { color: #ff0000; } /* 3 - 红 */
4.mine-cell.n4 { color: #000080; } /* 4 - 深蓝 */
5.mine-cell.n5 { color: #800000; } /* 5 - 深红 */
6.mine-cell.n6 { color: #008080; } /* 6 - 青色 */
7.mine-cell.n7 { color: #000000; } /* 7 - 黑 */
8.mine-cell.n8 { color: #808080; } /* 8 - 灰 */
总结
扫雷的核心在于首次点击安全布雷和 BFS 区域展开算法。通过模式切换和双击快速展开,提升了操作效率。胜率统计功能增加了游戏的挑战性和可玩性。
留言评论
期待你的想法评论加载中