掃雷游戲開發教程:從零打造精美像素掃雷

完整源碼在本文結尾處

在這里插入圖片描述

一、游戲概述

掃雷是一款經典的益智游戲,玩家需要在不觸發地雷的情況下揭開所有安全格子。本教程將帶你從零開始開發一個具有精美界面和動畫效果的掃雷游戲,包含難度選擇、棋盤大小調整等高級功能。

二、游戲核心功能

  1. 三種難度級別:初級(9×9)、中級(16×16)、高級(16×30)
  2. 棋盤大小調整:小、中、大三種尺寸
  3. 計時系統:記錄游戲用時
  4. 地雷計數器:顯示剩余地雷數量
  5. 標記系統:右鍵標記可疑地雷位置
  6. 動畫效果:格子揭示、地雷爆炸、勝利慶祝等動畫

三、開發步驟詳解

  1. 游戲數據結構設計
// 游戲配置
const DIFFICULTY = {beginner: { rows: 9, cols: 9, mines: 10 },intermediate: { rows: 16, cols: 16, mines: 40 },expert: { rows: 16, cols: 30, mines: 99 }
};// 尺寸因子
const SIZE_FACTOR = {small: 0.8,medium: 1.0,large: 1.2
};// 游戲狀態
let gameConfig = { ...DIFFICULTY.beginner, sizeFactor: SIZE_FACTOR.small };
let board = [];          // 存儲每個格子的值(-1表示地雷,0-8表示周圍地雷數)
let revealed = [];       // 記錄格子是否被揭開
let flagged = [];        // 記錄格子是否被標記
let mines = [];          // 存儲所有地雷位置
  1. 初始化游戲
function initGame() {// 重置游戲狀態clearInterval(timerInterval);timer = 0;gameOver = false;gameWon = false;firstClick = true;// 創建棋盤數據結構createBoard();// 渲染棋盤到DOMrenderBoard();
}function createBoard() {// 初始化二維數組for (let i = 0; i < gameConfig.rows; i++) {board[i] = [];revealed[i] = [];flagged[i] = [];for (let j = 0; j < gameConfig.cols; j++) {board[i][j] = 0;revealed[i][j] = false;flagged[i][j] = false;}}
}
  1. 渲染棋盤
function renderBoard() {gridElement.innerHTML = '';gridElement.style.gridTemplateColumns = `repeat(${gameConfig.cols}, 1fr)`;// 應用尺寸因子const cellSize = Math.floor(30 * gameConfig.sizeFactor);document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {const cell = document.createElement('div');cell.className = 'cell';cell.dataset.row = i;cell.dataset.col = j;// 添加點擊事件cell.addEventListener('click', () => handleCellClick(i, j));cell.addEventListener('contextmenu', (e) => {e.preventDefault();handleRightClick(i, j);});gridElement.appendChild(cell);}}
}
  1. 放置地雷(確保第一次點擊安全)
function placeMines(firstRow, firstCol) {mines = [];let minesPlaced = 0;// 確保第一次點擊周圍沒有地雷const safeCells = [];for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = firstRow + i;const newCol = firstCol + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {safeCells.push(`${newRow},${newCol}`);}}}// 隨機放置地雷while (minesPlaced < gameConfig.mines) {const row = Math.floor(Math.random() * gameConfig.rows);const col = Math.floor(Math.random() * gameConfig.cols);// 跳過第一次點擊及其周圍的格子if (row === firstRow && col === firstCol) continue;if (safeCells.includes(`${row},${col}`)) continue;if (board[row][col] === -1) continue;board[row][col] = -1;mines.push({ row, col });minesPlaced++;// 更新周圍格子的數字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 < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols && board[newRow][newCol] !== -1) {board[newRow][newCol]++;}}}}
}
  1. 處理格子點擊
function handleCellClick(row, col) {if (gameOver || gameWon || flagged[row][col]) return;// 第一次點擊放置地雷if (firstClick) {placeMines(row, col);firstClick = false;// 開始計時timerInterval = setInterval(() => {timer++;timerElement.textContent = timer;}, 1000);}// 如果點擊到地雷if (board[row][col] === -1) {revealMines();gameOver = true;statusElement.textContent = "游戲結束!你踩到地雷了 💥";statusElement.classList.add("game-over");clearInterval(timerInterval);return;}// 揭示格子revealCell(row, col);// 檢查勝利條件checkWin();
}function revealCell(row, col) {if (revealed[row][col] || flagged[row][col]) return;revealed[row][col] = true;const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);cell.classList.add('revealed');if (board[row][col] > 0) {cell.textContent = board[row][col];cell.classList.add(`num-${board[row][col]}`);} else if (board[row][col] === 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 < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {revealCell(newRow, newCol);}}}}
}
  1. 右鍵標記功能
function handleRightClick(row, col) {if (gameOver || gameWon || revealed[row][col]) return;// 切換旗幟狀態flagged[row][col] = !flagged[row][col];flagCount += flagged[row][col] ? 1 : -1;// 更新UIconst cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);if (flagged[row][col]) {cell.classList.add('flagged');cell.textContent = '🚩';} else {cell.classList.remove('flagged');cell.textContent = '';}// 更新剩余地雷計數remainingMines = gameConfig.mines - flagCount;mineCountElement.textContent = remainingMines;// 檢查勝利條件checkWin();
}
  1. 勝利條件檢查
function checkWin() {// 檢查是否所有非地雷格子都被揭示let allRevealed = true;for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {if (board[i][j] !== -1 && !revealed[i][j]) {allRevealed = false;break;}}if (!allRevealed) break;}// 檢查是否所有地雷都被正確標記let allMinesFlagged = true;mines.forEach(mine => {if (!flagged[mine.row][mine.col]) {allMinesFlagged = false;}});if (allRevealed || allMinesFlagged) {gameWon = true;clearInterval(timerInterval);statusElement.textContent = `恭喜獲勝!用時 ${timer} 秒 🎉`;statusElement.classList.add("win");revealMines();}
}

四、關鍵CSS樣式解析

  1. 格子基礎樣式
.cell {width: var(--cell-size, 30px);height: var(--cell-size, 30px);background: linear-gradient(145deg, #95a5a6, #7f8c8d);border: 2px outset #ecf0f1;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: all 0.2s ease;border-radius: 4px;
}.cell:hover:not(.revealed) {background: linear-gradient(145deg, #bdc3c7, #95a5a6);transform: scale(0.95);
}
  1. 動畫效果
/* 揭示動畫 */
.revealed {animation: reveal 0.3s ease;
}@keyframes reveal {0% { transform: scale(1); opacity: 0.8; }50% { transform: scale(0.95); opacity: 0.9; }100% { transform: scale(0.97); opacity: 1; }
}/* 地雷爆炸動畫 */
.mine {animation: mineExplode 0.5s ease;
}@keyframes mineExplode {0% { transform: scale(1); }50% { transform: scale(1.2); }100% { transform: scale(1); }
}/* 旗幟標記動畫 */
.flagged {animation: flagWave 0.5s ease;
}@keyframes flagWave {0% { transform: rotate(-10deg); }50% { transform: rotate(10deg); }100% { transform: rotate(0); }
}

五、如何擴展游戲

  1. 添加關卡系統:設計不同主題的關卡(沙漠、雪地、太空等)
  2. 實現存檔功能:使用localStorage保存游戲進度
  3. 添加音效:為點擊、爆炸、勝利等事件添加音效
  4. 設計成就系統:根據游戲表現解鎖成就
  5. 添加多人模式:實現玩家間的競爭或合作模式

六、開發小貼士

  1. 測試驅動開發:先編寫測試用例再實現功能
  2. 模塊化設計:將游戲拆分為獨立模塊(渲染、邏輯、事件處理)
  3. 性能優化:對于大型棋盤使用虛擬滾動技術
  4. 響應式設計:確保在不同設備上都有良好的體驗
  5. 代碼注釋:為復雜邏輯添加詳細注釋

七、總結

通過本教程,你已經學會了如何開發一個功能完整的掃雷游戲。記住,游戲開發就像掃雷一樣——需要耐心、策略和一點冒險精神!當你遇到"地雷"(bug)時,不要灰心,標記它、分析它,然后優雅地解決它。

現在,快去創建你自己的掃雷游戲吧!如果你在開發過程中遇到任何問題,記得程序員休閑群QQ:708877645里有眾多掃雷高手可以幫你排雷!💣??🚩

完整源代碼
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>精美掃雷游戲</title><style>/* 所有CSS樣式保持不變 */* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {display: flex;justify-content: center;align-items: center;min-height: 100vh;background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);padding: 20px;}.game-container {background: rgba(255, 255, 255, 0.9);border-radius: 20px;box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);padding: 30px;width: 100%;max-width: 800px;text-align: center;transform: translateY(0);transition: transform 0.3s ease;}.game-container:hover {transform: translateY(-5px);}.game-title {font-size: 2.5rem;color: #2c3e50;margin-bottom: 20px;text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);animation: pulse 2s infinite;}@keyframes pulse {0% { transform: scale(1); }50% { transform: scale(1.03); }100% { transform: scale(1); }}.controls {display: flex;justify-content: center;gap: 15px;margin-bottom: 25px;flex-wrap: wrap;}.control-group {background: #f8f9fa;border-radius: 15px;padding: 15px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);}.control-title {font-size: 1.2rem;margin-bottom: 10px;color: #3498db;}.difficulty-btn, .size-btn, .new-game-btn {padding: 12px 20px;border: none;border-radius: 50px;cursor: pointer;font-weight: bold;font-size: 1rem;transition: all 0.3s ease;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);margin: 5px;}.difficulty-btn {background: linear-gradient(135deg, #3498db, #2c3e50);color: white;}.size-btn {background: linear-gradient(135deg, #2ecc71, #27ae60);color: white;}.new-game-btn {background: linear-gradient(135deg, #e74c3c, #c0392b);color: white;font-size: 1.1rem;padding: 15px 25px;}.difficulty-btn:hover, .size-btn:hover, .new-game-btn:hover {transform: translateY(-3px);box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);}.difficulty-btn.active, .size-btn.active {transform: scale(1.05);box-shadow: 0 0 15px rgba(52, 152, 219, 0.6);animation: activeGlow 1.5s infinite alternate;}@keyframes activeGlow {0% { box-shadow: 0 0 10px rgba(52, 152, 219, 0.6); }100% { box-shadow: 0 0 20px rgba(52, 152, 219, 0.8); }}.status-bar {display: flex;justify-content: space-between;margin-bottom: 20px;background: linear-gradient(to right, #3498db, #2c3e50);border-radius: 50px;padding: 15px 25px;color: white;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);}.status-item {font-size: 1.2rem;font-weight: bold;}.grid-container {overflow: auto;margin: 0 auto;padding: 10px;background: #2c3e50;border-radius: 15px;box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.3);}.grid {display: grid;gap: 2px;margin: 0 auto;background: #34495e;border-radius: 10px;padding: 5px;}.cell {width: var(--cell-size, 30px);height: var(--cell-size, 30px);background: linear-gradient(145deg, #95a5a6, #7f8c8d);border: 2px outset #ecf0f1;display: flex;align-items: center;justify-content: center;cursor: pointer;font-weight: bold;font-size: 1.1rem;transition: all 0.2s ease;user-select: none;border-radius: 4px;}.cell:hover:not(.revealed) {background: linear-gradient(145deg, #bdc3c7, #95a5a6);transform: scale(0.95);}.revealed {background: #ecf0f1;border: 1px solid #bdc3c7;transform: scale(0.97);animation: reveal 0.3s ease;}@keyframes reveal {0% { transform: scale(1); opacity: 0.8; }50% { transform: scale(0.95); opacity: 0.9; }100% { transform: scale(0.97); opacity: 1; }}.mine {background: #e74c3c !important;animation: mineExplode 0.5s ease;}@keyframes mineExplode {0% { transform: scale(1); }50% { transform: scale(1.2); }100% { transform: scale(1); }}.flagged {background: linear-gradient(145deg, #f1c40f, #f39c12);animation: flagWave 0.5s ease;}@keyframes flagWave {0% { transform: rotate(-10deg); }50% { transform: rotate(10deg); }100% { transform: rotate(0); }}/* 數字顏色 */.num-1 { color: #3498db; }.num-2 { color: #2ecc71; }.num-3 { color: #e74c3c; }.num-4 { color: #9b59b6; }.num-5 { color: #e67e22; }.num-6 { color: #1abc9c; }.num-7 { color: #34495e; }.num-8 { color: #7f8c8d; }.status-message {margin-top: 20px;padding: 15px;border-radius: 10px;font-size: 1.3rem;font-weight: bold;min-height: 50px;display: flex;align-items: center;justify-content: center;transition: all 0.5s ease;background: rgba(236, 240, 241, 0.9);box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);}.game-over {color: #e74c3c;animation: shake 0.5s ease-in-out;}@keyframes shake {0%, 100% { transform: translateX(0); }25% { transform: translateX(-10px); }75% { transform: translateX(10px); }}.win {color: #2ecc71;animation: bounce 0.5s ease-in-out;}@keyframes bounce {0%, 100% { transform: translateY(0); }50% { transform: translateY(-10px); }}.instructions {margin-top: 25px;background: rgba(52, 73, 94, 0.1);padding: 15px;border-radius: 10px;text-align: left;}.instructions h3 {color: #2c3e50;margin-bottom: 10px;}.instructions p {margin-bottom: 8px;color: #34495e;}/* 響應式設計 */@media (max-width: 768px) {.controls {flex-direction: column;align-items: center;}.difficulty-btn, .size-btn {width: 100%;max-width: 250px;}.cell {width: 25px;height: 25px;font-size: 0.9rem;}}@media (max-width: 480px) {.cell {width: 20px;height: 20px;font-size: 0.8rem;}.game-title {font-size: 2rem;}}</style>
</head>
<body><div class="game-container"><h1 class="game-title">程序員休閑群QQ:708877645掃雷</h1><div class="controls"><div class="control-group"><div class="control-title">難度選擇</div><button class="difficulty-btn active" data-difficulty="beginner">初級</button><button class="difficulty-btn" data-difficulty="intermediate">中級</button><button class="difficulty-btn" data-difficulty="expert">高級</button></div><div class="control-group"><div class="control-title">棋盤大小</div><button class="size-btn active" data-size="small"></button><button class="size-btn" data-size="medium"></button><button class="size-btn" data-size="large"></button></div><button class="new-game-btn">🔄 新游戲</button></div><div class="status-bar"><div class="status-item">?? 時間: <span id="timer">0</span></div><div class="status-item">💣 剩余: <span id="mine-count">10</span></div><div class="status-item">🚩 標記: <span id="flag-count">0</span></div></div><div class="grid-container"><div id="grid" class="grid"></div></div><div id="status" class="status-message">歡迎來到掃雷游戲!選擇難度后開始游戲</div><div class="instructions"><h3>游戲說明:</h3><p>? 左鍵點擊:揭開格子</p><p>? 右鍵點擊:標記/取消標記地雷</p><p>? 勝利條件:標記所有地雷并揭開所有安全格子</p><p>? 失敗條件:點擊到地雷格子</p></div></div><script>// 游戲配置const DIFFICULTY = {beginner: { rows: 9, cols: 9, mines: 10 },intermediate: { rows: 16, cols: 16, mines: 40 },expert: { rows: 16, cols: 30, mines: 99 }};// 修復:正確定義 SIZE_FACTOR 常量const SIZE_FACTOR = {small: 0.8,medium: 1.0,large: 1.2};// 游戲狀態let gameConfig = { ...DIFFICULTY.beginner, sizeFactor: SIZE_FACTOR.small };let board = [];let revealed = [];let flagged = [];let mines = [];let gameOver = false;let gameWon = false;let firstClick = true;let timer = 0;let timerInterval = null;let remainingMines = gameConfig.mines;let flagCount = 0;// DOM元素const gridElement = document.getElementById('grid');const statusElement = document.getElementById('status');const timerElement = document.getElementById('timer');const mineCountElement = document.getElementById('mine-count');const flagCountElement = document.getElementById('flag-count');const newGameBtn = document.querySelector('.new-game-btn');// 初始化游戲function initGame() {// 重置游戲狀態clearInterval(timerInterval);timer = 0;timerElement.textContent = timer;gameOver = false;gameWon = false;firstClick = true;remainingMines = gameConfig.mines;flagCount = 0;mineCountElement.textContent = remainingMines;flagCountElement.textContent = flagCount;statusElement.textContent = "游戲開始!點擊任意格子";statusElement.className = "status-message";// 初始化數組board = [];revealed = [];flagged = [];mines = [];// 創建棋盤createBoard();renderBoard();}// 創建棋盤數據結構function createBoard() {// 初始化二維數組for (let i = 0; i < gameConfig.rows; i++) {board[i] = [];revealed[i] = [];flagged[i] = [];for (let j = 0; j < gameConfig.cols; j++) {board[i][j] = 0;revealed[i][j] = false;flagged[i][j] = false;}}}// 渲染棋盤到DOMfunction renderBoard() {gridElement.innerHTML = '';gridElement.style.gridTemplateColumns = `repeat(${gameConfig.cols}, 1fr)`;// 應用尺寸因子const cellSize = Math.floor(30 * gameConfig.sizeFactor);document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {const cell = document.createElement('div');cell.className = 'cell';cell.dataset.row = i;cell.dataset.col = j;// 添加點擊事件cell.addEventListener('click', () => handleCellClick(i, j));cell.addEventListener('contextmenu', (e) => {e.preventDefault();handleRightClick(i, j);});gridElement.appendChild(cell);}}}// 放置地雷(確保第一次點擊安全)function placeMines(firstRow, firstCol) {mines = [];let minesPlaced = 0;// 確保第一次點擊周圍沒有地雷const safeCells = [];for (let i = -1; i <= 1; i++) {for (let j = -1; j <= 1; j++) {const newRow = firstRow + i;const newCol = firstCol + j;if (newRow >= 0 && newRow < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {safeCells.push(`${newRow},${newCol}`);}}}// 隨機放置地雷while (minesPlaced < gameConfig.mines) {const row = Math.floor(Math.random() * gameConfig.rows);const col = Math.floor(Math.random() * gameConfig.cols);// 跳過第一次點擊及其周圍的格子if (row === firstRow && col === firstCol) continue;if (safeCells.includes(`${row},${col}`)) continue;if (board[row][col] === -1) continue;board[row][col] = -1;mines.push({ row, col });minesPlaced++;// 更新周圍格子的數字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 < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols && board[newRow][newCol] !== -1) {board[newRow][newCol]++;}}}}}// 處理格子點擊function handleCellClick(row, col) {if (gameOver || gameWon || flagged[row][col]) return;// 如果是第一次點擊,放置地雷if (firstClick) {placeMines(row, col);firstClick = false;// 開始計時timerInterval = setInterval(() => {timer++;timerElement.textContent = timer;}, 1000);}// 如果點擊到地雷if (board[row][col] === -1) {revealMines();gameOver = true;statusElement.textContent = "游戲結束!你踩到地雷了 💥";statusElement.classList.add("game-over");clearInterval(timerInterval);return;}// 揭示格子revealCell(row, col);// 檢查勝利條件checkWin();}// 處理右鍵點擊(標記旗幟)function handleRightClick(row, col) {if (gameOver || gameWon || revealed[row][col]) return;// 切換旗幟狀態flagged[row][col] = !flagged[row][col];flagCount += flagged[row][col] ? 1 : -1;flagCountElement.textContent = flagCount;// 更新UIconst cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);if (flagged[row][col]) {cell.classList.add('flagged');cell.textContent = '🚩';} else {cell.classList.remove('flagged');cell.textContent = '';}// 更新剩余地雷計數remainingMines = gameConfig.mines - flagCount;mineCountElement.textContent = remainingMines;// 檢查勝利條件checkWin();}// 揭示格子function revealCell(row, col) {if (revealed[row][col] || flagged[row][col]) return;revealed[row][col] = true;const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);cell.classList.add('revealed');if (board[row][col] > 0) {cell.textContent = board[row][col];cell.classList.add(`num-${board[row][col]}`);} else if (board[row][col] === 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 < gameConfig.rows && newCol >= 0 && newCol < gameConfig.cols) {revealCell(newRow, newCol);}}}}}// 揭示所有地雷(游戲結束時)function revealMines() {mines.forEach(mine => {const cell = document.querySelector(`.cell[data-row="${mine.row}"][data-col="${mine.col}"]`);if (!flagged[mine.row][mine.col]) {cell.classList.add('mine', 'revealed');cell.textContent = '💣';}});}// 檢查勝利條件function checkWin() {// 檢查是否所有非地雷格子都被揭示let allRevealed = true;for (let i = 0; i < gameConfig.rows; i++) {for (let j = 0; j < gameConfig.cols; j++) {if (board[i][j] !== -1 && !revealed[i][j]) {allRevealed = false;break;}}if (!allRevealed) break;}// 檢查是否所有地雷都被正確標記let allMinesFlagged = true;mines.forEach(mine => {if (!flagged[mine.row][mine.col]) {allMinesFlagged = false;}});if (allRevealed || allMinesFlagged) {gameWon = true;clearInterval(timerInterval);statusElement.textContent = `恭喜獲勝!用時 ${timer} 秒 🎉`;statusElement.classList.add("win");revealMines();}}// 設置難度function setDifficulty(difficulty) {gameConfig = { ...DIFFICULTY[difficulty], sizeFactor: gameConfig.sizeFactor };// 更新UIdocument.querySelectorAll('.difficulty-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.difficulty === difficulty);});initGame();}// 設置棋盤大小(確保調用initGame重新初始化)function setSize(size) {gameConfig.sizeFactor = SIZE_FACTOR[size];// 更新UIdocument.querySelectorAll('.size-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.size === size);});// 重新初始化游戲以應用新尺寸initGame();}// 事件監聽document.querySelectorAll('.difficulty-btn').forEach(btn => {btn.addEventListener('click', () => setDifficulty(btn.dataset.difficulty));});document.querySelectorAll('.size-btn').forEach(btn => {btn.addEventListener('click', () => setSize(btn.dataset.size));});newGameBtn.addEventListener('click', initGame);// 初始化游戲initGame();</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90824.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90824.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90824.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux驅動開發筆記(五)——設備樹(上)

內容詳見《【正點原子】I.MX6U嵌入式Linux驅動開發指南》四十三章 開發板&#xff1a;imx6ull mini 虛擬機&#xff1a;VMware17 ubuntu&#xff1a;ubuntu20.04 一、什么是設備樹 視頻&#xff1a;第6.1講 Linux設備樹詳解-什么是設備樹&#xff1f;_嗶哩嗶哩_bilibili 對…

【QT入門到晉級】window opencv安裝及引入qtcreator(包含兩種qt編譯器:MSVC和MinGW)

前言 本文主要分享QT的兩種編譯器環境&#xff08;MSVC和MinGW&#xff09;下&#xff0c;安裝及引入opencv的方法。 編譯器區別 特性????MSVC????MinGW????編譯器類型??微軟專有編譯器&#xff08;cl.exe&#xff09;基于GCC的開源工具鏈??平臺支持??僅Wi…

字節跳動Coze Studio開源了!架構解析

Coze Studio 是字節跳動推出的一款 AI 應用開發平臺&#xff0c;專注于幫助開發者快速構建、測試和部署基于大語言模型的智能應用。其整體架構圍繞“低代碼開發 AI 應用”的核心目標設計&#xff0c;融合了模型能力、工具集成、流程編排和多端部署等功能。以下是其整體架構的詳…

Claude 4.0 終極編程指南:模型對比、API配置與IDE集成實戰

Claude 4.0 終極編程指南&#xff1a;模型對比、API配置與IDE集成實戰 基于官方文檔及可驗證數據源&#xff08;2025年7月更新&#xff09; 1 Claude 4.0 技術解析&#xff1a;對比競品的核心優勢與局限 1.1 官方性能數據&#xff08;來源&#xff1a;Anthropic技術白皮書&…

優化:Toc小程序猜你喜歡功能

引言&#xff1a;來自自創的小程序中熱點接口&#xff0c;本小程序專為在校學生自提點餐使用 一、功能描述 該功能作為一個推薦的職責&#xff0c;根據用戶最近行為給用戶推薦用戶可能喜歡去吃的店鋪&#xff0c;可能比較簡潔&#xff0c;但是需要設計的方面挺多的&#xff0c…

Datawhale AI 夏令營:讓AI理解列車排期表 Notebook(Baseline拆解)

Step1、讀取數據 import pandas as pd import requests import re import json from tqdm import tqdm# 讀取數據 data pd.read_excel(data/info_table.xlsx) data data.fillna(無數據) dataStep2、注冊硅基流動https://cloud.siliconflow.cnQwen/Qwen3-8B 模型可以免費使用&…

vue寫的app設置角標

原生App角標&#xff08;UniApp示例&#xff09;調用plus.runtime.setBadgeNumber方法設置安卓/iOS角標&#xff1a;javascriptCopy Code// 設置角標 plus.runtime.setBadgeNumber(99); // 清除角標&#xff08;部分平臺需特殊處理&#xff09; plus.runtime.setBadgeNumber(0)…

GAN/cGAN中到底要不要注入噪聲

MelGAN論文MelGAN針對的是從mel譜生成語音&#xff0c;里面說當條件很強的時候&#xff0c;隨機噪聲就沒啥用了&#xff0c;因此沒將noise注入到生成器中&#xff1b;運用的判別器也僅有1個輸入&#xff0c;不是cGAN的形式image-to-image translation with conditional adversa…

備份一下我的 mac mini 的環境變量配置情況

export PATH“/opt/homebrew/bin:$PATH” #THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! export SDKMAN_DIR“HOME/.sdkman"[[?s"HOME/.sdkman" [[ -s "HOME/.sdkman"[[?s"HOME/.sdkman/bin/sdkman-init.sh” ]] && so…

JVM學習日記(十)Day10

G1回收器 這一篇是詳細說明G1回收器的&#xff0c;因為他相對來說確實是個縫合怪&#xff0c;上篇的內容又太多了所不清楚&#xff0c;所有這一篇進行詳細的說明&#xff0c; 第一個呢就是其實G1是兼顧并行和并發的&#xff0c;簡單來說就是既可以并行也可以并發&#xff0c;…

使用IP掃描工具排查網絡問題

隨著企業的發展&#xff0c;網絡中會新增各類設備&#xff0c;從臺式機、服務器到物聯網設備和虛擬機&#xff08;VMs&#xff09;&#xff0c;所有這些設備都通過復雜的子網和虛擬局域網&#xff08;VLAN&#xff09;相連。 這種復雜性給 IT 團隊帶來了壓力&#xff0c;他們需…

Wireshark TS | 發送數據超出接收窗口

前言 來自于測試中無意發現到的一個接收窗口滿的案例&#xff0c;特殊&#xff0c;或者可以說我以前都沒在實際場景中見過。一開始都沒整太明白&#xff0c;花了些精力才算是弄清楚了些&#xff0c;記錄分享下。 問題說明 在研究擁塞控制的慢啟動階段時&#xff0c;通過 packet…

C語言自定義數據類型詳解(四)——聯合體

好的&#xff0c;接下來我們來學習最后一個自定義數據類型——聯合體。 一、什么是聯合體&#xff1a; 聯合體又叫共用體&#xff0c;用關鍵字union來進行定義。又因為所有的成員變量共用同一段內存空間&#xff08;關于這一點&#xff0c;我們不久就會加以驗證&#xff09;&…

[python][flask]Flask-Login 使用詳解

1. 簡介Flask-Login 是 Flask 的一個擴展&#xff0c;專門用于處理用戶認證相關的功能。它提供了用戶會話管理、登錄/注銷視圖、記住我功能等常見認證需求&#xff0c;讓開發者能夠快速實現安全的用戶認證系統。2. 安裝與基礎配置首先&#xff0c;需要安裝 Flask-Login&#xf…

【WebGPU學習雜記】WebAssembly中的relaxed_madd指令到底做了什么?

relaxed_madd 這條指令到底做了什么核心&#xff1a;relaxed_madd 是一個分量級別 (Component-wise) 的操作 首先&#xff0c;最重要的一點是&#xff1a;v128.relaxed_madd<f32>(a, b, c) 不是矩陣乘法。它是一個在三個向量 a, b, c 之間進行的、逐個分量的、并行的融合…

【全新上線】境內 Docker 鏡像狀態監控

境內 Docker 鏡像狀態監控&#xff1a;您的 Docker 加速伴侶 在當今云計算和容器化技術飛速發展的時代&#xff0c;Docker 已成為開發者不可或缺的工具。然而&#xff0c;對于身處國內的用戶而言&#xff0c;訪問境外 Docker Hub 等鏡像倉庫時常會遭遇網絡延遲和連接不穩定的困…

Visual Studio中部署PaddleOCRv5 (借助ncnn框架)

PaddleOCRv5_ncnn PaddleOCRv5 在Visual Studio中進行圖片OCR檢測&#xff08;ncnn框架open-mobile實現)&#xff0c;嘗試對nihui的ncnn-android-ppocrv5檢測算法的剝離與移植。 本項目Github鏈接如下&#xff1a;PaddleOCRv5_ncnn 寫在前面 本倉庫代碼是基于nihui的ncnn-a…

中級全棧工程師筆試題

解釋ACID特性&#xff0c;如何在node.js中實現事務操作針對React單頁應用&#xff0c;請提供至少5種性能優化方案&#xff0c;并解釋其原理&#xff1a; 減少首屏加載時間優化渲染性能資源加載策略狀態管理優化代碼分割方案 如何防止以下攻擊&#xff1a; JWT令牌挾持Graph QL查…

Windows---動態鏈接庫Dynamic Link Library(.dll)

DLL的“幕后英雄”角色 在Windows操作系統的生態中&#xff0c;有一類文件始終扮演著“幕后英雄”的角色——它們不像.exe文件那樣直接呈現為用戶可見的程序窗口&#xff0c;卻支撐著幾乎所有應用程序的運行&#xff1b;它們不單獨執行&#xff0c;卻承載著系統與軟件的核心功…

深入分析計算機網絡傳輸層和應用層面試題

三、傳輸層面試題&#xff08;Transmission Layer&#xff09;傳輸層位于 OSI 七層模型的第四層&#xff0c;它的核心任務是為兩個主機之間的應用層提供可靠的數據傳輸服務。它不僅承擔了數據的端到端傳輸&#xff0c;而且還實現了諸如差錯檢測、數據流控制、擁塞控制等機制&am…