使用说明

游戏操作:

使用键盘方向键(↑↓←→)移动方块

在触摸设备上可以通过滑动屏幕移动方块

点击"撤销"按钮可以回退到上一步操作

点击"新游戏"按钮重新开始游戏

回溯功能:

最多可以回溯5步操作

游戏结束或获胜后无法回溯

回溯会恢复分数和方块位置

游戏目标:

合并相同数字的方块

尝试创建2048方块

获得尽可能高的分数

<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>炫酷2048游戏 - 终极优化版</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            user-select: none;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #0c0b1d, #252348, #1a1a33);
            color: #fff;
            overflow: hidden;
            position: relative;
        }
        
        /* 粒子背景 */
        .particles {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
        }
        
        .particle {
            position: absolute;
            width: 4px;
            height: 4px;
            background: rgba(255, 255, 255, 0.5);
            border-radius: 50%;
            animation: float 15s infinite linear;
        }
        
        @keyframes float {
            0% {
                transform: translateY(100vh) translateX(0);
                opacity: 0;
            }
            10% {
                opacity: 1;
            }
            90% {
                opacity: 1;
            }
            100% {
                transform: translateY(-100px) translateX(100px);
                opacity: 0;
            }
        }
        
        .game-container {
            max-width: 500px;
            width: 100%;
            padding: 20px;
            position: relative;
            z-index: 10;
        }
        
        .game-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        
        .title {
            font-size: 3rem;
            font-weight: 800;
            background: linear-gradient(to right, #ff9a9e, #fad0c4, #fad0c4, #a18cd1);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            text-shadow: 0 0 15px rgba(255, 154, 158, 0.4);
            letter-spacing: 2px;
        }
        
        .scores-container {
            display: flex;
            gap: 10px;
        }
        
        .score-box {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 10px;
            padding: 12px 18px;
            text-align: center;
            min-width: 110px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.15);
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
        }
        
        .score-title {
            font-size: 0.9rem;
            font-weight: 600;
            color: #ffca28;
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 5px;
        }
        
        .score-value {
            font-size: 1.8rem;
            font-weight: 800;
            color: #fff;
        }
        
        .game-intro {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        
        .game-controls {
            display: flex;
            gap: 10px;
        }
        
        .game-button {
            background: linear-gradient(to right, #4facfe, #00f2fe);
            color: white;
            border: none;
            border-radius: 8px;
            padding: 12px 20px;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
            box-shadow: 0 4px 12px rgba(79, 172, 254, 0.4);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .game-button.undo {
            background: linear-gradient(to right, #ff9a9e, #fad0c4);
        }
        
        .game-button:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 18px rgba(79, 172, 254, 0.6);
        }
        
        .game-button:active {
            transform: translateY(1px);
        }
        
        .game-message {
            font-size: 1.2rem;
            font-weight: 600;
            height: 30px;
            display: flex;
            align-items: center;
            padding: 0 15px;
            border-radius: 6px;
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(5px);
        }
        
        .game-win {
            color: #4caf50;
            text-shadow: 0 0 10px rgba(76, 175, 80, 0.5);
        }
        
        .game-over {
            color: #f44336;
            text-shadow: 0 0 10px rgba(244, 67, 54, 0.5);
        }
        
        .game-grid-container {
            background: rgba(255, 255, 255, 0.05);
            border-radius: 12px;
            padding: 15px;
            margin-bottom: 20px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
            position: relative;
        }
        
        .grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-gap: 15px;
            position: relative;
        }
        
        .grid-cell {
            width: 100%;
            height: 0;
            padding-bottom: 100%;
            background: rgba(255, 255, 255, 0.08);
            border-radius: 8px;
            position: relative;
            box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.2);
        }
        
        .tile-container {
            position: absolute;
            top: 15px;
            left: 15px;
            right: 15px;
            bottom: 15px;
            z-index: 10;
        }
        
        .tile {
            position: absolute;
            width: calc(25% - 11.25px);
            height: calc(25% - 11.25px);
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 2rem;
            font-weight: 800;
            z-index: 10;
            transition: transform 0.15s ease, opacity 0.15s ease;
            animation-duration: 0.2s;
            animation-fill-mode: both;
            /* 添加平滑移动动画 */
            transition: transform 0.15s ease, opacity 0.15s ease;
        }
        
        /* 添加移动动画效果 */
        .tile-moving {
            transition: transform 0.15s ease;
        }
        
        .tile-new {
            animation: appear 0.3s;
        }
        
        .tile-merged {
            animation: pop 0.4s;
        }
        
        /* 增强合并动画效果 */
        @keyframes pop {
            0% {
                transform: scale(0.9);
                box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
            }
            50% {
                transform: scale(1.2);
                box-shadow: 0 0 0 10px rgba(255, 255, 255, 0);
            }
            100% {
                transform: scale(1);
            }
        }
        
        @keyframes appear {
            0% {
                transform: scale(0);
                opacity: 0;
            }
            70% {
                transform: scale(1.1);
                opacity: 1;
            }
            100% {
                transform: scale(1);
            }
        }
        
        /* 方向指示器 */
        .direction-indicator {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 4rem;
            opacity: 0;
            pointer-events: none;
            z-index: 20;
            text-shadow: 0 0 20px rgba(255, 255, 255, 0.8);
            animation: fadeDirection 0.5s ease-out;
        }
        
        @keyframes fadeDirection {
            0% {
                opacity: 0.8;
                transform: translate(-50%, -50%) scale(1.5);
            }
            100% {
                opacity: 0;
                transform: translate(-50%, -50%) scale(2.5);
            }
        }
        
        /* 不同数值的方块颜色 */
        .tile-2 { background: #3a3a5d; color: #eee; font-size: 1.8rem; }
        .tile-4 { background: #2a2a4a; color: #eee; font-size: 1.8rem; }
        .tile-8 { background: linear-gradient(135deg, #ff7043, #ff8c5a); color: #fff; font-size: 1.8rem; box-shadow: 0 5px 15px rgba(255, 112, 67, 0.4); }
        .tile-16 { background: linear-gradient(135deg, #ff5722, #ff7043); color: #fff; font-size: 1.7rem; box-shadow: 0 5px 15px rgba(255, 87, 34, 0.4); }
        .tile-32 { background: linear-gradient(135deg, #f44336, #ff5722); color: #fff; font-size: 1.7rem; box-shadow: 0 5px 15px rgba(244, 67, 54, 0.4); }
        .tile-64 { background: linear-gradient(135deg, #d32f2f, #f44336); color: #fff; font-size: 1.7rem; box-shadow: 0 5px 15px rgba(211, 47, 47, 0.4); }
        .tile-128 { background: linear-gradient(135deg, #ffca28, #ffd54f); color: #333; font-size: 1.6rem; box-shadow: 0 5px 20px rgba(255, 202, 40, 0.5); }
        .tile-256 { background: linear-gradient(135deg, #ffc107, #ffca28); color: #333; font-size: 1.6rem; box-shadow: 0 5px 20px rgba(255, 193, 7, 0.5); }
        .tile-512 { background: linear-gradient(135deg, #ffb300, #ffc107); color: #333; font-size: 1.5rem; box-shadow: 0 5px 20px rgba(255, 179, 0, 0.5); }
        .tile-1024 { background: linear-gradient(135deg, #ffa000, #ffb300); color: #333; font-size: 1.4rem; box-shadow: 0 5px 20px rgba(255, 160, 0, 0.6); }
        .tile-2048 { background: linear-gradient(135deg, #ff8f00, #ffa000); color: #333; font-size: 1.3rem; box-shadow: 0 5px 20px rgba(255, 143, 0, 0.6); }
        .tile-super { background: linear-gradient(135deg, #4a148c, #7b1fa2); color: #fff; font-size: 1.2rem; box-shadow: 0 5px 20px rgba(74, 20, 140, 0.6); }
        
        .game-explanation {
            background: rgba(255, 255, 255, 0.08);
            border-radius: 12px;
            padding: 20px;
            font-size: 1rem;
            line-height: 1.6;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
        }
        
        .game-explanation p {
            margin-bottom: 10px;
        }
        
        .highlight {
            color: #ffca28;
            font-weight: 600;
        }
        
        .keys {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin-top: 15px;
        }
        
        .key {
            background: rgba(255, 255, 255, 0.15);
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 6px;
            padding: 8px 15px;
            font-size: 1rem;
            min-width: 40px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }
        
        /* 响应式设计 */
        @media (max-width: 520px) {
            .grid {
                grid-gap: 10px;
            }
            
            .tile {
                width: calc(25% - 7.5px);
                height: calc(25% - 7.5px);
                font-size: 1.5rem;
            }
            
            .title {
                font-size: 2.2rem;
            }
            
            .score-box {
                min-width: 90px;
                padding: 10px 12px;
            }
            
            .score-value {
                font-size: 1.6rem;
            }
            
            .game-button {
                padding: 10px 15px;
                font-size: 0.9rem;
            }
            
            .tile-2, .tile-4, .tile-8 { font-size: 1.5rem; }
            .tile-16, .tile-32, .tile-64 { font-size: 1.4rem; }
            .tile-128, .tile-256 { font-size: 1.3rem; }
            .tile-512, .tile-1024 { font-size: 1.2rem; }
            .tile-2048, .tile-super { font-size: 1.1rem; }
        }
    </style>
</head>
<body>
    <!-- 粒子背景 -->
    <div class="particles" id="particles"></div>
    
    <!-- 方向指示器 -->
    <div class="direction-indicator" id="direction-indicator"></div>
    
    <div class="game-container">
        <div class="game-header">
            <div class="title">2048</div>
            <div class="scores-container">
                <div class="score-box">
                    <div class="score-title">分数</div>
                    <div class="score-value" id="score">0</div>
                </div>
                <div class="score-box">
                    <div class="score-title">最高分</div>
                    <div class="score-value" id="best-score">0</div>
                </div>
            </div>
        </div>
        
        <div class="game-intro">
            <div class="game-message" id="game-message"></div>
            <div class="game-controls">
                <button class="game-button undo" id="undo-button">
                    <i class="fas fa-undo"></i> 撤销
                </button>
                <button class="game-button" id="restart-button">
                    <i class="fas fa-redo"></i> 新游戏
                </button>
            </div>
        </div>
        
        <div class="game-grid-container">
            <div class="grid">
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>
            <div class="tile-container" id="tile-container"></div>
        </div>
        
        <div class="game-explanation">
            <p><span class="highlight">游戏规则:</span>使用键盘方向键或触摸滑动移动方块。当两个相同数字的方块碰撞时,它们会<span class="highlight">合并成一个新的方块</span>!</p>
            <p>每次移动后,会在空白位置随机生成一个2或4的方块。当得到<span class="highlight">2048</span>方块时获胜,当没有可移动的方块时游戏结束。</p>
            <div class="keys">
                <div class="key">↑</div>
                <div class="key">↓</div>
                <div class="key">←</div>
                <div class="key">→</div>
            </div>
        </div>
    </div>

    <script>
        // 游戏状态变量
        let grid = [];
        let score = 0;
        let bestScore = localStorage.getItem('bestScore') || 0;
        let gameOver = false;
        let gameWon = false;
        let tileContainer;
        let history = []; // 用于回溯功能
        const MAX_HISTORY = 5; // 最多保存5步历史
        let tiles = []; // 存储所有方块元素
        
        // 初始化游戏
        function initGame() {
            grid = Array(4).fill().map(() => Array(4).fill(0));
            score = 0;
            gameOver = false;
            gameWon = false;
            history = [];
            tiles = [];
            
            document.getElementById('score').textContent = '0';
            document.getElementById('best-score').textContent = bestScore;
            document.getElementById('game-message').textContent = '';
            document.getElementById('game-message').className = 'game-message';
            
            tileContainer = document.getElementById('tile-container');
            tileContainer.innerHTML = '';
            
            // 添加两个初始方块
            addRandomTile();
            addRandomTile();
            
            // 创建粒子背景
            createParticles();
            
            // 保存初始状态
            saveState();
        }
        
        // 创建粒子背景
        function createParticles() {
            const particlesContainer = document.getElementById('particles');
            particlesContainer.innerHTML = '';
            
            for (let i = 0; i < 80; i++) {
                const particle = document.createElement('div');
                particle.className = 'particle';
                
                // 随机位置
                particle.style.left = `${Math.random() * 100}%`;
                particle.style.top = `${Math.random() * 100}%`;
                
                // 随机动画延迟和持续时间
                particle.style.animationDelay = `${Math.random() * 15}s`;
                particle.style.animationDuration = `${10 + Math.random() * 15}s`;
                
                particlesContainer.appendChild(particle);
            }
        }
        
        // 添加随机方块
        function addRandomTile() {
            const emptyCells = [];
            
            // 收集所有空格子
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] === 0) {
                        emptyCells.push({ r, c });
                    }
                }
            }
            
            if (emptyCells.length > 0) {
                // 随机选择一个空格子
                const randIndex = Math.floor(Math.random() * emptyCells.length);
                const cell = emptyCells[randIndex];
                const value = Math.random() < 0.9 ? 2 : 4;
                
                // 更新网格
                grid[cell.r][cell.c] = value;
                
                // 创建方块元素
                createTileElement(cell.r, cell.c, value, true);
            }
        }
        
        // 创建方块元素
        function createTileElement(row, col, value, isNew = false) {
            const tile = document.createElement('div');
            tile.className = `tile tile-${value}`;
            if (isNew) tile.classList.add('tile-new');
            tile.textContent = value;
            tile.dataset.row = row;
            tile.dataset.col = col;
            tile.dataset.value = value;
            
            // 计算位置
            const cellSize = tileContainer.offsetWidth / 4;
            tile.style.left = `${col * cellSize}px`;
            tile.style.top = `${row * cellSize}px`;
            
            tileContainer.appendChild(tile);
            tiles.push(tile);
            
            return tile;
        }
        
        // 保存当前状态用于回溯
        function saveState() {
            // 只保存最近几步
            if (history.length >= MAX_HISTORY) {
                history.shift();
            }
            
            history.push({
                grid: JSON.parse(JSON.stringify(grid)),
                score: score
            });
        }
        
        // 显示方向指示器
        function showDirectionIndicator(direction) {
            const indicator = document.getElementById('direction-indicator');
            let symbol = '';
            
            switch(direction) {
                case 'left': symbol = '←'; break;
                case 'right': symbol = '→'; break;
                case 'up': symbol = '↑'; break;
                case 'down': symbol = '↓'; break;
            }
            
            indicator.textContent = symbol;
            indicator.style.animation = 'none';
            void indicator.offsetWidth; // 触发重绘
            indicator.style.animation = 'fadeDirection 0.5s ease-out';
        }
        
        // 移动方块
        function move(direction) {
            if (gameOver) return;
            
            // 显示方向指示器
            showDirectionIndicator(direction);
            
            // 保存当前状态
            saveState();
            
            let moved = false;
            
            // 根据方向处理移动
            if (direction === 'left') {
                moved = moveLeft();
            } else if (direction === 'right') {
                moved = moveRight();
            } else if (direction === 'up') {
                moved = moveUp();
            } else if (direction === 'down') {
                moved = moveDown();
            }
            
            // 如果有移动,添加新方块并检查游戏状态
            if (moved) {
                // 添加新方块前先更新显示
                updateTiles();
                addRandomTile();
                updateGameState();
            }
        }
        
        // 向左移动
        function moveLeft() {
            let moved = false;
            const moves = [];
            
            for (let r = 0; r < 4; r++) {
                // 移动方块到左侧
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] !== 0) {
                        let targetCol = c;
                        while (targetCol > 0 && grid[r][targetCol - 1] === 0) {
                            targetCol--;
                        }
                        
                        if (targetCol !== c) {
                            grid[r][targetCol] = grid[r][c];
                            grid[r][c] = 0;
                            moved = true;
                            moves.push({
                                from: { r, c },
                                to: { r, targetCol },
                                value: grid[r][targetCol]
                            });
                        }
                    }
                }
                
                // 合并相同数字
                for (let c = 0; c < 3; c++) {
                    if (grid[r][c] !== 0 && grid[r][c] === grid[r][c + 1]) {
                        const newValue = grid[r][c] * 2;
                        grid[r][c] = newValue;
                        grid[r][c + 1] = 0;
                        score += newValue;
                        moved = true;
                        
                        // 移动右侧的方块
                        for (let i = c + 1; i < 3; i++) {
                            grid[r][i] = grid[r][i + 1];
                            grid[r][i + 1] = 0;
                        }
                        
                        // 记录合并
                        moves.push({
                            from: { r, c: c + 1 },
                            to: { r, c },
                            value: newValue,
                            merged: true
                        });
                    }
                }
            }
            
            // 执行移动动画
            animateMoves(moves);
            
            return moved;
        }
        
        // 向右移动
        function moveRight() {
            let moved = false;
            const moves = [];
            
            for (let r = 0; r < 4; r++) {
                // 移动方块到右侧
                for (let c = 3; c >= 0; c--) {
                    if (grid[r][c] !== 0) {
                        let targetCol = c;
                        while (targetCol < 3 && grid[r][targetCol + 1] === 0) {
                            targetCol++;
                        }
                        
                        if (targetCol !== c) {
                            grid[r][targetCol] = grid[r][c];
                            grid[r][c] = 0;
                            moved = true;
                            moves.push({
                                from: { r, c },
                                to: { r, targetCol },
                                value: grid[r][targetCol]
                            });
                        }
                    }
                }
                
                // 合并相同数字
                for (let c = 3; c > 0; c--) {
                    if (grid[r][c] !== 0 && grid[r][c] === grid[r][c - 1]) {
                        const newValue = grid[r][c] * 2;
                        grid[r][c] = newValue;
                        grid[r][c - 1] = 0;
                        score += newValue;
                        moved = true;
                        
                        // 移动左侧的方块
                        for (let i = c - 1; i > 0; i--) {
                            grid[r][i] = grid[r][i - 1];
                            grid[r][i - 1] = 0;
                        }
                        
                        // 记录合并
                        moves.push({
                            from: { r, c: c - 1 },
                            to: { r, c },
                            value: newValue,
                            merged: true
                        });
                    }
                }
            }
            
            // 执行移动动画
            animateMoves(moves);
            
            return moved;
        }
        
        // 向上移动
        function moveUp() {
            let moved = false;
            const moves = [];
            
            for (let c = 0; c < 4; c++) {
                // 移动方块到上方
                for (let r = 0; r < 4; r++) {
                    if (grid[r][c] !== 0) {
                        let targetRow = r;
                        while (targetRow > 0 && grid[targetRow - 1][c] === 0) {
                            targetRow--;
                        }
                        
                        if (targetRow !== r) {
                            grid[targetRow][c] = grid[r][c];
                            grid[r][c] = 0;
                            moved = true;
                            moves.push({
                                from: { r, c },
                                to: { r: targetRow, c },
                                value: grid[targetRow][c]
                            });
                        }
                    }
                }
                
                // 合并相同数字
                for (let r = 0; r < 3; r++) {
                    if (grid[r][c] !== 0 && grid[r][c] === grid[r + 1][c]) {
                        const newValue = grid[r][c] * 2;
                        grid[r][c] = newValue;
                        grid[r + 1][c] = 0;
                        score += newValue;
                        moved = true;
                        
                        // 移动下方的方块
                        for (let i = r + 1; i < 3; i++) {
                            grid[i][c] = grid[i + 1][c];
                            grid[i + 1][c] = 0;
                        }
                        
                        // 记录合并
                        moves.push({
                            from: { r: r + 1, c },
                            to: { r, c },
                            value: newValue,
                            merged: true
                        });
                    }
                }
            }
            
            // 执行移动动画
            animateMoves(moves);
            
            return moved;
        }
        
        // 向下移动
        function moveDown() {
            let moved = false;
            const moves = [];
            
            for (let c = 0; c < 4; c++) {
                // 移动方块到下方
                for (let r = 3; r >= 0; r--) {
                    if (grid[r][c] !== 0) {
                        let targetRow = r;
                        while (targetRow < 3 && grid[targetRow + 1][c] === 0) {
                            targetRow++;
                        }
                        
                        if (targetRow !== r) {
                            grid[targetRow][c] = grid[r][c];
                            grid[r][c] = 0;
                            moved = true;
                            moves.push({
                                from: { r, c },
                                to: { r: targetRow, c },
                                value: grid[targetRow][c]
                            });
                        }
                    }
                }
                
                // 合并相同数字
                for (let r = 3; r > 0; r--) {
                    if (grid[r][c] !== 0 && grid[r][c] === grid[r - 1][c]) {
                        const newValue = grid[r][c] * 2;
                        grid[r][c] = newValue;
                        grid[r - 1][c] = 0;
                        score += newValue;
                        moved = true;
                        
                        // 移动上方的方块
                        for (let i = r - 1; i > 0; i--) {
                            grid[i][c] = grid[i - 1][c];
                            grid[i - 1][c] = 0;
                        }
                        
                        // 记录合并
                        moves.push({
                            from: { r: r - 1, c },
                            to: { r, c },
                            value: newValue,
                            merged: true
                        });
                    }
                }
            }
            
            // 执行移动动画
            animateMoves(moves);
            
            return moved;
        }
        
        // 执行移动动画
        function animateMoves(moves) {
            const cellSize = tileContainer.offsetWidth / 4;
            
            // 先移除所有方块的移动状态
            tiles.forEach(tile => {
                tile.classList.remove('tile-moving');
            });
            
            // 执行动画
            moves.forEach(move => {
                const tile = findTileAt(move.from.r, move.from.c);
                if (tile) {
                    tile.classList.add('tile-moving');
                    
                    // 更新位置
                    tile.style.left = `${move.to.c * cellSize}px`;
                    tile.style.top = `${move.to.r * cellSize}px`;
                    
                    // 更新数据属性
                    tile.dataset.row = move.to.r;
                    tile.dataset.col = move.to.c;
                    
                    // 如果是合并,添加合并动画
                    if (move.merged) {
                        setTimeout(() => {
                            tile.classList.add('tile-merged');
                            tile.textContent = move.value;
                            tile.className = `tile tile-${move.value} tile-merged`;
                        }, 150);
                    }
                }
            });
        }
        
        // 根据位置查找方块
        function findTileAt(row, col) {
            return tiles.find(tile => 
                parseInt(tile.dataset.row) === row && 
                parseInt(tile.dataset.col) === col
            );
        }
        
        // 更新游戏状态
        function updateGameState() {
            document.getElementById('score').textContent = score;
            
            // 更新最高分
            if (score > bestScore) {
                bestScore = score;
                localStorage.setItem('bestScore', bestScore);
                document.getElementById('best-score').textContent = bestScore;
            }
            
            // 检查是否获胜
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] === 2048) {
                        gameWon = true;
                    }
                }
            }
            
            if (gameWon) {
                document.getElementById('game-message').textContent = '恭喜!你赢了!';
                document.getElementById('game-message').classList.add('game-win');
                return;
            }
            
            // 检查是否失败
            if (!hasAvailableMoves()) {
                gameOver = true;
                document.getElementById('game-message').textContent = '游戏结束!';
                document.getElementById('game-message').classList.add('game-over');
            }
        }
        
        // 检查是否还有可移动的步数
        function hasAvailableMoves() {
            // 检查是否有空格子
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] === 0) {
                        return true;
                    }
                }
            }
            
            // 检查是否有可以合并的相邻方块
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 3; c++) {
                    if (grid[r][c] === grid[r][c + 1]) {
                        return true;
                    }
                }
            }
            
            for (let r = 0; r < 3; r++) {
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] === grid[r + 1][c]) {
                        return true;
                    }
                }
            }
            
            return false;
        }
        
        // 更新方块显示
        function updateTiles() {
            // 移除已不存在的方块
            tiles = tiles.filter(tile => {
                const r = parseInt(tile.dataset.row);
                const c = parseInt(tile.dataset.col);
                if (grid[r][c] !== parseInt(tile.dataset.value)) {
                    tile.remove();
                    return false;
                }
                return true;
            });
            
            // 添加新方块
            for (let r = 0; r < 4; r++) {
                for (let c = 0; c < 4; c++) {
                    if (grid[r][c] !== 0 && !findTileAt(r, c)) {
                        createTileElement(r, c, grid[r][c]);
                    }
                }
            }
        }
        
        // 回溯功能
        function undoMove() {
            if (history.length < 2 || gameOver || gameWon) return;
            
            // 移除当前状态
            history.pop();
            
            // 恢复上一个状态
            const prevState = history[history.length - 1];
            grid = JSON.parse(JSON.stringify(prevState.grid));
            score = prevState.score;
            
            // 更新显示
            updateGameState();
            updateTiles();
        }
        
        // 事件监听器
        document.addEventListener('keydown', (e) => {
            if (e.key === 'ArrowLeft') {
                move('left');
            } else if (e.key === 'ArrowRight') {
                move('right');
            } else if (e.key === 'ArrowUp') {
                move('up');
            } else if (e.key === 'ArrowDown') {
                move('down');
            }
        });
        
        // 触摸滑动支持
        let touchStartX, touchStartY;
        let touchStartTime;
        
        document.addEventListener('touchstart', (e) => {
            touchStartX = e.touches[0].clientX;
            touchStartY = e.touches[0].clientY;
            touchStartTime = new Date().getTime();
        });
        
        document.addEventListener('touchend', (e) => {
            if (!touchStartX || !touchStartY) return;
            
            const touchEndX = e.changedTouches[0].clientX;
            const touchEndY = e.changedTouches[0].clientY;
            const touchDuration = new Date().getTime() - touchStartTime;
            
            const dx = touchEndX - touchStartX;
            const dy = touchEndY - touchStartY;
            
            // 确定滑动方向(仅在滑动距离足够大且时间短时)
            if ((Math.abs(dx) > 20 || Math.abs(dy) > 20) && touchDuration < 500) {
                if (Math.abs(dx) > Math.abs(dy)) {
                    if (dx > 0) {
                        move('right');
                    } else {
                        move('left');
                    }
                } else {
                    if (dy > 0) {
                        move('down');
                    } else {
                        move('up');
                    }
                }
            }
            
            // 重置触摸点
            touchStartX = null;
            touchStartY = null;
        });
        
        // 新游戏按钮
        document.getElementById('restart-button').addEventListener('click', () => {
            initGame();
        });
        
        // 撤销按钮
        document.getElementById('undo-button').addEventListener('click', () => {
            undoMove();
        });
        
        // 初始化游戏
        window.onload = () => {
            initGame();
        };
    </script>
</body>
</html>