多主题素材扫雷游戏edit icon

作者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>智能扫雷(多主题优化版)</title>
    <style>
        /* ============ 主题系统 ============ */
        :root {
            --bg-color: #f0f0f0;
            --cell-color: #c0c0c0;
            --text-color: #333;
            --border-color: #808080;
            --danger: #ff4444;
            --safe: #4CAF50;
            --header-bg: #e0e0e0;
            --button-bg: #bbb;
            --button-hover: #999;
            --flag-color: #ffecb3;
        }

        [data-theme="dark"] {
            --bg-color: #2d2d2d;
            --cell-color: #404040;
            --text-color: #ddd;
            --border-color: #666;
            --danger: #d32f2f;
            --safe: #388e3c;
            --header-bg: #3a3a3a;
            --button-bg: #555;
            --button-hover: #777;
            --flag-color: #5d4037;
        }

        [data-theme="forest-light"] {
            --bg-color: #e8f5e9;
            --cell-color: #a5d6a7;
            --text-color: #1b5e20;
            --border-color: #4caf50;
            --danger: #e53935;
            --safe: #2e7d32;
            --header-bg: #c8e6c9;
            --button-bg: #81c784;
            --button-hover: #66bb6a;
            --flag-color: #fff176;
        }

        [data-theme="forest-dark"] {
            --bg-color: #1b5e20;
            --cell-color: #388e3c;
            --text-color: #e8f5e8;
            --border-color: #66bb6a;
            --danger: #f44336;
            --safe: #81c784;
            --header-bg: #2e7d32;
            --button-bg: #1b5e20;
            --button-hover: #388e3c;
            --flag-color: #ffd54f;
        }

        [data-theme="ocean-light"] {
            --bg-color: #e0f7fa;
            --cell-color: #80deea;
            --text-color: #006064;
            --border-color: #00acc1;
            --danger: #ff7043;
            --safe: #00838f;
            --header-bg: #b2ebf2;
            --button-bg: #4dd0e1;
            --button-hover: #26c6da;
            --flag-color: #ffcc80;
        }

        [data-theme="ocean-dark"] {
            --bg-color: #004d40;
            --cell-color: #00838f;
            --text-color: #e0f7fa;
            --border-color: #26c6da;
            --danger: #ff7043;
            --safe: #80deea;
            --header-bg: #006064;
            --button-bg: #004d40;
            --button-hover: #00838f;
            --flag-color: #ffcc80;
        }

        /* ============ 全局样式 ============ */
        body {
            background: var(--bg-color);
            color: var(--text-color);
            transition: background 0.5s ease, color 0.5s ease;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
        }

        .mode-select-container,
        .game-container,
        .custom-mode-container {
            max-width: 500px;
            margin: 2rem auto;
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 6px 20px rgba(0,0,0,0.25);
            background: var(--bg-color);
            transition: background 0.5s;
        }

        .header {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: space-between;
            align-items: center;
            padding: 12px;
            background: var(--header-bg);
            border-radius: 10px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
        }

        button {
            background: var(--button-bg);
            color: var(--text-color);
            border: none;
            padding: 8px 14px;
            border-radius: 8px;
            cursor: pointer;
            font-weight: bold;
            transition: background 0.3s, transform 0.2s;
        }

        button:hover {
            background: var(--button-hover);
            transform: translateY(-2px);
        }

        .grid {
            display: grid;
            gap: 2px;
            margin-top: 1rem;
        }

        .cell {
            aspect-ratio: 1;
            background: var(--cell-color);
            border: 2px solid var(--border-color);
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 1.2em;
            cursor: pointer;
            transition: all 0.3s ease;
            user-select: none;
            border-radius: 4px;
        }

        .cell:hover:not(.revealed) {
            transform: scale(1.08);
            box-shadow: 0 0 8px rgba(0,0,0,0.2);
        }

        .cell.revealed {
            background: var(--bg-color);
            box-shadow: inset 0 0 4px rgba(0,0,0,0.1);
        }

        .cell.mine {
            background: var(--danger) !important;
        }

        .cell.flag {
            background: var(--flag-color) !important;
        }

        #status {
            margin-top: 15px;
            font-weight: bold;
            text-align: center;
            font-size: 1.1em;
            padding: 8px;
            border-radius: 8px;
            background: rgba(0,0,0,0.05);
        }

        .theme-select-container {
            position: fixed;
            top: 15px;
            right: 15px;
            z-index: 10;
        }

        .theme-select-container select {
            padding: 6px 10px;
            border-radius: 20px;
            background: var(--button-bg);
            color: var(--text-color);
            border: none;
            font-weight: bold;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <!-- 主题选择器 -->
    <div class="theme-select-container">
        <select id="theme-select" onchange="changeTheme(this.value)">
            <option value="light">经典浅色</option>
            <option value="dark">经典深色</option>
            <option value="forest-light">🌲 森林(浅)</option>
            <option value="forest-dark">🌲 森林(深)</option>
            <option value="ocean-light">🌊 海洋(浅)</option>
            <option value="ocean-dark">🌊 海洋(深)</option>
        </select>
    </div>

    <!-- 开始页面 -->
    <div class="mode-select-container" id="mode-select">
        <h1>🎮 智能扫雷</h1>
        <button onclick="selectMode('default')">默认模式(10×10,10雷)</button>
        <button onclick="selectMode('custom')">自定义模式</button>
    </div>

    <!-- 游戏页面 -->
    <div class="game-container" id="game-container" style="display: none;">
        <button onclick="returnToModeSelect()">⬅️ 返回开始页面</button>
        <div class="header">
            <span id="mine-count">💣10</span>
            <button onclick="initGame()">🔄 新游戏</button>
            <button onclick="resetGame()">🔁 重来</button>
            <span id="timer">⏱<span id="time">0</span></span>
            <button id="swapBtn" onclick="swapClickMode()">↔️ 正常模式</button>
        </div>
        <div class="grid" id="grid"></div>
        <div id="status"></div>
    </div>

    <!-- 自定义页面 -->
    <div class="custom-mode-container" id="custom-mode-container" style="display: none;">
        <h1>🛠 自定义游戏</h1>
        <label for="width">宽度(5-20):</label>
        <input type="number" id="width" min="5" max="20" value="10"><br><br>
        <label for="height">高度(5-20):</label>
        <input type="number" id="height" min="5" max="20" value="10"><br><br>
        <label for="mines">地雷数量(1-100):</label>
        <input type="number" id="mines" min="1" max="100" value="10"><br><br>
        <button onclick="startCustomGame()">🚀 开始游戏</button>
        <button onclick="returnToModeSelect()">⬅️ 返回开始页面</button>
    </div>

    <script>
        let GRID_SIZE = 10;
        let MINES_COUNT = 10;
        let gameActive = true;
        let timerInterval;
        let cellsRevealed = 0;
        let bestTime = localStorage.getItem('bestTime') || Infinity;
        let isSwapped = false;
        let remainingMines = MINES_COUNT;
        let mineMap = [];

        // 初始化主题
        let currentTheme = localStorage.getItem('theme') || 'light';
        document.body.dataset.theme = currentTheme;
        document.getElementById('theme-select').value = currentTheme;

        function changeTheme(theme) {
            document.body.dataset.theme = theme;
            localStorage.setItem('theme', theme);
        }

        function selectMode(mode) {
            document.getElementById('mode-select').style.display = 'none';
            if (mode === 'default') {
                GRID_SIZE = 10;
                MINES_COUNT = 10;
                document.getElementById('game-container').style.display = 'block';
                initGame();
            } else {
                document.getElementById('custom-mode-container').style.display = 'block';
            }
        }

        function startCustomGame() {
            const w = parseInt(document.getElementById('width').value);
            const h = parseInt(document.getElementById('height').value);
            const m = parseInt(document.getElementById('mines').value);
            if (m >= w * h) {
                alert("地雷数量不能大于或等于总格子数!");
                return;
            }
            GRID_SIZE = Math.max(5, Math.min(20, w));
            MINES_COUNT = Math.max(1, Math.min(100, m));
            document.getElementById('custom-mode-container').style.display = 'none';
            document.getElementById('game-container').style.display = 'block';
            initGame();
        }

        function returnToModeSelect() {
            clearInterval(timerInterval);
            document.getElementById('game-container').style.display = 'none';
            document.getElementById('custom-mode-container').style.display = 'none';
            document.getElementById('mode-select').style.display = 'block';
        }

        function initGame() {
            clearInterval(timerInterval);
            document.getElementById('time').textContent = '0';
            document.getElementById('status').textContent = '';
            gameActive = true;
            cellsRevealed = 0;
            remainingMines = MINES_COUNT;
            document.getElementById('mine-count').textContent = `💣${remainingMines}`;

            const grid = document.getElementById('grid');
            grid.innerHTML = '';
            grid.style.gridTemplateColumns = `repeat(${GRID_SIZE}, 1fr)`;

            mineMap = createMineMap();
            mineMap.forEach((row, i) => {
                row.forEach((cell, j) => {
                    const div = document.createElement('div');
                    div.className = 'cell';
                    div.dataset.value = cell;
                    div.dataset.x = i;
                    div.dataset.y = j;
                    div.addEventListener('click', handleClick);
                    div.addEventListener('contextmenu', handleRightClick);
                    grid.appendChild(div);
                });
            });

            let seconds = 0;
            timerInterval = setInterval(() => {
                if (gameActive) document.getElementById('time').textContent = ++seconds;
            }, 1000);
        }

        function createMineMap() {
            const map = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0));

            let mines = 0;
            while (mines < MINES_COUNT) {
                const x = Math.floor(Math.random() * GRID_SIZE);
                const y = Math.floor(Math.random() * GRID_SIZE);
                if (map[x][y] !== 'X') {
                    map[x][y] = 'X';
                    mines++;
                }
            }

            for (let i = 0; i < GRID_SIZE; i++) {
                for (let j = 0; j < GRID_SIZE; j++) {
                    if (map[i][j] === 'X') continue;
                    let count = 0;
                    for (let dx = -1; dx <= 1; dx++) {
                        for (let dy = -1; dy <= 1; dy++) {
                            const x = i + dx;
                            const y = j + dy;
                            if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
                                if (map[x][y] === 'X') count++;
                            }
                        }
                    }
                    map[i][j] = count;
                }
            }
            return map;
        }

        function handleClick(e) {
            if (!gameActive) return;
            const cell = e.target;
            isSwapped ? handleRightClickAction(cell) : handleLeftClickAction(cell);
        }

        function handleRightClick(e) {
            e.preventDefault();
            if (!gameActive) return;
            const cell = e.target;
            isSwapped ? handleLeftClickAction(cell) : handleRightClickAction(cell);
        }

        function handleLeftClickAction(cell) {
            const value = cell.dataset.value;
            if (cell.classList.contains('flag')) return;

            if (value === 'X') {
                gameOver();
                cell.classList.add('mine');
                cell.textContent = '💥';
            } else {
                revealCell(cell);
                checkWinConditions();
            }
        }

        function handleRightClickAction(cell) {
            if (!cell.classList.contains('revealed')) {
                const wasFlagged = cell.classList.contains('flag');
                cell.classList.toggle('flag');
                cell.textContent = cell.classList.contains('flag') ? '🚩' : '';

                if (wasFlagged) {
                    remainingMines += 1;
                } else {
                    remainingMines -= 1;
                }
                remainingMines = Math.max(0, Math.min(MINES_COUNT, remainingMines));
                document.getElementById('mine-count').textContent = `💣${remainingMines}`;

                checkWinConditions();
            }
        }

        function revealCell(cell) {
            if (cell.classList.contains('revealed')) return;

            cell.classList.add('revealed');
            cell.textContent = cell.dataset.value;

            if (cell.dataset.value === '0') {
                cell.textContent = '';
                revealNeighbors(cell);
            }

            checkWinConditions();
        }

        function revealNeighbors(cell) {
            const x = parseInt(cell.dataset.x);
            const y = parseInt(cell.dataset.y);

            for (let dx = -1; dx <= 1; dx++) {
                for (let dy = -1; dy <= 1; dy++) {
                    const nx = x + dx;
                    const ny = y + dy;
                    const neighbor = document.querySelector(`[data-x="${nx}"][data-y="${ny}"]`);
                    if (neighbor && !neighbor.classList.contains('revealed')) {
                        revealCell(neighbor);
                    }
                }
            }
        }

        function checkWinConditions() {
            const allNonMinesRevealed = Array.from(document.querySelectorAll('.cell'))
                .filter(cell => cell.dataset.value !== 'X')
                .every(cell => cell.classList.contains('revealed'));

            if (allNonMinesRevealed) {
                gameActive = false;
                clearInterval(timerInterval);
                const time = parseInt(document.getElementById('time').textContent);
                if (time < bestTime) {
                    bestTime = time;
                    localStorage.setItem('bestTime', bestTime);
                }
                document.getElementById('status').textContent = `🎉 胜利!用时:${time}s | 最佳成绩:${bestTime}s`;

                document.querySelectorAll('.cell').forEach(cell => {
                    if (cell.dataset.value === 'X') {
                        cell.textContent = '💣';
                        cell.classList.add('revealed');
                    }
                });
            }
        }

        function gameOver() {
            gameActive = false;
            clearInterval(timerInterval);
            document.querySelectorAll('.cell').forEach(cell => {
                if (cell.dataset.value === 'X') {
                    cell.classList.add('mine');
                    cell.textContent = '💥';
                } else if (cell.classList.contains('flag') && cell.dataset.value !== 'X') {
                    cell.textContent = '❌'; // 错误标记
                }
            });
            document.getElementById('status').textContent = '💥 踩到地雷了!游戏结束!';
        }

        function swapClickMode() {
            isSwapped = !isSwapped;
            document.getElementById('swapBtn').textContent = isSwapped
                ? "↔️ 左键标记 / 右键点击(标记模式)"
                : "↔️ 正常模式";
        }

        function resetGame() {
            clearInterval(timerInterval);
            document.getElementById('time').textContent = '0';
            document.getElementById('status').textContent = '';
            gameActive = true;
            cellsRevealed = 0;
            remainingMines = MINES_COUNT;
            document.getElementById('mine-count').textContent = `💣${remainingMines}`;

            const grid = document.getElementById('grid');
            Array.from(grid.children).forEach(cell => {
                cell.classList.remove('revealed', 'mine', 'flag');
                cell.textContent = '';
            });

            let seconds = 0;
            timerInterval = setInterval(() => {
                if (gameActive) document.getElementById('time').textContent = ++seconds;
            }, 1000);
        }
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台