動態

詳情 返回 返回

模擬網頁中國象棋模擬對戰 - 動態 詳情

簡介
本程序有人人對戰和人機對戰,歡迎挑戰

源碼
'''
<!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>
    body { font-family: Arial, sans-serif; text-align: center; }
    .board { display: inline-block; border: 2px solid #000; }
    .row { display: flex; }
    .cell { width: 40px; height: 40px; border: 1px solid #ccc; position: relative; cursor: pointer; }
    .cell.black { background-color: #f0f0f0; }
    .piece { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-weight: bold; user-select: none; }
    .piece.red { color: #f00; }
    .piece.black { color: #000; }
    .selected { background-color: #ff9 !important; }
    .valid-move { background-color: #9f9; }
    #info { margin-top: 10px; font-size: 16px; }
    .menu { margin-bottom: 20px; padding: 10px; background-color: #f9f9f9; border-radius: 5px; display: inline-block; }
    button, select { margin: 5px; padding: 5px 10px; }
    #difficulty-selector { display: none; }
</style>

</head>
<body>

<h1>迷你象棋</h1>
<div class="menu">
    <div>
        <label>遊戲模式:</label>
        <select id="game-mode">
            <option value="human">人人對戰</option>
            <option value="ai">人機對戰</option>
        </select>
    </div>
    <div id="difficulty-selector">
        <label>難度:</label>
        <select id="difficulty">
            <option value="easy">簡單</option>
            <option value="medium">困難</option>
            <option value="hard">地獄</option>
        </select>
    </div>
    <button id="start-game">開始遊戲</button>
</div>
<div id="board" class="board"></div>
<div id="info"></div>

<script>
    const BOARD_SIZE = 10;
    const INITIAL_POSITIONS = [
        {x:0,y:9,type:'R',color:'red'},{x:1,y:9,type:'N',color:'red'},{x:2,y:9,type:'E',color:'red'},{x:3,y:9,type:'A',color:'red'},{x:4,y:9,type:'K',color:'red'},{x:5,y:9,type:'A',color:'red'},{x:6,y:9,type:'E',color:'red'},{x:7,y:9,type:'N',color:'red'},{x:8,y:9,type:'R',color:'red'},
        {x:1,y:7,type:'C',color:'red'},{x:7,y:7,type:'C',color:'red'},
        {x:0,y:6,type:'P',color:'red'},{x:2,y:6,type:'P',color:'red'},{x:4,y:6,type:'P',color:'red'},{x:6,y:6,type:'P',color:'red'},{x:8,y:6,type:'P',color:'red'},
        {x:0,y:0,type:'R',color:'black'},{x:1,y:0,type:'N',color:'black'},{x:2,y:0,type:'E',color:'black'},{x:3,y:0,type:'A',color:'black'},{x:4,y:0,type:'K',color:'black'},{x:5,y:0,type:'A',color:'black'},{x:6,y:0,type:'E',color:'black'},{x:7,y:0,type:'N',color:'black'},{x:8,y:0,type:'R',color:'black'},
        {x:1,y:2,type:'C',color:'black'},{x:7,y:2,type:'C',color:'black'},
        {x:0,y:3,type:'P',color:'black'},{x:2,y:3,type:'P',color:'black'},{x:4,y:3,type:'P',color:'black'},{x:6,y:3,type:'P',color:'black'},{x:8,y:3,type:'P',color:'black'}
    ];
    const PIECE_NAMES = {R:'車',N:'馬',E:'相',A:'士',K:'將',C:'炮',P:'兵'};
    const PIECE_VALUES = {K: 1000, A: 20, E: 20, N: 40, C: 45, R: 90, P: 10};
    
    // 位置權重表 - 基於中國象棋開局理論優化的位置價值評估
    const POSITION_WEIGHTS = {
        'red': {
            'R': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [2, 2, 2, 2, 2, 2, 2, 2, 2],
                [3, 3, 3, 3, 3, 3, 3, 3, 3],
                [4, 4, 4, 4, 4, 4, 4, 4, 4],
                [5, 5, 5, 5, 5, 5, 5, 5, 5],
                [10, 0, 0, 0, 0, 0, 0, 0, 10]
            ],
            'N': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 10, 0, 10, 0, 10, 0, 0],
                [0, 10, 0, 0, 0, 0, 0, 10, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 10, 0, 0, 0, 0, 0, 10, 0],
                [0, 0, 15, 0, 15, 0, 15, 0, 0],
                [0, 0, 0, 20, 0, 20, 0, 0, 0],
                [0, 5, 0, 0, 0, 0, 0, 5, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            'C': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [10, 0, 0, 15, 15, 15, 0, 0, 10],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            'P': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [10, 10, 10, 10, 10, 10, 10, 10, 10],
                [15, 15, 15, 15, 15, 15, 15, 15, 15],
                [20, 20, 20, 20, 20, 20, 20, 20, 20],
                [30, 30, 30, 30, 30, 30, 30, 30, 30],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ]
        },
        'black': {
            'R': [
                [10, 0, 0, 0, 0, 0, 0, 0, 10],
                [5, 5, 5, 5, 5, 5, 5, 5, 5],
                [4, 4, 4, 4, 4, 4, 4, 4, 4],
                [3, 3, 3, 3, 3, 3, 3, 3, 3],
                [2, 2, 2, 2, 2, 2, 2, 2, 2],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            'N': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 5, 0, 0, 0, 0, 0, 5, 0],
                [0, 0, 0, 20, 0, 20, 0, 0, 0],
                [0, 0, 15, 0, 15, 0, 15, 0, 0],
                [0, 10, 0, 0, 0, 0, 0, 10, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 10, 0, 0, 0, 0, 0, 10, 0],
                [0, 0, 10, 0, 10, 0, 10, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            'C': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [10, 0, 0, 15, 15, 15, 0, 0, 10],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [5, 5, 5, 10, 10, 10, 5, 5, 5],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ],
            'P': [
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [30, 30, 30, 30, 30, 30, 30, 30, 30],
                [20, 20, 20, 20, 20, 20, 20, 20, 20],
                [15, 15, 15, 15, 15, 15, 15, 15, 15],
                [10, 10, 10, 10, 10, 10, 10, 10, 10],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0]
            ]
        }
    };
    
    let board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
    let currentPlayer = 'red';
    let selectedPiece = null;
    let gameOver = false;
    let gameMode = 'human'; // 'human' or 'ai'
    let difficulty = 'easy'; // 'easy', 'medium', 'hard'
    let aiColor = 'black';
    
    // DOM元素
    const gameModeSelect = document.getElementById('game-mode');
    const difficultySelector = document.getElementById('difficulty-selector');
    const difficultySelect = document.getElementById('difficulty');
    const startGameButton = document.getElementById('start-game');
    
    // 事件監聽器
    gameModeSelect.addEventListener('change', () => {
        if (gameModeSelect.value === 'ai') {
            difficultySelector.style.display = 'block';
        } else {
            difficultySelector.style.display = 'none';
        }
    });
    
    startGameButton.addEventListener('click', () => {
        gameMode = gameModeSelect.value;
        difficulty = difficultySelect.value;
        initBoard();
    });
    
    // 初始化棋盤
    function initBoard() {
        const boardElement = document.getElementById('board');
        boardElement.innerHTML = '';
        
        // 初始化棋盤數據
        board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
        currentPlayer = 'red';
        selectedPiece = null;
        gameOver = false;
        
        for (let y = 0; y < BOARD_SIZE; y++) {
            const row = document.createElement('div');
            row.className = 'row';
            
            for (let x = 0; x < BOARD_SIZE; x++) {
                const cell = document.createElement('div');
                cell.className = `cell ${(x + y) % 2 === 1 ? 'black' : ''}`;
                cell.dataset.x = x;
                cell.dataset.y = y;
                cell.addEventListener('click', () => handleCellClick(x, y));
                
                row.appendChild(cell);
            }
            
            boardElement.appendChild(row);
        }
        
        // 放置初始棋子
        INITIAL_POSITIONS.forEach(pos => {
            board[pos.y][pos.x] = {type: pos.type, color: pos.color};
            renderPiece(pos.x, pos.y, pos.type, pos.color);
        });
        
        updateInfo();
    }
    
    // 渲染棋子
    function renderPiece(x, y, type, color) {
        const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
        if (!cell) return;
        
        while (cell.firstChild) cell.removeChild(cell.firstChild);
        
        if (type && color) {
            const piece = document.createElement('div');
            piece.className = `piece ${color}`;
            piece.textContent = PIECE_NAMES[type];
            cell.appendChild(piece);
        }
    }
    
    // 處理單元格點擊
    function handleCellClick(x, y) {
        if (gameOver || (gameMode === 'ai' && currentPlayer === aiColor)) return;
        
        if (board[y][x] && board[y][x].color === currentPlayer) {
            selectPiece(x, y);
            return;
        }
        
        if (selectedPiece) {
            const fromX = selectedPiece.x;
            const fromY = selectedPiece.y;
            
            if (isValidMove(fromX, fromY, x, y)) {
                movePiece(fromX, fromY, x, y);
                checkGameOver();
                currentPlayer = currentPlayer === 'red' ? 'black' : 'red';
                
                // 如果是人機對戰且輪到AI回合,執行AI移動
                if (gameMode === 'ai' && currentPlayer === aiColor && !gameOver) {
                    setTimeout(aiMakeMove, 500); // 延遲執行,讓玩家能看到
                }
            }
            
            deselectAll();
            updateInfo();
        }
    }
    
    // 選中棋子
    function selectPiece(x, y) {
        deselectAll();
        selectedPiece = {x, y};
        const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
        cell.classList.add('selected');
        
        showValidMoves(x, y);
    }
    
    // 取消所有選中
    function deselectAll() {
        selectedPiece = null;
        document.querySelectorAll('.cell').forEach(cell => {
            cell.classList.remove('selected', 'valid-move');
        });
    }
    
    // 顯示有效移動
    function showValidMoves(fromX, fromY) {
        for (let y = 0; y < BOARD_SIZE; y++) {
            for (let x = 0; x < BOARD_SIZE; x++) {
                if (isValidMove(fromX, fromY, x, y)) {
                    const cell = document.querySelector(`.cell[data-x="${x}"][data-y="${y}"]`);
                    cell.classList.add('valid-move');
                }
            }
        }
    }
    
    // 檢查移動是否有效
    function isValidMove(fromX, fromY, toX, toY) {
        const piece = board[fromY][fromX];
        
        if (board[toY][toX] && board[toY][toX].color === piece.color) return false;
        
        switch (piece.type) {
            case 'R': return isValidRookMove(fromX, fromY, toX, toY);
            case 'N': return isValidKnightMove(fromX, fromY, toX, toY);
            case 'E': return isValidElephantMove(fromX, fromY, toX, toY);
            case 'A': return isValidAdvisorMove(fromX, fromY, toX, toY);
            case 'K': return isValidKingMove(fromX, fromY, toX, toY);
            case 'C': return isValidCannonMove(fromX, fromY, toX, toY);
            case 'P': return isValidPawnMove(fromX, fromY, toX, toY);
            default: return false;
        }
    }
    
    // 車的移動規則
    function isValidRookMove(fromX, fromY, toX, toY) {
        if (fromX !== toX && fromY !== toY) return false;
        
        if (fromX === toX) {
            const minY = Math.min(fromY, toY) + 1;
            const maxY = Math.max(fromY, toY);
            for (let y = minY; y < maxY; y++) {
                if (board[y][fromX]) return false;
            }
        } else {
            const minX = Math.min(fromX, toX) + 1;
            const maxX = Math.max(fromX, toX);
            for (let x = minX; x < maxX; x++) {
                if (board[fromY][x]) return false;
            }
        }
        
        return true;
    }
    
    // 馬的移動規則
    function isValidKnightMove(fromX, fromY, toX, toY) {
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);
        
        if (!((dx === 1 && dy === 2) || (dx === 2 && dy === 1))) return false;
        
        if (dx === 2) {
            const midX = fromX + (toX > fromX ? 1 : -1);
            if (board[fromY][midX]) return false;
        } else {
            const midY = fromY + (toY > fromY ? 1 : -1);
            if (board[midY][fromX]) return false;
        }
        
        return true;
    }
    
    // 相/象的移動規則
    function isValidElephantMove(fromX, fromY, toX, toY) {
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);
        
        if (dx !== 2 || dy !== 2) return false;
        
        const midX = (fromX + toX) / 2;
        const midY = (fromY + toY) / 2;
        if (board[midY][midX]) return false;
        
        const riverY = 5;
        if ((board[fromY][fromX].color === 'red' && toY < riverY) || 
            (board[fromY][fromX].color === 'black' && toY > riverY)) {
            return false;
        }
        
        return true;
    }
    
    // 士的移動規則
    function isValidAdvisorMove(fromX, fromY, toX, toY) {
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);
        
        if (dx !== 1 || dy !== 1) return false;
        
        if (board[fromY][fromX].color === 'red') {
            return toX >= 3 && toX <= 5 && toY >= 7 && toY <= 9;
        } else {
            return toX >= 3 && toX <= 5 && toY >= 0 && toY <= 2;
        }
    }
    
    // 將/帥的移動規則
    function isValidKingMove(fromX, fromY, toX, toY) {
        const dx = Math.abs(toX - fromX);
        const dy = Math.abs(toY - fromY);
        
        if (!((dx === 0 && dy === 1) || (dx === 1 && dy === 0))) return false;
        
        if (board[fromY][fromX].color === 'red') {
            return toX >= 3 && toX <= 5 && toY >= 7 && toY <= 9;
        } else {
            return toX >= 3 && toX <= 5 && toY >= 0 && toY <= 2;
        }
    }
    
    // 炮的移動規則
    function isValidCannonMove(fromX, fromY, toX, toY) {
        const hasTarget = board[toY][toX] !== null;
        let obstacleCount = 0;
        
        if (fromX !== toX && fromY !== toY) return false;
        
        if (fromX === toX) {
            const minY = Math.min(fromY, toY) + 1;
            const maxY = Math.max(fromY, toY);
            for (let y = minY; y < maxY; y++) {
                if (board[y][fromX]) obstacleCount++;
            }
        } else {
            const minX = Math.min(fromX, toX) + 1;
            const maxX = Math.max(fromX, toX);
            for (let x = minX; x < maxX; x++) {
                if (board[fromY][x]) obstacleCount++;
            }
        }
        
        return (hasTarget && obstacleCount === 1) || (!hasTarget && obstacleCount === 0);
    }
    
    // 兵/卒的移動規則
    function isValidPawnMove(fromX, fromY, toX, toY) {
        const piece = board[fromY][fromX];
        const direction = piece.color === 'red' ? -1 : 1;
        const dx = toX - fromX;
        const dy = toY - fromY;
        
        const riverY = piece.color === 'red' ? 5 : 4;
        const hasCrossedRiver = (piece.color === 'red' && fromY <= riverY) || 
                               (piece.color === 'black' && fromY >= riverY);
        
        if (dx === 0 && dy === direction) return true;
        
        if (hasCrossedRiver && Math.abs(dx) === 1 && dy === 0) return true;
        
        return false;
    }
    
    // 移動棋子
    function movePiece(fromX, fromY, toX, toY) {
        const piece = board[fromY][fromX];
        board[toY][toX] = piece;
        board[fromY][fromX] = null;
        
        renderPiece(fromX, fromY, null, null);
        renderPiece(toX, toY, piece.type, piece.color);
    }
    
    // 檢查遊戲是否結束
    function checkGameOver() {
        let redKingExists = false;
        let blackKingExists = false;
        
        for (let y = 0; y < BOARD_SIZE; y++) {
            for (let x = 0; x < BOARD_SIZE; x++) {
                if (board[y][x] && board[y][x].type === 'K') {
                    if (board[y][x].color === 'red') redKingExists = true;
                    else blackKingExists = true;
                }
            }
        }
        
        if (!redKingExists) {
            gameOver = true;
            document.getElementById('info').textContent = '黑方勝利!';
        } else if (!blackKingExists) {
            gameOver = true;
            document.getElementById('info').textContent = '紅方勝利!';
        }
    }
    
    // 更新遊戲信息
    function updateInfo() {
        if (!gameOver) {
            document.getElementById('info').textContent = `${currentPlayer === 'red' ? '紅' : '黑'}方回合`;
        }
    }
    
    // AI移動
    function aiMakeMove() {
        if (gameOver) return;
        
        let bestMove = null;
        
        switch (difficulty) {
            case 'easy':
                bestMove = getEasyAIMove();
                break;
            case 'medium':
                bestMove = getMediumAIMove();
                break;
            case 'hard':
                bestMove = getHardAIMove();
                break;
        }
        
        if (bestMove) {
            movePiece(bestMove.fromX, bestMove.fromY, bestMove.toX, bestMove.toY);
            checkGameOver();
            currentPlayer = currentPlayer === 'red' ? 'black' : 'red';
            updateInfo();
        }
    }
    
    // 獲取所有可能的移動
    function getAllPossibleMoves(color) {
        const moves = [];
        
        for (let y = 0; y < BOARD_SIZE; y++) {
            for (let x = 0; x < BOARD_SIZE; x++) {
                if (board[y][x] && board[y][x].color === color) {
                    for (let toY = 0; toY < BOARD_SIZE; toY++) {
                        for (let toX = 0; toX < BOARD_SIZE; toX++) {
                            if (isValidMove(x, y, toX, toY)) {
                                moves.push({
                                    fromX: x,
                                    fromY: y,
                                    toX: toX,
                                    toY: toY
                                });
                            }
                        }
                    }
                }
            }
        }
        
        return moves;
    }
    
    // 簡單難度AI:隨機選擇一個可行的移動
    function getEasyAIMove() {
        const moves = getAllPossibleMoves(aiColor);
        if (moves.length === 0) return null;
        
        // 簡單難度:90%概率隨機移動,10%概率選擇喫子移動
        if (Math.random() < 0.9) {
            return moves[Math.floor(Math.random() * moves.length)];
        } else {
            const capturingMoves = moves.filter(move => board[move.toY][move.toX] !== null);
            return capturingMoves.length > 0 ? capturingMoves[Math.floor(Math.random() * capturingMoves.length)] : moves[Math.floor(Math.random() * moves.length)];
        }
    }
    
    // 中等難度AI:考慮基本策略
    function getMediumAIMove() {
        const moves = getAllPossibleMoves(aiColor);
        if (moves.length === 0) return null;
        
        // 評估每個移動的分數
        let bestScore = -Infinity;
        let bestMoves = [];
        
        for (const move of moves) {
            const score = evaluateMove(move);
            if (score > bestScore) {
                bestScore = score;
                bestMoves = [move];
            } else if (score === bestScore) {
                bestMoves.push(move);
            }
        }
        
        return bestMoves[Math.floor(Math.random() * bestMoves.length)];
    }
    
    // 地獄難度AI:使用優化版極小極大算法
    function getHardAIMove() {
        let bestScore = -Infinity;
        let bestMove = null;
        
        const moves = getAllPossibleMoves(aiColor);
        if (moves.length === 0) return null;
        
        // 對移動進行排序,優先評估可能更好的移動(喫子、中心位置等)
        moves.sort((a, b) => {
            const valueA = board[a.toY][a.toX] ? (PIECE_VALUES[board[a.toY][a.toX].type] || 0) : 0;
            const valueB = board[b.toY][b.toX] ? (PIECE_VALUES[board[b.toY][b.toX].type] || 0) : 0;
            return valueB - valueA;
        });
        
        // 限制最大移動評估數量
        const maxMovesToEvaluate = Math.min(10, moves.length);
        
        for (let i = 0; i < maxMovesToEvaluate; i++) {
            const move = moves[i];
            // 檢查計算時間是否過長(限制為300毫秒)
            if (Date.now() - startTime > 300) {
                console.log('AI計算超時,提前返回當前最優解');
                break;
            }
            
            // 模擬移動
            const capturedPiece = board[move.toY][move.toX];
            board[move.toY][move.toX] = board[move.fromY][move.fromX];
            board[move.fromY][move.fromX] = null;
            
            // 降低搜索深度到3層
            const score = -minimax(2, -Infinity, Infinity, aiColor === 'red' ? 'black' : 'red', startTime);
            
            // 撤銷移動
            board[move.fromY][move.fromX] = board[move.toY][move.toX];
            board[move.toY][move.toX] = capturedPiece;
            
            if (score > bestScore) {
                bestScore = score;
                bestMove = move;
            }
        }
        
        // 如果沒有找到最優解,返回第一個可行移動
        return bestMove || moves[0];
    }
    
    // 優化版極小極大算法帶Alpha-Beta剪枝
    function minimax(depth, alpha, beta, color, startTime) {
        // 檢查計算時間是否過長(限制為250毫秒)
        if (Date.now() - startTime > 250) {
            // 超時情況下返回一個快速評估的分數
            return evaluateBoardFast();
        }
        
        if (depth === 0) {
            return evaluateBoardFast();
        }
        
        const moves = getAllPossibleMoves(color);
        if (moves.length === 0) {
            // 如果沒有合法移動,檢查是否被將死
            return -10000; // 被將死,分數極低
        }
        
        // 簡化版移動排序,只基於喫子價值
        moves.sort((a, b) => {
            const valA = board[a.toY][a.toX] ? (PIECE_VALUES[board[a.toY][a.toX].type] || 0) : 0;
            const valB = board[b.toY][b.toX] ? (PIECE_VALUES[board[b.toY][b.toX].type] || 0) : 0;
            return color === aiColor ? valB - valA : valA - valB;
        });
        
        // 限制每層的搜索分支數量
        const maxBranches = Math.min(15, moves.length);
        
        if (color === aiColor) {
            let maxScore = -Infinity;
            for (let i = 0; i < maxBranches; i++) {
                const move = moves[i];
                // 模擬移動
                const capturedPiece = board[move.toY][move.toX];
                board[move.toY][move.toX] = board[move.fromY][move.fromX];
                board[move.fromY][move.fromX] = null;
                
                const score = minimax(depth - 1, alpha, beta, aiColor === 'red' ? 'black' : 'red', startTime);
                
                // 撤銷移動
                board[move.fromY][move.fromX] = board[move.toY][move.toX];
                board[move.toY][move.toX] = capturedPiece;
                
                maxScore = Math.max(maxScore, score);
                alpha = Math.max(alpha, score);
                if (beta <= alpha) {
                    break; // Beta剪枝
                }
            }
            return maxScore;
        } else {
            let minScore = Infinity;
            for (let i = 0; i < maxBranches; i++) {
                const move = moves[i];
                // 模擬移動
                const capturedPiece = board[move.toY][move.toX];
                board[move.toY][move.toX] = board[move.fromY][move.fromX];
                board[move.fromY][move.fromX] = null;
                
                const score = minimax(depth - 1, alpha, beta, aiColor, startTime);
                
                // 撤銷移動
                board[move.fromY][move.fromX] = board[move.toY][move.toX];
                board[move.toY][move.toX] = capturedPiece;
                
                minScore = Math.min(minScore, score);
                beta = Math.min(beta, score);
                if (beta <= alpha) {
                    break; // Alpha剪枝
                }
            }
            return minScore;
        }
    }
    
    // 簡化版移動評估函數(中等難度)
    function evaluateMove(move) {
        let score = 0;
        
        // 喫子加分
        const capturedPiece = board[move.toY][move.toX];
        if (capturedPiece) {
            score += PIECE_VALUES[capturedPiece.type] * 1.5;
        }
        
        // 保護自己的將/帥
        const movingPiece = board[move.fromY][move.fromX];
        if (movingPiece.type === 'K') {
            score += 10;
        }
        
        // 簡化版位置價值評估
        if (POSITION_WEIGHTS[aiColor] && POSITION_WEIGHTS[aiColor][movingPiece.type]) {
            const fromWeight = POSITION_WEIGHTS[aiColor][movingPiece.type][move.fromY][move.fromX];
            const toWeight = POSITION_WEIGHTS[aiColor][movingPiece.type][move.toY][move.toX];
            score += (toWeight - fromWeight) * 0.5;
        }
        
        // 棋子價值
        score += PIECE_VALUES[movingPiece.type];
        
        return score;
    }
    
    // 快速版棋盤評估函數(用於地獄難度)
    function evaluateBoardFast() {
        let score = 0;
        
        // 1. 簡化版棋子價值評估
        for (let y = 0; y < BOARD_SIZE; y++) {
            for (let x = 0; x < BOARD_SIZE; x++) {
                const piece = board[y][x];
                if (piece) {
                    let pieceScore = PIECE_VALUES[piece.type];
                    
                    // 2. 簡化版位置價值評估
                    if (POSITION_WEIGHTS[piece.color] && POSITION_WEIGHTS[piece.color][piece.type]) {
                        pieceScore += POSITION_WEIGHTS[piece.color][piece.type][y][x] * 0.8;
                    }
                    
                    // 3. 過河兵加成
                    if (piece.type === 'P') {
                        if ((piece.color === 'red' && y <= 4) || (piece.color === 'black' && y >= 5)) {
                            pieceScore *= 1.8;
                        }
                    }
                    
                    // 4. 根據顏色調整分數
                    if (piece.color === aiColor) {
                        score += pieceScore;
                    } else {
                        score -= pieceScore;
                    }
                }
            }
        }
        
        // 5. 簡化版將的安全性評估
        const aiKingPos = findKingPosition(aiColor);
        const playerKingPos = findKingPosition(aiColor === 'red' ? 'black' : 'red');
        
        if (aiKingPos && playerKingPos && aiKingPos.x === playerKingPos.x) {
            let hasObstacle = false;
            const minY = Math.min(aiKingPos.y, playerKingPos.y) + 1;
            const maxY = Math.max(aiKingPos.y, playerKingPos.y);
            for (let y = minY; y < maxY; y++) {
                if (board[y][aiKingPos.x]) {
                    hasObstacle = true;
                    break;
                }
            }
            if (!hasObstacle) {
                // 如果AI是黑方,紅方老將對面是優勢
                if (aiColor === 'black') {
                    score += 100;
                } else {
                    score -= 100;
                }
            }
        }
        
        return score;
    }
    
    // 找到將/帥的位置
    function findKingPosition(color) {
        for (let y = 0; y < BOARD_SIZE; y++) {
            for (let x = 0; x < BOARD_SIZE; x++) {
                if (board[y][x] && board[y][x].type === 'K' && board[y][x].color === color) {
                    return {x, y};
                }
            }
        }
        return null;
    }
    
    // 初始化遊戲
    window.onload = function() {
        // 顯示菜單,等待用户開始遊戲
        document.getElementById('info').textContent = '請選擇遊戲模式並點擊開始遊戲';
    };
</script>

</body>
</html>
'''

user avatar u_14540126 頭像 dawanzi_6278b06ec111c 頭像 xiaoxxuejishu 頭像 chiqingdezhentou 頭像 taoqix 頭像 weidelanqiu 頭像 xixu 頭像 tangge 頭像 mrbone11 頭像 xiaokang-coding 頭像 skysailstar 頭像
點贊 11 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.