当前位置: 首页 > news >正文

11.10 脚本网页 中国象棋2版

a. 只要一个页面就能运行。算法没写在后端。

b.优化了注释,增加了切换背景

c.  「可选」termux 运行服务器

 

 <!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 id="dynamicStyles"></style>

</head>

<body>

    <!-- 模式选择界面 -->

    <div class="mode-selection" id="modeSelection">

        <div class="mode-box">

            <h2>选择游戏模式</h2>

            <button class="mode-button" onclick="startGame('pvp')">双人对战</button>

            <button class="mode-button" onclick="startGame('ai')">AI对战</button>

        </div>

    </div>

 

    <!-- 游戏主界面 -->

    <div class="game-container">

        <h1>中国象棋</h1>

        

        <!-- 棋盘区域 -->

        <div class="board" id="board">

            <div class="board-lines">

                <!-- 横线 -->

                <div class="horizontal-line" style="top: 0%;"></div>

                <div class="horizontal-line" style="top: 10%;"></div>

                <div class="horizontal-line" style="top: 20%;"></div>

                <div class="horizontal-line" style="top: 30%;"></div>

                <div class="horizontal-line" style="top: 40%;"></div>

                <div class="horizontal-line" style="top: 50%;"></div>

                <div class="horizontal-line" style="top: 60%;"></div>

                <div class="horizontal-line" style="top: 70%;"></div>

                <div class="horizontal-line" style="top: 80%;"></div>

                <div class="horizontal-line" style="top: 90%;"></div>

                <div class="horizontal-line" style="top: 100%;"></div>

                

                <!-- 竖线 -->

                <div class="vertical-line" style="left: 0%;"></div>

                <div class="vertical-line" style="left: 12.5%;"></div>

                <div class="vertical-line" style="left: 25%;"></div>

                <div class="vertical-line" style="left: 37.5%;"></div>

                <div class="vertical-line" style="left: 50%;"></div>

                <div class="vertical-line" style="left: 62.5%;"></div>

                <div class="vertical-line" style="left: 75%;"></div>

                <div class="vertical-line" style="left: 87.5%;"></div>

                <div class="vertical-line" style="left: 100%;"></div>

                

                <!-- 楚河汉界 -->

                <div class="river"></div>

                

                <!-- 九宫格斜线 -->

                <div class="diagonal" style="left: 37.5%; top: 0%; transform: rotate(45deg);"></div>

                <div class="diagonal" style="left: 87.5%; top: 0%; transform: rotate(-45deg);"></div>

                <div class="diagonal" style="left: 37.5%; top: 75%; transform: rotate(-45deg);"></div>

                <div class="diagonal" style="left: 87.5%; top: 75%; transform: rotate(45deg);"></div>

            </div>

        </div>

        

        <!-- 控制按钮区域 -->

        <div class="controls">

            <button id="resetBtn" onclick="resetGame()">重新开始</button>

            <button id="rulesBtn" onclick="showRules()">规则说明</button>

            <button id="undoBtn" onclick="undoMove()">悔棋</button>

            <button id="hintBtn" onclick="getHint()">提示走法</button>

        </div>

        

        <!-- 状态显示区域 -->

        <div class="status">

            当前玩家:<span id="currentPlayer" class="current-player">红方</span>

            <span id="gameMode" style="margin-left: 20px; color: #666;"></span>

        </div>

        

        <!-- 提示信息区域 -->

        <div class="hint-text" id="hintText"></div>

        

        <!-- 走棋记录区域 -->

        <div class="move-history" id="moveHistory">

            <h4>走棋记录</h4>

            <div id="moveList"></div>

        </div>

    </div>

 

    <!-- 背景切换按钮 -->

    <button id="bgChangeBtn" onclick="changeBackground()" title="切换背景">🎨</button>

 

    <script>

        // 一. 配置变量

        const CONFIG = {

            // 1. 棋盘配置

            BOARD_WIDTH: 9,

            BOARD_HEIGHT: 10,

            

            // 2. 棋子类型

            PIECE_TYPES: {

                SHUAI: '帅', SHI: '士', XIANG: '相', MA: '马',

                JU: '车', PAO: '炮', BING: '兵'

            },

            

            // 3. 背景颜色配置

            BACKGROUNDS: [

                'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',

                'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',

                'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',

                'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',

                'linear-gradient(135deg, #fa709a 0%, #fee140 100%)',

                'linear-gradient(135deg, #30cfd0 0%, #330867 100%)',

                'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)',

                'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)',

                'linear-gradient(135deg, #fbc2eb 0%, #a6c1ee 100%)',

                'linear-gradient(135deg, #fdcbf1 0%, #e6dee9 100%)'

            ],

            

            // 4. 棋子价值

            PIECE_VALUES: {

                '兵': 10, '卒': 10, '炮': 30, '马': 30, '相': 20, '象': 20,

                '士': 20, '仕': 20, '车': 50, '車': 50, '帅': 1000, '将': 1000

            },

            

            // 5. CSS样式模板

            CSS_TEMPLATE: `

                /* 基础样式 */

                body {

                    display: flex;

                    justify-content: center;

                    align-items: center;

                    min-height: 100vh;

                    margin: 0;

                    padding: 10px;

                    background: {{BACKGROUND}};

                    font-family: Arial, sans-serif;

                    box-sizing: border-box;

                }

                .game-container {

                    text-align: center;

                    max-width: 100vw;

                    overflow-x: auto;

                }

                

                /* 模式选择弹窗 */

                .mode-selection {

                    position: fixed;

                    top: 0;

                    left: 0;

                    width: 100%;

                    height: 100%;

                    background-color: rgba(0,0,0,0.7);

                    display: flex;

                    justify-content: center;

                    align-items: center;

                    z-index: 1000;

                }

                .mode-box {

                    background-color: white;

                    padding: 30px;

                    border-radius: 10px;

                    box-shadow: 0 0 20px rgba(0,0,0,0.5);

                    max-width: 90vw;

                }

                .mode-box h2 {

                    margin-bottom: 20px;

                    color: #8b4513;

                }

                .mode-button {

                    display: block;

                    width: 200px;

                    margin: 10px auto;

                    padding: 15px;

                    font-size: 18px;

                    background-color: #8b4513;

                    color: white;

                    border: none;

                    border-radius: 5px;

                    cursor: pointer;

                }

                .mode-button:hover {

                    background-color: #a0522d;

                }

                

                /* 棋盘样式 */

                .board {

                    position: relative;

                    width: 90vw;

                    max-width: 600px;

                    height: calc(90vw * 1.1);

                    max-height: 660px;

                    background-color: #f9d4b4;

                    border: 3px solid #8b4513;

                    margin: 20px auto;

                    box-shadow: 0 0 20px rgba(0,0,0,0.3);

                }

                @media (min-width: 768px) {

                    .board {

                        width: 600px;

                        height: 660px;

                    }

                }

                

                /* 棋子样式 */

                .piece {

                    position: absolute;

                    border-radius: 50%;

                    font-weight: bold;

                    display: flex;

                    align-items: center;

                    justify-content: center;

                    cursor: pointer;

                    transition: all 0.3s ease;

                    z-index: 10;

                    user-select: none;

                }

                .piece.red {

                    background: radial-gradient(circle at 30% 30%, #ff6b6b, #cc0000);

                    color: #fff;

                    border: 2px solid #990000;

                    box-shadow: 2px 2px 4px rgba(0,0,0,0.3);

                }

                .piece.black {

                    background: radial-gradient(circle at 30% 30%, #666, #000);

                    color: #fff;

                    border: 2px solid #000;

                    box-shadow: 2px 2px 4px rgba(0,0,0,0.3);

                }

                .piece.selected {

                    transform: scale(1.1);

                    box-shadow: 0 0 20px #ffff00, 2px 2px 4px rgba(0,0,0,0.3);

                    border-color: #ffff00;

                }

                .piece.hint {

                    animation: pulse 1s infinite;

                }

                @keyframes pulse {

                    0% { transform: scale(1); }

                    50% { transform: scale(1.15); }

                    100% { transform: scale(1); }

                }

                

                /* 棋盘网格样式 */

                .grid {

                    position: absolute;

                    cursor: pointer;

                    z-index: 1;

                }

                

                /* 棋盘线条响应式 */

                .board-lines {

                    position: absolute;

                    top: 5vw;

                    left: 5vw;

                    width: 80vw;

                    max-width: 540px;

                    height: calc(80vw * 1.11);

                    max-height: 600px;

                }

                @media (min-width: 768px) {

                    .board-lines {

                        top: 30px;

                        left: 30px;

                        width: 540px;

                        height: 600px;

                    }

                }

                .horizontal-line {

                    position: absolute;

                    width: 80vw;

                    max-width: 540px;

                    height: 1px;

                    background-color: #000;

                }

                @media (min-width: 768px) {

                    .horizontal-line {

                        width: 540px;

                    }

                }

                .vertical-line {

                    position: absolute;

                    width: 1px;

                    height: calc(80vw * 1.11);

                    max-height: 600px;

                    background-color: #000;

                }

                @media (min-width: 768px) {

                    .vertical-line {

                        height: 600px;

                    }

                }

                .river {

                    position: absolute;

                    top: calc(45vw - 5vw);

                    left: 5vw;

                    width: 80vw;

                    max-width: 540px;

                    height: 10vw;

                    max-height: 60px;

                    background-color: rgba(135, 206, 235, 0.3);

                    pointer-events: none;

                }

                @media (min-width: 768px) {

                    .river {

                        top: 270px;

                        left: 30px;

                        width: 540px;

                        height: 60px;

                    }

                }

                

                /* 控制按钮样式 */

                .controls {

                    margin-top: 20px;

                    display: flex;

                    flex-wrap: wrap;

                    justify-content: center;

                    gap: 10px;

                }

                button {

                    padding: 10px 20px;

                    font-size: 16px;

                    background-color: #8b4513;

                    color: white;

                    border: none;

                    border-radius: 5px;

                    cursor: pointer;

                    margin: 5px;

                }

                button:hover {

                    background-color: #a0522d;

                }

                

                /* 状态显示样式 */

                .status {

                    margin-top: 10px;

                    font-size: 18px;

                    font-weight: bold;

                }

                .hint-text {

                    margin-top: 10px;

                    font-size: 14px;

                    color: #666;

                    min-height: 20px;

                }

                

                /* 走棋记录样式 */

                .move-history {

                    margin-top: 20px;

                    max-height: 150px;

                    overflow-y: auto;

                    background-color: rgba(255, 255, 255, 0.5);

                    padding: 10px;

                    border-radius: 5px;

                    width: 90vw;

                    max-width: 300px;

                    margin-left: auto;

                    margin-right: auto;

                }

                .move-item {

                    font-size: 12px;

                    margin: 2px 0;

                    padding: 2px 5px;

                    background-color: rgba(255, 255, 255, 0.8);

                    border-radius: 3px;

                }

                .move-item.red {

                    color: #cc0000;

                }

                .move-item.black {

                    color: #000;

                }

                

                /* 背景切换按钮 */

                #bgChangeBtn {

                    position: fixed;

                    bottom: 20px;

                    right: 20px;

                    width: 40px;

                    height: 40px;

                    border-radius: 50%;

                    background: rgba(255, 255, 255, 0.8);

                    border: 2px solid #8b4513;

                    cursor: pointer;

                    font-size: 20px;

                    display: flex;

                    align-items: center;

                    justify-content: center;

                    z-index: 999;

                    transition: all 0.3s ease;

                }

                #bgChangeBtn:hover {

                    transform: scale(1.1);

                    background: rgba(255, 255, 255, 1);

                }

            `

        };

 

        // 二. 游戏状态变量

        let board = [];

        let selectedPiece = null;

        let currentPlayer = 'red';

        let gameOver = false;

        let moveHistory = [];

        let gameMode = '';

        let aiThinking = false;

        let currentBgIndex = 0;

 

        // 三. 初始化CSS样式

        function initStyles() {

            const styleElement = document.getElementById('dynamicStyles');

            styleElement.textContent = CONFIG.CSS_TEMPLATE.replace('{{BACKGROUND}}', CONFIG.BACKGROUNDS[currentBgIndex]);

        }

 

        // 四. 背景切换功能

        function changeBackground() {

            currentBgIndex = (currentBgIndex + 1) % CONFIG.BACKGROUNDS.length;

            const styleElement = document.getElementById('dynamicStyles');

            styleElement.textContent = CONFIG.CSS_TEMPLATE.replace('{{BACKGROUND}}', CONFIG.BACKGROUNDS[currentBgIndex]);

        }

 

        // 五. 棋盘初始化

        function initBoard() {

            board = Array(CONFIG.BOARD_HEIGHT).fill(null).map(() => Array(CONFIG.BOARD_WIDTH).fill(null));

            

            // 1. 红方棋子初始位置

            const redPieces = [

                {type: CONFIG.PIECE_TYPES.JU, row: 9, col: 0, player: 'red'},

                {type: CONFIG.PIECE_TYPES.MA, row: 9, col: 1, player: 'red'},

                {type: CONFIG.PIECE_TYPES.XIANG, row: 9, col: 2, player: 'red'},

                {type: CONFIG.PIECE_TYPES.SHI, row: 9, col: 3, player: 'red'},

                {type: CONFIG.PIECE_TYPES.SHUAI, row: 9, col: 4, player: 'red'},

                {type: CONFIG.PIECE_TYPES.SHI, row: 9, col: 5, player: 'red'},

                {type: CONFIG.PIECE_TYPES.XIANG, row: 9, col: 6, player: 'red'},

                {type: CONFIG.PIECE_TYPES.MA, row: 9, col: 7, player: 'red'},

                {type: CONFIG.PIECE_TYPES.JU, row: 9, col: 8, player: 'red'},

                {type: CONFIG.PIECE_TYPES.PAO, row: 7, col: 1, player: 'red'},

                {type: CONFIG.PIECE_TYPES.PAO, row: 7, col: 7, player: 'red'},

                {type: CONFIG.PIECE_TYPES.BING, row: 6, col: 0, player: 'red'},

                {type: CONFIG.PIECE_TYPES.BING, row: 6, col: 2, player: 'red'},

                {type: CONFIG.PIECE_TYPES.BING, row: 6, col: 4, player: 'red'},

                {type: CONFIG.PIECE_TYPES.BING, row: 6, col: 6, player: 'red'},

                {type: CONFIG.PIECE_TYPES.BING, row: 6, col: 8, player: 'red'}

            ];

            

            // 2. 黑方棋子初始位置

            const blackPieces = [

                {type: CONFIG.PIECE_TYPES.JU, row: 0, col: 0, player: 'black'},

                {type: CONFIG.PIECE_TYPES.MA, row: 0, col: 1, player: 'black'},

                {type: CONFIG.PIECE_TYPES.XIANG, row: 0, col: 2, player: 'black'},

                {type: CONFIG.PIECE_TYPES.SHI, row: 0, col: 3, player: 'black'},

                {type: CONFIG.PIECE_TYPES.SHUAI, row: 0, col: 4, player: 'black'},

                {type: CONFIG.PIECE_TYPES.SHI, row: 0, col: 5, player: 'black'},

                {type: CONFIG.PIECE_TYPES.XIANG, row: 0, col: 6, player: 'black'},

                {type: CONFIG.PIECE_TYPES.MA, row: 0, col: 7, player: 'black'},

                {type: CONFIG.PIECE_TYPES.JU, row: 0, col: 8, player: 'black'},

                {type: CONFIG.PIECE_TYPES.PAO, row: 2, col: 1, player: 'black'},

                {type: CONFIG.PIECE_TYPES.PAO, row: 2, col: 7, player: 'black'},

                {type: CONFIG.PIECE_TYPES.BING, row: 3, col: 0, player: 'black'},

                {type: CONFIG.PIECE_TYPES.BING, row: 3, col: 2, player: 'black'},

                {type: CONFIG.PIECE_TYPES.BING, row: 3, col: 4, player: 'black'},

                {type: CONFIG.PIECE_TYPES.BING, row: 3, col: 6, player: 'black'},

                {type: CONFIG.PIECE_TYPES.BING, row: 3, col: 8, player: 'black'}

            ];

            

            // 3. 将所有棋子放置到棋盘上

            [...redPieces, ...blackPieces].forEach(piece => {

                board[piece.row][piece.col] = piece;

            });

        }

 

        // 六. 棋盘渲染

        function getCellSize() {

            const board = document.getElementById('board');

            return board.offsetWidth / CONFIG.BOARD_WIDTH;

        }

 

        function renderBoard() {

            const boardElement = document.getElementById('board');

            const cellSize = getCellSize();

            const pieceSize = Math.round(cellSize * 0.70);

            const pieceOff = Math.round((cellSize - pieceSize) / 2);

            

            // 1. 清空旧内容

            boardElement.querySelectorAll('.piece, .grid').forEach(el => el.remove());

            

            // 2. 创建点击格子

            for (let row = 0; row < CONFIG.BOARD_HEIGHT; row++) {

                for (let col = 0; col < CONFIG.BOARD_WIDTH; col++) {

                    const grid = document.createElement('div');

                    grid.className = 'grid';

                    grid.style.left = `${col * cellSize}px`;

                    grid.style.top = `${row * cellSize}px`;

                    grid.style.width = `${cellSize}px`;

                    grid.style.height = `${cellSize}px`;

                    grid.dataset.row = row;

                    grid.dataset.col = col;

                    grid.onclick = () => handleGridClick(row, col);

                    boardElement.appendChild(grid);

                }

            }

            

            // 3. 创建棋子

            for (let row = 0; row < CONFIG.BOARD_HEIGHT; row++) {

                for (let col = 0; col < CONFIG.BOARD_WIDTH; col++) {

                    const piece = board[row][col];

                    if (!piece) continue;

                    

                    const el = document.createElement('div');

                    el.className = `piece ${piece.player}`;

                    el.textContent = piece.type;

                    el.style.left = `${col * cellSize + pieceOff}px`;

                    el.style.top = `${row * cellSize + pieceOff}px`;

                    el.style.width = `${pieceSize}px`;

                    el.style.height = `${pieceSize}px`;

                    el.style.fontSize = `${Math.round(pieceSize * 0.5)}px`;

                    el.dataset.row = row;

                    el.dataset.col = col;

                    el.onclick = (e) => {

                        e.stopPropagation();

                        handlePieceClick(row, col);

                    };

                    boardElement.appendChild(el);

                }

            }

            

            // 4. 调整棋盘线位置

            const lines = document.querySelector('.board-lines');

            if (lines) {

                lines.style.left = `${cellSize / 2}px`;

                lines.style.top = `${cellSize / 2}px`;

                lines.style.width = `${cellSize * (CONFIG.BOARD_WIDTH - 1)}px`;

                lines.style.height = `${cellSize * (CONFIG.BOARD_HEIGHT - 1)}px`;

            }

        }

 

        // 七. 事件处理

        function handlePieceClick(row, col) {

            if (gameOver || aiThinking) return;

            

            const piece = board[row][col];

            if (!piece) return;

            

            // 1. 已选中己方棋子,再点对方棋子→直接吃

            if (selectedPiece && piece.player !== currentPlayer) {

                if (isValidMove(selectedPiece.row, selectedPiece.col, row, col)) {

                    movePiece(selectedPiece.row, selectedPiece.col, row, col);

                    if (gameMode === 'ai' && currentPlayer === 'black' && !gameOver) {

                        setTimeout(() => aiMove(), 500);

                    }

                }

                return;

            }

            

            // 2. 没选中己方棋子,点对方棋子→自动找能吃它的己方棋子

            if (piece.player !== currentPlayer) {

                for (let r = 0; r < CONFIG.BOARD_HEIGHT; r++) {

                    for (let c = 0; c < CONFIG.BOARD_WIDTH; c++) {

                        const my = board[r][c];

                        if (my && my.player === currentPlayer && isValidMove(r, c, row, col)) {

                            movePiece(r, c, row, col);

                            if (gameMode === 'ai' && currentPlayer === 'black' && !gameOver) {

                                setTimeout(() => aiMove(), 500);

                            }

                            return;

                        }

                    }

                }

                return;

            }

            

            // 3. 点己方棋子→正常选中

            clearSelection();

            selectedPiece = {row, col, piece};

            highlightPiece(row, col);

            showValidMoves(row, col);

        }

 

        function handleGridClick(row, col) {

            if (gameOver || !selectedPiece || aiThinking) return;

            

            const targetPiece = board[row][col];

            if (targetPiece && targetPiece.player === currentPlayer) {

                handlePieceClick(row, col);

                return;

            }

            

            if (isValidMove(selectedPiece.row, selectedPiece.col, row, col)) {

                movePiece(selectedPiece.row, selectedPiece.col, row, col);

                if (gameMode === 'ai' && currentPlayer === 'black' && !gameOver) {

                    setTimeout(() => aiMove(), 500);

                }

            }

        }

 

        // 八. AI 相关功能

        function aiMove() {

            if (gameOver || aiThinking) return;

            

            aiThinking = true;

            document.getElementById('hintText').textContent = 'AI 正在思考...';

            

            setTimeout(() => {

                const bestMove = findBestMove(3);

                if (bestMove) {

                    movePiece(bestMove.from.row, bestMove.from.col, bestMove.to.row, bestMove.to.col);

                }

                aiThinking = false;

            }, 1000);

        }

 

        function findBestMove(depth) {

            const possibleMoves = getAllPossibleMoves('black');

            if (possibleMoves.length === 0) return null;

            

            let bestMove = null;

            let bestScore = -Infinity;

            

            for (const move of possibleMoves) {

                const moveData = executeMove(move);

                const score = minimax(depth - 1, -Infinity, Infinity, false);

                undoMoveData(moveData);

                

                if (score > bestScore) {

                    bestScore = score;

                    bestMove = move;

                }

            }

            

            return bestMove;

        }

 

        function minimax(depth, alpha, beta, isMaximizing) {

            if (depth === 0 || gameOver) {

                return evaluateBoard();

            }

            

            const player = isMaximizing ? 'black' : 'red';

            const possibleMoves = getAllPossibleMoves(player);

            

            if (isMaximizing) {

                let maxEval = -Infinity;

                for (const move of possibleMoves) {

                    const moveData = executeMove(move);

                    const eval = minimax(depth - 1, alpha, beta, false);

                    undoMoveData(moveData);

                    maxEval = Math.max(maxEval, eval);

                    alpha = Math.max(alpha, eval);

                    if (beta <= alpha) break;

                }

                return maxEval;

            } else {

                let minEval = Infinity;

                for (const move of possibleMoves) {

                    const moveData = executeMove(move);

                    const eval = minimax(depth - 1, alpha, beta, true);

                    undoMoveData(moveData);

                    minEval = Math.min(minEval, eval);

                    beta = Math.min(beta, eval);

                    if (beta <= alpha) break;

                }

                return minEval;

            }

        }

 

        function getAllPossibleMoves(player) {

            const moves = [];

            for (let row = 0; row < CONFIG.BOARD_HEIGHT; row++) {

                for (let col = 0; col < CONFIG.BOARD_WIDTH; col++) {

                    const piece = board[row][col];

                    if (piece && piece.player === player) {

                        for (let toRow = 0; toRow < CONFIG.BOARD_HEIGHT; toRow++) {

                            for (let toCol = 0; toCol < CONFIG.BOARD_WIDTH; toCol++) {

                                if (isValidMove(row, col, toRow, toCol)) {

                                    moves.push({

                                        from: {row, col},

                                        to: {row: toRow, col: toCol},

                                        piece: piece

                                    });

                                }

                            }

                        }

                    }

                }

            }

            return moves;

        }

 

        function executeMove(move) {

            const piece = board[move.from.row][move.from.col];

            const targetPiece = board[move.to.row][move.to.col];

            

            const moveData = {

                from: {...move.from},

                to: {...move.to},

                piece: {...piece},

                captured: targetPiece ? {...targetPiece} : null,

                board: board.map(row => row.map(cell => cell ? {...cell} : null))

            };

            

            board[move.to.row][move.to.col] = piece;

            board[move.from.row][move.from.col] = null;

            

            return moveData;

        }

 

        function undoMoveData(moveData) {

            board = moveData.board.map(row => row.map(cell => cell ? {...cell} : null));

        }

 

        function evaluateBoard() {

            let score = 0;

            for (let r = 0; r < CONFIG.BOARD_HEIGHT; r++) {

                for (let c = 0; c < CONFIG.BOARD_WIDTH; c++) {

                    const p = board[r][c];

                    if (!p) continue;

                    

                    let v = CONFIG.PIECE_VALUES[p.type] || 0;

                    

                    // 过河兵额外加分

                    if ((p.player === 'red' && p.type === '兵' && r <= 4) ||

                        (p.player === 'black' && p.type === '卒' && r >= 5)) v += 8;

                    

                    // 控制中心区域加分

                    if (r >= 2 && r <= 7 && c >= 2 && c <= 6) v += 3;

                    

                    score += (p.player === 'black' ? v : -v);

                }

            }

            return score;

        }

 

        // 九. 棋子选择与显示

        function clearSelection() {

            selectedPiece = null;

            document.querySelectorAll('.piece.selected').forEach(el => {

                el.classList.remove('selected');

            });

            document.querySelectorAll('.piece.hint').forEach(el => {

                el.classList.remove('hint');

            });

            document.querySelectorAll('.piece.valid-move').forEach(el => {

                el.classList.remove('valid-move');

            });

        }

 

        function highlightPiece(row, col) {

            const pieceElement = document.querySelector(`.piece[data-row="${row}"][data-col="${col}"]`);

            if (pieceElement) {

                pieceElement.classList.add('selected');

            }

        }

 

        function showValidMoves(row, col) {

            for (let r = 0; r < CONFIG.BOARD_HEIGHT; r++) {

                for (let c = 0; c < CONFIG.BOARD_WIDTH; c++) {

                    if (isValidMove(row, col, r, c)) {

                        const pieceElement = document.querySelector(`.piece[data-row="${r}"][data-col="${c}"]`);

                        if (pieceElement) {

                            pieceElement.classList.add('valid-move');

                        }

                    }

                }

            }

        }

 

        // 十. 棋子移动规则

        function isValidMove(fromRow, fromCol, toRow, toCol) {

            const piece = board[fromRow][fromCol];

            if (!piece) return false;

            

            const targetPiece = board[toRow][toCol];

            if (targetPiece && targetPiece.player === piece.player) return false;

            

            const rowDiff = toRow - fromRow;

            const colDiff = toCol - fromCol;

            const absRowDiff = Math.abs(rowDiff);

            const absColDiff = Math.abs(colDiff);

            

            switch (piece.type) {

                case CONFIG.PIECE_TYPES.SHUAI:

                    return isValidShuaiMove(fromRow, fromCol, toRow, toCol);

                case CONFIG.PIECE_TYPES.SHI:

                    if (piece.player === 'red') {

                        return toRow >= 7 && toRow <= 9 && toCol >= 3 && toCol <= 5 &&

                               absRowDiff === 1 && absColDiff === 1;

                    } else {

                        return toRow >= 0 && toRow <= 2 && toCol >= 3 && toCol <= 5 &&

                               absRowDiff === 1 && absColDiff === 1;

                    }

                case CONFIG.PIECE_TYPES.XIANG:

                    if (piece.player === 'red' && toRow < 5) return false;

                    if (piece.player === 'black' && toRow > 4) return false;

                    if (absRowDiff !== 2 || absColDiff !== 2) return false;

                    const midRow = fromRow + rowDiff / 2;

                    const midCol = fromCol + colDiff / 2;

                    return board[midRow][midCol] === null;

                case CONFIG.PIECE_TYPES.MA:

                    if (!((absRowDiff === 2 && absColDiff === 1) || (absRowDiff === 1 && absColDiff === 2))) return false;

                    if (absRowDiff === 2) {

                        const midRow = fromRow + rowDiff / 2;

                        return board[midRow][fromCol] === null;

                    } else {

                        const midCol = fromCol + colDiff / 2;

                        return board[fromRow][midCol] === null;

                    }

                case CONFIG.PIECE_TYPES.JU:

                    return isValidJuMove(fromRow, fromCol, toRow, toCol);

                case CONFIG.PIECE_TYPES.PAO:

                    return isValidPaoMove(fromRow, fromCol, toRow, toCol);

                case CONFIG.PIECE_TYPES.BING:

                    return isValidBingMove(fromRow, fromCol, toRow, toCol);

                default:

                    return false;

            }

        }

 

        function isValidShuaiMove(fromRow, fromCol, toRow, toCol) {

            const piece = board[fromRow][fromCol];

            const targetPiece = board[toRow][toCol];

            

            if (piece.player === 'red') {

                if (toRow < 7 || toRow > 9 || toCol < 3 || toCol > 5) return false;

            } else {

                if (toRow < 0 || toRow > 2 || toCol < 3 || toCol > 5) return false;

            }

            

            const rowDiff = Math.abs(toRow - fromRow);

            const colDiff = Math.abs(toCol - fromCol);

            if (!((rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1))) {

                return false;

            }

            

            // 将帅对面

            if (targetPiece && targetPiece.type === CONFIG.PIECE_TYPES.SHUAI) {

                if (fromCol === toCol) {

                    const minRow = Math.min(fromRow, toRow);

                    const maxRow = Math.max(fromRow, toRow);

                    for (let row = minRow + 1; row < maxRow; row++) {

                        if (board[row][fromCol] !== null) return false;

                    }

                    return true;

                }

            }

            

            return true;

        }

 

        function isValidJuMove(fromRow, fromCol, toRow, toCol) {

            if (fromRow !== toRow && fromCol !== toCol) return false;

            

            if (fromRow === toRow) {

                const minCol = Math.min(fromCol, toCol);

                const maxCol = Math.max(fromCol, toCol);

                for (let col = minCol + 1; col < maxCol; col++) {

                    if (board[fromRow][col] !== null) return false;

                }

            } else {

                const minRow = Math.min(fromRow, toRow);

                const maxRow = Math.max(fromRow, toRow);

                for (let row = minRow + 1; row < maxRow; row++) {

                    if (board[row][fromCol] !== null) return false;

                }

            }

            

            return true;

        }

 

        function isValidPaoMove(fromRow, fromCol, toRow, toCol) {

            if (fromRow !== toRow && fromCol !== toCol) return false;

            

            const targetPiece = board[toRow][toCol];

            let pieceCount = 0;

            

            if (fromRow === toRow) {

                const minCol = Math.min(fromCol, toCol);

                const maxCol = Math.max(fromCol, toCol);

                for (let col = minCol + 1; col < maxCol; col++) {

                    if (board[fromRow][col] !== null) pieceCount++;

                }

            } else {

                const minRow = Math.min(fromRow, toRow);

                const maxRow = Math.max(fromRow, toRow);

                for (let row = minRow + 1; row < maxRow; row++) {

                    if (board[row][fromCol] !== null) pieceCount++;

                }

            }

            

            if (targetPiece) {

                return pieceCount === 1;

            } else {

                return pieceCount === 0;

            }

        }

 

        function isValidBingMove(fromRow, fromCol, toRow, toCol) {

            const piece = board[fromRow][fromCol];

            const rowDiff = toRow - fromRow;

            const colDiff = Math.abs(toCol - fromCol);

            

            if (piece.player === 'red') {

                if (fromRow > 4) {

                    return rowDiff === -1 && colDiff === 0;

                } else {

                    return (rowDiff === -1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1);

                }

            } else {

                if (fromRow < 5) {

                    return rowDiff === 1 && colDiff === 0;

                } else {

                    return (rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1);

                }

            }

        }

 

        // 十一. 棋子移动与游戏逻辑

        function movePiece(fromRow, fromCol, toRow, toCol) {

            const piece = board[fromRow][fromCol];

            const targetPiece = board[toRow][toCol];

            

            const moveData = {

                from: {row: fromRow, col: fromCol},

                to: {row: toRow, col: toCol},

                piece: {...piece},

                captured: targetPiece ? {...targetPiece} : null,

                board: board.map(row => row.map(cell => cell ? {...cell} : null))

            };

            

            board[toRow][toCol] = piece;

            board[fromRow][fromCol] = null;

            

            addToHistory(moveData);

            

            if (targetPiece) {

                if (targetPiece.type === CONFIG.PIECE_TYPES.SHUAI) {

                    gameOver = true;

                    setTimeout(() => {

                        alert(`${currentPlayer === 'red' ? '红方' : '黑方'}获胜!`);

                    }, 100);

                }

            }

            

            currentPlayer = currentPlayer === 'red' ? 'black' : 'red';

            updateStatus();

            document.getElementById('hintText').textContent = '';

            clearSelection();

            renderBoard();

        }

 

        function addToHistory(moveData) {

            const moveList = document.getElementById('moveList');

            const moveItem = document.createElement('div');

            moveItem.className = `move-item ${currentPlayer}`;

            

            const fromPos = `${9 - moveData.from.row}${String.fromCharCode(97 + moveData.from.col)}`;

            const toPos = `${9 - moveData.to.row}${String.fromCharCode(97 + moveData.to.col)}`;

            const captureText = moveData.captured ? ` 吃 ${moveData.captured.type}` : '';

            

            moveItem.textContent = `${moveData.piece.type}: ${fromPos} → ${toPos}${captureText}`;

            moveList.insertBefore(moveItem, moveList.firstChild);

            moveHistory.push(moveData);

        }

 

        // 十二. 游戏控制功能

        function undoMove() {

            if (moveHistory.length === 0) {

                alert('没有可以悔棋的记录了!');

                return;

            }

            

            if (gameMode === 'ai' && moveHistory.length < 2) {

                alert('AI 模式下至少需要走两步才能悔棋!');

                return;

            }

            

            if (confirm('确定要悔棋吗?')) {

                const steps = gameMode === 'ai' ? 2 : 1;

                for (let i = 0; i < steps; i++) {

                    if (moveHistory.length === 0) break;

                    const lastMove = moveHistory.pop();

                    board = lastMove.board.map(row => row.map(cell => cell ? {...cell} : null));

                    

                    const moveList = document.getElementById('moveList');

                    if (moveList.firstChild) {

                        moveList.removeChild(moveList.firstChild);

                    }

                    

                    currentPlayer = currentPlayer === 'red' ? 'black' : 'red';

                }

                

                updateStatus();

                clearSelection();

                document.getElementById('hintText').textContent = '';

                renderBoard();

            }

        }

 

        function getHint() {

            if (gameOver || aiThinking) return;

            

            const playerPieces = [];

            for (let row = 0; row < CONFIG.BOARD_HEIGHT; row++) {

                for (let col = 0; col < CONFIG.BOARD_WIDTH; col++) {

                    const piece = board[row][col];

                    if (piece && piece.player === currentPlayer) {

                        playerPieces.push({row, col, piece});

                    }

                }

            }

            

            const possibleMoves = [];

            for (const pieceInfo of playerPieces) {

                for (let toRow = 0; toRow < CONFIG.BOARD_HEIGHT; toRow++) {

                    for (let toCol = 0; toCol < CONFIG.BOARD_WIDTH; toCol++) {

                        if (isValidMove(pieceInfo.row, pieceInfo.col, toRow, toCol)) {

                            const score = evaluateMoveDeep(pieceInfo.row, pieceInfo.col, toRow, toCol, 3);

                            possibleMoves.push({

                                from: {row: pieceInfo.row, col: pieceInfo.col},

                                to: {row: toRow, col: toCol},

                                piece: pieceInfo.piece,

                                score: score

                            });

                        }

                    }

                }

            }

            

            if (possibleMoves.length === 0) {

                document.getElementById('hintText').textContent = '没有可走的棋子了!';

                return;

            }

            

            possibleMoves.sort((a, b) => b.score - a.score);

            const bestMove = possibleMoves[0];

            

            const hintText = document.getElementById('hintText');

            const fromPos = `${9 - bestMove.from.row}${String.fromCharCode(97 + bestMove.from.col)}`;

            const toPos = `${9 - bestMove.to.row}${String.fromCharCode(97 + bestMove.to.col)}`;

            

            let reason = '';

            if (bestMove.score > 50) {

                reason = ' (可以吃掉对方重要棋子)';

            } else if (bestMove.score < -20) {

                reason = ' (可能被吃,谨慎考虑)';

            } else {

                reason = ' (较为安全的走法)';

            }

            

            hintText.textContent = `建议走法:${bestMove.piece.type} 从 ${fromPos} 走到${toPos}${reason}`;

            hintText.style.color = currentPlayer === 'red' ? '#cc0000' : '#000';

            

            clearSelection();

            const pieceElement = document.querySelector(`.piece[data-row="${bestMove.from.row}"][data-col="${bestMove.from.col}"]`);

            if (pieceElement) {

                pieceElement.classList.add('hint');

            }

        }

 

        function evaluateMoveDeep(fromRow, fromCol, toRow, toCol, depth) {

            if (depth === 0) return 0;

            

            const piece = board[fromRow][fromCol];

            const targetPiece = board[toRow][toCol];

            let score = 0;

            

            const pieceValues = {

                [CONFIG.PIECE_TYPES.BING]: 10,

                [CONFIG.PIECE_TYPES.PAO]: 30,

                [CONFIG.PIECE_TYPES.MA]: 30,

                [CONFIG.PIECE_TYPES.XIANG]: 20,

                [CONFIG.PIECE_TYPES.SHI]: 20,

                [CONFIG.PIECE_TYPES.JU]: 50,

                [CONFIG.PIECE_TYPES.SHUAI]: 1000

            };

            

            if (targetPiece) {

                score += pieceValues[targetPiece.type] || 0;

            }

            

            const originalBoard = board.map(row => row.map(cell => cell ? {...cell} : null));

            const originalGameOver = gameOver;

            

            board[toRow][toCol] = piece;

            board[fromRow][fromCol] = null;

            

            let canBeCaptured = false;

            let captureValue = 0;

            

            for (let row = 0; row < CONFIG.BOARD_HEIGHT; row++) {

                for (let col = 0; col < CONFIG.BOARD_WIDTH; col++) {

                    const enemyPiece = board[row][col];

                    if (enemyPiece && enemyPiece.player !== currentPlayer) {

                        if (isValidMove(row, col, toRow, toCol)) {

                            canBeCaptured = true;

                            const value = pieceValues[piece.type] || 0;

                            captureValue = Math.max(captureValue, value);

                        }

                    }

                }

            }

            

            if (canBeCaptured) {

                score -= captureValue * 0.8;

            }

            

            if (depth > 1 && !gameOver) {

                const nextPlayer = currentPlayer === 'red' ? 'black' : 'red';

                const nextMoves = getAllPossibleMoves(nextPlayer);

                

                if (nextMoves.length > 0) {

                    let worstResponse = Infinity;

                    for (const nextMove of nextMoves.slice(0, 10)) {

                        const nextScore = evaluateMoveDeep(

                            nextMove.from.row, nextMove.from.col,

                            nextMove.to.row, nextMove.to.col,

                            depth - 1

                        );

                        worstResponse = Math.min(worstResponse, nextScore);

                    }

                    score += worstResponse * 0.3;

                }

            }

            

            board = originalBoard;

            gameOver = originalGameOver;

            

            // 位置价值

            if (piece.player === 'red' && toRow < fromRow) score += 2;

            if (piece.player === 'black' && toRow > fromRow) score += 2;

            

            if (toRow >= 2 && toRow <= 7 && toCol >= 2 && toCol <= 6) {

                score += 3;

            }

            

            // 帅的安全

            if (piece.type === CONFIG.PIECE_TYPES.SHUAI) {

                const inPalace = piece.player === 'red' ?

                    (toRow >= 7 && toRow <= 9 && toCol >= 3 && toCol <= 5) :

                    (toRow >= 0 && toRow <= 2 && toCol >= 3 && toCol <= 5);

                if (!inPalace) score -= 50;

            }

            

            return score;

        }

 

        // 十三. 游戏初始化与控制

        function startGame(mode) {

            gameMode = mode;

            document.getElementById('modeSelection').style.display = 'none';

            document.getElementById('gameMode').textContent = mode === 'ai' ? '(AI对战)' : '(双人对战)';

            

            if (mode === 'ai' && currentPlayer === 'black') {

                setTimeout(() => aiMove(), 1000);

            }

        }

 

        function updateStatus() {

            const statusElement = document.getElementById('currentPlayer');

            statusElement.textContent = currentPlayer === 'red' ? '红方' : '黑方';

            statusElement.style.color = currentPlayer === 'red' ? '#cc0000' : '#000';

        }

 

      function resetGame() {

    if (confirm('确定要重新开始游戏?')) {

        // 清除游戏状态

        gameOver = false;

        currentPlayer = 'red';

        selectedPiece = null;

        moveHistory = [];

        aiThinking = false;

        gameMode = '';

 

        // 清空界面

        document.getElementById('moveList').innerHTML = '';

        document.getElementById('hintText').textContent = '';

        document.getElementById('gameMode').textContent = '';

 

        // 重新初始化棋盘

        initBoard();

        renderBoard();

        updateStatus();

 

        // 显示模式选择界面

        const modeSelection = document.getElementById('modeSelection');

        modeSelection.style.display = 'flex';

 

        // 🔥强制重新绑定事件(防止点击无效)

        modeSelection.innerHTML = `

            <div class="mode-box">

                <h2>选择游戏模式</h2>

                <button class="mode-button" onclick="startGame('pvp')">双人对战</button>

                <button class="mode-button" onclick="startGame('ai')">AI对战</button>

            </div>

        `;

    }

}

 

 

        function showRules() {

            alert(`象棋规则:

1. 帅(将):只能在九宫格内移动,每次只能走一格

2. 士(仕):只能在九宫格内斜走一格

3. 象(相):走田字,不能过河,不能塞象眼

4. 马:走日字,不能蹩马腿

5. 车:直线行走,格数不限

6. 炮:直线行走,吃子时需要隔一个棋子

7. 兵(卒):过河前只能向前,过河后可以左右移动

 

操作说明:

- 点击棋子选中,再点击目标位置移动

- 点击"悔棋"按钮可以撤销上一步

- 点击"提示走法"可以获得AI建议(考虑3步)

- AI对战模式下,AI会自动走棋

 

吃掉对方的将/帅即可获胜!`);

        }

 

        // 十四. 事件监听器

        window.addEventListener('resize', () => {

            if (board.length > 0) {

                renderBoard();

            }

        });

 

        window.onload = function() {

            initStyles();

            initBoard();

            renderBoard();

            updateStatus();

        };

    </script>

</body>

</html>

 

http://www.dtcms.com/a/594526.html

相关文章:

  • 基于站点的网络营销方法app开发多少钱
  • 无忧网站建设费用做一个手机app大概需要多少钱
  • winlogon!SASWndProc函数分析之win+L键的处理
  • Uni-app条件编译(// #ifndef APP)
  • 做网站为什么很复杂建好网站是不是还得维护
  • 非专业人士可以做网站编辑的工作吗WordPress文章生成图片
  • 平凉市城乡建设局网站让别人访问自己做的网站
  • 企业经营异常信息查询接口分享、技术文档
  • seo网站分析报告网站分享的功能怎么做
  • idae快捷键
  • 推荐西安优秀的响应式网站建设公司教务管理系统下载
  • 企业部署智能决策系统成本高吗?
  • PCB之电源完整性之电源网络的PDN仿真CST---06
  • 搭建一个简单的springcloud服务
  • 重庆科技网站建设婚纱摄影哪家好
  • 不让Django DRF ListAPIView 类进行2次查询
  • HarmonyOS:弹性布局(Flex)
  • CANN在智能视频分析场景中的实践应用
  • 基于ESP32的宠物喂食小屋
  • 西昌有做网站的公司吗海南网站设计公司
  • Prometheus实战教程 - 服务发现
  • 卸载搜狗压缩软件
  • 企业网站制作免费下载效果图网站发帖平台
  • 做网站的时候用的什么框架app下载汅api免费下载大全视频
  • 鸿蒙应用开发之实现键值型数据库跨设备数据同步
  • 企业网站域名备案流程营销网红
  • 双擎驱动 AI 开发:智能体全流程评测 + 应用编排创新实践指南
  • 小杰-大模型(four)——RAG与Agent设计——Langchain-chain链
  • 吐鲁番大型网站建设平台素材库网站
  • mysql表的连接——内外连接