linuxDo 2048 AI玩家 Plus

专为2048.linux.do设计的高性能AI

目前為 2025-07-16 提交的版本,檢視 最新版本

// ==UserScript==
// @name         linuxDo 2048 AI玩家 Plus 
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  专为2048.linux.do设计的高性能AI
// @author       littleleo
// @match        https://2048.linux.do/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    
    // 防止密码管理器干扰
    document.addEventListener('keydown', function(e) {
        e.stopImmediatePropagation();
    }, true);

    // ===================================================================================
    // 核心配置参数
    // ===================================================================================
    const MOVE_INTERVAL = 150; // 默认移动延迟(ms)
    const TARGET_SCORE = 250000; // 25万分目标
    const AI_VERSION = "v4.8 Pro";
    let moveSpeed = MOVE_INTERVAL;
    
    // 高级策略系统
    const strategies = {
        default: {
            weights: [
                [6, 5, 4, 3],
                [5, 4, 3, 2],
                [4, 3, 2, 1],
                [3, 2, 1, 0]
            ],
            emptyWeight: 2.7
        },
        aggressive: {
            weights: [
                [10, 8, 6, 4],
                [8, 6, 4, 2],
                [6, 4, 2, 1],
                [4, 2, 1, 0]
            ],
            emptyWeight: 2.0
        },
        expert: {
            weights: [
                [15, 14, 13, 12],
                [8,  9,  10, 11],
                [7,  6,  5,  4],
                [0,  1,  2,  3]
            ],
            emptyWeight: 4.0
        },
        linuxdo: {
            weights: [
                [16, 15, 14, 13],
                [9, 10, 11, 12],
                [8, 7, 6, 5],
                [1, 2, 3, 4]
            ],
            emptyWeight: 4.5
        }
    };
    
    let currentStrategy = 'linuxdo'; // 默认使用LinuxDo专用策略
    let isAiRunning = false;
    let isThinking = false;
    let gameLoopInterval = null;
    
    // 游戏统计
    let gamesPlayed = 0;
    let highestScore = 0;
    let highestTile = 0;
    let targetAchieved = false;

    // ===================================================================================
    // AI核心算法 - 完整实现
    // ===================================================================================
    
    // 移动模拟函数
    function simulateMove(board, direction) {
        let moved = false;
        const tempBoard = JSON.parse(JSON.stringify(board));

        function slide(row) {
            const arr = row.filter(val => val);
            const missing = 4 - arr.length;
            const zeros = Array(missing).fill(0);
            return arr.concat(zeros);
        }

        function combine(row) {
            for (let i = 0; i < 3; i++) {
                if (row[i] !== 0 && row[i] === row[i + 1]) {
                    row[i] *= 2;
                    row[i + 1] = 0;
                    moved = true;
                }
            }
            return row;
        }

        function operate(row) {
            row = slide(row);
            row = combine(row);
            return slide(row);
        }

        // 优化方向处理
        switch (direction) {
            case 'left':
                for (let r = 0; r < 4; r++) tempBoard[r] = operate(tempBoard[r]);
                break;
            case 'right':
                for (let r = 0; r < 4; r++) tempBoard[r] = operate(tempBoard[r].reverse()).reverse();
                break;
            case 'up':
                for (let c = 0; c < 4; c++) {
                    const column = [
                        tempBoard[0][c],
                        tempBoard[1][c],
                        tempBoard[2][c],
                        tempBoard[3][c]
                    ];
                    const newColumn = operate(column);
                    for (let r = 0; r < 4; r++) {
                        tempBoard[r][c] = newColumn[r];
                    }
                }
                break;
            case 'down':
                for (let c = 0; c < 4; c++) {
                    const column = [
                        tempBoard[3][c],
                        tempBoard[2][c],
                        tempBoard[1][c],
                        tempBoard[0][c]
                    ];
                    const newColumn = operate(column).reverse();
                    for (let r = 0; r < 4; r++) {
                        tempBoard[r][c] = newColumn[r];
                    }
                }
                break;
        }

        if (JSON.stringify(board) !== JSON.stringify(tempBoard)) {
            moved = true;
            Object.assign(board, tempBoard);
        }
        return moved;
    }

    // 游戏阶段检测
    function detectGameStage(board) {
        const tiles = board.flat();
        const maxTile = Math.max(...tiles.filter(Boolean));
        const emptyCount = 16 - tiles.filter(Boolean).length;
        const smallTiles = tiles.filter(t => t > 0 && t <= 64).length;
        
        if (maxTile >= 8192) return 'endgame';
        if (maxTile >= 4096) return 'lategame';
        if (emptyCount > 6 || smallTiles > 8) return 'earlygame';
        return 'midgame';
    }

    // 智能评估函数
    function enhancedEvaluate(b) {
        const strategy = strategies[currentStrategy];
        const stage = detectGameStage(b);
        let score = 0;
        let emptyCount = 0;
        let smoothness = 0;
        let monotonicity = 0;
        let maxTile = 0;
        let mergePossible = 0;
        let cornerBonus = 0;
        
        // 1. 基础数据收集
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (b[r][c] === 0) {
                    emptyCount++;
                } else {
                    const tileValue = b[r][c];
                    if (tileValue > maxTile) maxTile = tileValue;
                    
                    // 位置权重
                    score += Math.log2(tileValue) * strategy.weights[r][c];
                    
                    // 角落大值奖励
                    if ((r === 0 || r === 3) && (c === 0 || c === 3) && tileValue >= 1024) {
                        cornerBonus += tileValue * 0.5;
                    }
                    
                    // 平滑度评估
                    if (c < 3 && b[r][c+1] !== 0) {
                        const diff = Math.abs(Math.log2(tileValue) - Math.log2(b[r][c+1]));
                        smoothness -= diff;
                        if (diff === 0) mergePossible++;
                    }
                    if (r < 3 && b[r+1][c] !== 0) {
                        const diff = Math.abs(Math.log2(tileValue) - Math.log2(b[r+1][c]));
                        smoothness -= diff;
                        if (diff === 0) mergePossible++;
                    }
                }
            }
        }
        
        // 2. 阶段特定策略
        if (stage === 'earlygame') {
            // 早期游戏:空格优先
            score += emptyCount * 4.5;
        } else if (stage === 'midgame') {
            // 中期游戏:平衡发展
            score += emptyCount * 3.0;
            score += monotonicity * 1.5;
        } else if (stage === 'lategame') {
            // 后期游戏:大值保护
            score += maxTile * 2.5;
            score += cornerBonus;
            // 8192保护机制
            score += avoidLargeTileMerge(b, maxTile) * 3.0;
        } else {
            // 终局:防合并策略
            score += avoidLargeTileMerge(b, maxTile) * 5.0;
        }
        
        // 3. 通用评估因素
        score += smoothness * 1.5;
        score += mergePossible * 2.0;
        score += emptyCount * strategy.emptyWeight;
        
        return score;
    }
    
    // 大值防合并算法
    function avoidLargeTileMerge(board, maxTile) {
        if (maxTile < 4096) return 0;
        
        let riskScore = 0;
        const largeTiles = [];
        
        // 找出所有大值方块位置
        for (let r = 0; r < 4; r++) {
            for (let c = 0; c < 4; c++) {
                if (board[r][c] >= 2048) {
                    largeTiles.push({r, c, value: board[r][c]});
                }
            }
        }
        
        // 评估合并风险
        for (let i = 0; i < largeTiles.length; i++) {
            for (let j = i + 1; j < largeTiles.length; j++) {
                const tileA = largeTiles[i];
                const tileB = largeTiles[j];
                
                if (tileA.value === tileB.value) {
                    const distR = Math.abs(tileA.r - tileB.r);
                    const distC = Math.abs(tileA.c - tileB.c);
                    
                    // 相邻高风险
                    if ((distR === 1 && distC === 0) || (distR === 0 && distC === 1)) {
                        riskScore -= 50000;
                    }
                    // 同排/同列中风险
                    else if (distR === 0 || distC === 0) {
                        riskScore -= 20000;
                    }
                }
            }
        }
        
        return riskScore;
    }

    // 获取最佳移动
    function getNextMove(board) {
        const directions = {up: 'ArrowUp', right: 'ArrowRight', down: 'ArrowDown', left: 'ArrowLeft'};
        let bestScore = -Infinity;
        let bestDirection = 'ArrowRight';

        for (const dirKey in directions) {
            const simBoard = JSON.parse(JSON.stringify(board));
            if (simulateMove(simBoard, dirKey)) {
                const moveScore = enhancedEvaluate(simBoard);
                if (moveScore > bestScore) {
                    bestScore = moveScore;
                    bestDirection = directions[dirKey];
                }
            }
        }
        return bestDirection;
    }

    // ===================================================================================
    // 游戏执行引擎 - 完整实现
    // ===================================================================================
    async function attemptMove(direction) {
        const stateBefore = JSON.stringify(window.canvasGame.board);
        document.body.dispatchEvent(new KeyboardEvent('keydown', { key: direction, bubbles: true }));
        return new Promise(resolve => {
            const startTime = Date.now();
            const checkInterval = setInterval(() => {
                if (JSON.stringify(window.canvasGame.board) !== stateBefore) {
                    clearInterval(checkInterval);
                    resolve(true);
                } else if (Date.now() - startTime > 500) {
                    clearInterval(checkInterval);
                    resolve(false);
                }
            }, 50);
        });
    }

    async function executeThinkCycle() {
        if (isThinking || !isAiRunning) return;
        
        // 游戏结束检测
        if (window.canvasGame.gameOver || (window.canvasGame.victory && !window.canvasGame.keepPlaying)) {
            const score = window.canvasGame.score;
            const maxTile = window.canvasGame.maxTile;
            
            console.log(`🎉 游戏结束! 得分: ${score} | 最大方块: ${maxTile}`);
            
            // 更新统计
            gamesPlayed++;
            if (score > highestScore) {
                highestScore = score;
                if (score >= TARGET_SCORE) {
                    targetAchieved = true;
                    console.log(`🏆 达成目标分数: ${TARGET_SCORE}`);
                }
            }
            if (maxTile > highestTile) highestTile = maxTile;
            
            // 更新UI
            updateStatsUI();
            
            // 停止AI
            isAiRunning = false;
            clearInterval(gameLoopInterval);
            
            // 启用按钮
            const autoPlayBtn = document.getElementById('auto-play-btn');
            if (autoPlayBtn) {
                autoPlayBtn.disabled = false;
                autoPlayBtn.style.backgroundColor = '#27ae60';
                autoPlayBtn.textContent = 'AI自动游戏';
            }
            
            return;
        }

        isThinking = true;

        try {
            const board = window.canvasGame.board;
            const bestMove = getNextMove(board);
            
            if (!await attemptMove(bestMove)) {
                // 备用移动方案
                const fallbackMoves = ['ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp'];
                for(const move of fallbackMoves) {
                    if (await attemptMove(move)) break;
                }
            }
        } catch (e) {
            console.error("AI执行错误:", e);
        } finally {
            isThinking = false;
        }
    }
    
    // ===================================================================================
    // 用户界面与控制 - 完整实现
    // ===================================================================================
    function addControlPanel() {
        if (document.getElementById('ai-control-panel')) return;
        const gameContainer = document.querySelector('.game-container');
        if (!gameContainer) { setTimeout(addControlPanel, 500); return; };
        
        // 创建控制面板
        const panel = document.createElement('div');
        panel.id = 'ai-control-panel';
        panel.style.cssText = `
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(255, 255, 255, 0.9);
            padding: 15px;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 1000;
            font-family: Arial, sans-serif;
            min-width: 250px;
        `;
        
        panel.innerHTML = `
            <h3 style="margin-top:0; color: #776e65;">2048 AI ${AI_VERSION}</h3>
            <div style="margin-bottom:15px;">
                <button id="auto-play-btn" class="ai-control-btn" style="padding:10px 15px; background:#27ae60; color:white; border:none; border-radius:4px; cursor:pointer; font-weight:bold;">
                    ▶ AI自动游戏
                </button>
            </div>
            <div id="ai-stats" style="font-size:13px; line-height:1.5; margin-bottom:15px;">
                <div>游戏次数: <span id="games-count">0</span></div>
                <div>最高分数: <span id="high-score">0</span></div>
                <div>最大方块: <span id="max-tile">0</span></div>
                <div>目标进度: <span id="target-progress">0%</span></div>
            </div>
            <div style="margin-bottom:10px;">
                <label style="display:block; margin-bottom:8px; font-size:14px;">
                    速度控制:
                    <input type="range" id="speed-slider" min="50" max="500" value="${moveSpeed}" style="width:100%;">
                    <span id="speed-value">${moveSpeed}ms</span>
                </label>
            </div>
            <div>
                <label style="display:block; margin-bottom:8px; font-size:14px;">
                    游戏策略:
                    <select id="strategy-select" style="width:100%; padding:5px; margin-top:5px;">
                        ${Object.keys(strategies).map(strat => 
                            `<option value="${strat}" ${strat === currentStrategy ? 'selected' : ''}>${strat.charAt(0).toUpperCase() + strat.slice(1)}</option>`
                        ).join('')}
                    </select>
                </label>
            </div>
            <div style="margin-top:10px; text-align:center; font-size:12px; color:#777;">
                <span>目标分数: ${TARGET_SCORE.toLocaleString()}</span>
            </div>
        `;
        
        gameContainer.appendChild(panel);
        
        // 添加事件监听
        document.getElementById('auto-play-btn').addEventListener('click', toggleAI);
        document.getElementById('speed-slider').addEventListener('input', function() {
            moveSpeed = parseInt(this.value);
            document.getElementById('speed-value').textContent = moveSpeed + 'ms';
            if (isAiRunning) {
                clearInterval(gameLoopInterval);
                gameLoopInterval = setInterval(executeThinkCycle, moveSpeed);
            }
        });
        
        document.getElementById('strategy-select').addEventListener('change', function() {
            currentStrategy = this.value;
        });
    }
    
    function updateStatsUI() {
        if (!document.getElementById('games-count')) return;
        
        document.getElementById('games-count').textContent = gamesPlayed;
        document.getElementById('high-score').textContent = highestScore;
        document.getElementById('max-tile').textContent = highestTile || 0;
        
        const progress = Math.min(100, Math.round((highestScore / TARGET_SCORE) * 100));
        const progressEl = document.getElementById('target-progress');
        progressEl.textContent = `${progress}%`;
        progressEl.style.color = progress > 90 ? '#27ae60' : 
                               progress > 50 ? '#f39c12' : '#e74c3c';
        progressEl.style.fontWeight = progress > 80 ? 'bold' : 'normal';
    }
    
function toggleAI() {
    const button = document.getElementById('auto-play-btn');
    
    if (isAiRunning) {
        // 停止AI
        isAiRunning = false;
        clearInterval(gameLoopInterval);
        button.style.backgroundColor = '#27ae60';
        button.textContent = '▶ AI自动游戏';
        console.log('AI已停止');
    } else {
        // 检查游戏状态
        if (window.canvasGame.gameOver || (window.canvasGame.victory && !window.canvasGame.keepPlaying)) {
            alert("游戏已结束! 请先点击'新游戏'按钮");
            return;
        }
        
        // 启动AI
        isAiRunning = true;
        button.style.backgroundColor = '#e74c3c';
        button.textContent = '■ 停止AI';
        console.log('AI开始运行...');
        
        // 启动游戏循环
        gameLoopInterval = setInterval(executeThinkCycle, moveSpeed);
    }
}

// ===================================================================================
// 初始化函数 - 确保游戏加载后执行
// ===================================================================================
function initializeAI() {
    // 等待游戏加载完成
    if (typeof window.canvasGame === 'undefined' || !window.canvasGame.board) {
        setTimeout(initializeAI, 500);
        return;
    }
    
    console.log('2048.linux.do AI加载成功!');
    
    // 添加控制面板
    addControlPanel();
    
    // 初始化统计
    updateStatsUI();
    
    // 添加新游戏监听
    document.querySelector('.new-game-btn')?.addEventListener('click', () => {
        if (isAiRunning) {
            isAiRunning = false;
            clearInterval(gameLoopInterval);
            const button = document.getElementById('auto-play-btn');
            if (button) {
                button.style.backgroundColor = '#27ae60';
                button.textContent = '▶ AI自动游戏';
            }
        }
    });
}

// ===================================================================================
// 启动脚本
// ===================================================================================
(function() {
    // 防止重复初始化
    if (window.AI_LOADED) return;
    window.AI_LOADED = true;
    
    console.log(`2048 AI ${AI_VERSION} 加载中,目标分数: ${TARGET_SCORE.toLocaleString()}`);
    
    // 开始初始化
    initializeAI();
})
})();