1.1 脚本网页 战推棋

游戏已开源,可以集成到个人网站

html 复制代码
<!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>
        :root {
            /* 配色方案:深空蓝与霓虹色 */
            --bg-gradient-start: #1a1c2c;
            --bg-gradient-end: #4a192c;
            --primary-color: #4ecca3; /* 玩家/高亮 */
            --secondary-color: #e94560; /* AI/敌人 */
            --text-color: #ecf0f1;
            --glass-bg: rgba(255, 255, 255, 0.1);
            --glass-border: rgba(255, 255, 255, 0.2);
            
            /* 棋盘吸盘颜色 */
            --board-bg: #16213e;
            --cell-base: #0f3460;
            --cell-hover: #1a4b85;
        }

        * {
            box-sizing: border-box;
            user-select: none;
            -webkit-tap-highlight-color: transparent;
        }

        body {
            font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
            background: radial-gradient(circle at center, var(--bg-gradient-start), #000);
            background-size: cover;
            color: var(--text-color);
            display: flex;
            flex-direction: column;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            padding: 20px;
        }

        /* --- 头部区域 --- */
        header {
            text-align: center;
            margin-bottom: 20px;
            animation: fadeIn Down 0.8s ease-out;
        }

        h1 {
            margin: 0;
            font-size: 2.5rem;
            color: #fff;
            text-shadow: 0 0 15px rgba(78, 204, 163, 0.6);
            letter-spacing: 2px;
        }

        .subtitle {
            font-size: 1rem;
            color: #8d9db6;
            margin-top: 8px;
            font-weight: 300;
        }

        /* --- 主布局 --- */
        main {
            display: flex;
            gap: 40px;
            flex-wrap: wrap;
            justify-content: center;
            align-items: flex-start;
            width: 100%;
            max-width: 1000px;
        }

        /* --- 游戏控制区 (左侧) --- */
        .game-wrapper {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        /* 状态栏 */
        .status-bar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 100%;
            margin-bottom: 15px;
            background: var(--glass-bg);
            backdrop-filter: blur(10px);
            padding: 10px 20px;
            border-radius: 50px;
            border: 1px solid var(--glass-border);
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
        }

        .turn-badge {
            padding: 6px 16px;
            border-radius: 20px;
            font-weight: bold;
            font-size: 0.9rem;
            transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        .turn-player {
            background: var(--primary-color);
            color: #1a1c2c;
            box-shadow: 0 0 10px rgba(78, 204, 163, 0.5);
        }

        .turn-ai {
            background: var(--secondary-color);
            color: #fff;
            box-shadow: 0 0 10px rgba(233, 69, 96, 0.5);
        }

        /* --- 棋盘 (吸盘风格) --- */
        .board-container {
            padding: 15px;
            background: #2a2d3e;
            border-radius: 16px;
            box-shadow: 
                20px 20px 60px #15171f, 
                -20px -20px 60px #3f435d; /* 新拟态阴影 */
            position: relative;
        }

        #board {
            display: grid;
            grid-template-columns: repeat(6, 1fr);
            grid-template-rows: repeat(6, 1fr);
            gap: 6px; /* 格子间距,模仿吸盘间隔 */
            width: 360px;
            height: 360px;
        }

        .cell {
            background-color: var(--cell-base);
            border-radius: 50%; /* 圆形模仿吸盘 */
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            position: relative;
            transition: all 0.2s ease;
            box-shadow: inset 2px 2px 5px rgba(0,0,0,0.5), inset -2px -2px 5px rgba(255,255,255,0.05);
        }

        /* 鼠标悬停 */
        .cell:hover {
            transform: scale(0.95);
        }

        /* 可移动提示 (吸盘光晕) */
        .cell.highlight {
            background-color: rgba(78, 204, 163, 0.25);
            box-shadow: 0 0 15px var(--primary-color), inset 0 0 10px var(--primary-color);
            animation: pulse 1.5s infinite;
        }

        .cell.last-move {
            background-color: rgba(255, 215, 0, 0.15);
            box-shadow: inset 0 0 8px rgba(255, 215, 0, 0.4);
        }

        /* --- 棋子 --- */
        .piece {
            width: 85%;
            height: 85%;
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 1.2rem;
            font-weight: bold;
            transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
            z-index: 2;
        }

        .piece.player {
            background: radial-gradient(circle at 30% 30%, #6ef7c7, #1a8f66);
            border: 2px solid #a3ffce;
            color: #052e1e;
            box-shadow: 0 4px 6px rgba(0,0,0,0.4);
        }

        .piece.ai {
            background: radial-gradient(circle at 30% 30%, #ff7b93, #c82333);
            border: 2px solid #ffccd5;
            color: #4a0e15;
            box-shadow: 0 4px 6px rgba(0,0,0,0.4);
        }

        /* 棋子类型符号 */
        .piece.king::after { content: '♔'; font-size: 1.4rem; }
        .piece.pawn::after { content: '●'; font-size: 0.9rem; }

        /* 选中状态 */
        .piece.selected {
            transform: scale(1.2);
            box-shadow: 0 0 20px #fff;
            z-index: 10;
        }

        /* --- 侧边栏 (右) --- */
        aside {
            flex: 1;
            min-width: 280px;
            max-width: 350px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }

        /* 按钮组 */
        .btn-group {
            display: flex;
            gap: 10px;
        }

        button {
            flex: 1;
            background: var(--glass-bg);
            backdrop-filter: blur(10px);
            border: 1px solid var(--glass-border);
            padding: 12px;
            color: #fff;
            font-weight: 600;
            font-size: 0.95rem;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        button:hover {
            background: rgba(255,255,255,0.2);
            transform: translateY(-2px);
        }

        button:active {
            transform: translateY(1px);
        }

        button.primary {
            background: var(--primary-color);
            color: #1a1c2c;
            border: none;
        }

        button.primary:hover {
            background: #6ef7c7;
            box-shadow: 0 0 15px rgba(78, 204, 163, 0.4);
        }

        /* 日志窗口 */
        .log-container {
            flex-grow: 1;
            background: rgba(0, 0, 0, 0.3);
            border: 1px solid var(--glass-border);
            border-radius: 8px;
            padding: 15px;
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 0.85rem;
            overflow-y: auto;
            max-height: 200px;
            min-height: 150px;
            box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
        }

        /* 自定义滚动条 */
        .log-container::-webkit-scrollbar { width: 6px; }
        .log-container::-webkit-scrollbar-thumb { background: #4a5568; border-radius: 3px; }

        .log-entry { margin-bottom: 6px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 4px; }
        .log-player { color: var(--primary-color); }
        .log-ai { color: var(--secondary-color); }
        .log-system { color: #8899ac; font-style: italic; }

        /* --- 模态框 (规则 & 结束) --- */
        .modal-overlay {
            position: fixed;
            top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(5px);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s ease;
        }

        .modal-overlay.active {
            opacity: 1;
            pointer-events: all;
        }

        .modal {
            background: #1f2233;
            padding: 30px;
            border-radius: 16px;
            text-align: center;
            border: 1px solid var(--glass-border);
            max-width: 90%;
            width: 400px;
            box-shadow: 0 20px 50px rgba(0,0,0,0.5);
            transform: translateY(20px);
            transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        .modal-overlay.active .modal {
            transform: translateY(0);
        }

        .modal h2 {
            color: var(--primary-color);
            margin-top: 0;
            font-size: 1.8rem;
        }

        .modal-content {
            text-align: left;
            color: #ccc;
            margin-bottom: 25px;
            line-height: 1.6;
            font-size: 0.95rem;
        }

        .modal-content strong { color: #fff; }
        .modal-content ul { padding-left: 20px; margin: 5px 0; }
        .modal-content li { margin-bottom: 6px; }

        .modal-btn {
            background: var(--primary-color);
            color: #1a1c2c;
            width: 100%;
            font-weight: bold;
        }

        /* --- 动画 --- */
        @keyframes pulse {
            0% { box-shadow: 0 0 0 0 rgba(78, 204, 163, 0.4); }
            70% { box-shadow: 0 0 0 10px rgba(78, 204, 163, 0); }
            100% { box-shadow: 0 0 0 0 rgba(78, 204, 163, 0); }
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        .shake { animation: shake 0.5s; }
        @keyframes shake {
            0%, 100% { transform: translateX(0); }
            10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
            20%, 40%, 60%, 80% { transform: translateX(4px); }
        }

        /* 响应式调整 */
        @media (max-width: 600px) {
            #board { width: 300px; height: 300px; gap: 4px; }
            main { flex-direction: column; align-items: center; }
            aside { width: 100%; }
        }
    </style>
</head>
<body>

<header>
    <h1>战推棋</h1>
    <div class="subtitle">Battle Push Chess - 极简推挤策略</div>
</header>

<main>
    <div class="game-wrapper">
        <!-- 状态栏 -->
        <div class="status-bar">
            <div id="turn-indicator" class="turn-badge turn-player">玩家回合</div>
            <div id="game-state" style="font-size: 0.85rem; color: #aaa;">进行中</div>
        </div>

        <!-- 棋盘 -->
        <div class="board-container">
            <div id="board"></div>
        </div>
    </div>

    <!-- 侧边栏 -->
    <aside>
        <div class="btn-group">
            <button onclick="openRulesModal()">查看规则</button>
            <button class="primary" onclick="game.init()">重新开始</button>
        </div>

        <div class="log-container" id="game-log">
            <div class="log-entry log-system">欢迎来到战推棋!</div>
            <div class="log-entry log-system">请点击绿色棋子开始。</div>
        </div>
    </aside>
</main>

<!-- 规则弹窗 -->
<div id="rules-modal" class="modal-overlay">
    <div class="modal">
        <h2>游戏规则</h2>
        <div class="modal-content">
            <p><strong>胜利条件:</strong>粉碎对方的主帅(♔)。</p>
            <ul>
                <li><strong>移动:</strong>点击己方棋子,再点击高亮光圈移动。</li>
                <li><strong>推挤:</strong>移动到敌方位置会将其向后推1格。</li>
                <li><strong>粉碎(Crush):</strong>
                    <br>- 被推棋子后方是墙壁、边界或友军 -> <span style="color:var(--secondary-color)">直接粉碎</span>。
                    <br>- 主帅被推挤或被粉碎 -> 游戏结束。
                </li>
                <li><strong>棋子:</strong>
                    <br>♔ 主帅:可向周围8个方向移动。
                    <br>● 先锋:仅可向上下左右4个方向移动。
                </li>
            </ul>
        </div>
        <button class="modal-btn" onclick="closeRulesModal()">明白了,开始战斗</button>
    </div>
</div>

<!-- 游戏结束弹窗 -->
<div id="end-modal" class="modal-overlay">
    <div class="modal">
        <h2 id="end-title">游戏结束</h2>
        <p id="end-message" style="color:#fff; font-size:1.1rem;">你赢了!</p>
        <button class="modal-btn" onclick="closeEndModal()">再来一局</button>
    </div>
</div>

<script>
    /**
     * 游戏配置与常量
     */
    const BOARD_SIZE = 6;
    const PLAYER = 1;  // 绿方
    const AI = -1;     // 红方
    const TYPE_KING = 'king';
    const TYPE_PAWN = 'pawn';

    /**
     * 游戏核心逻辑类
     */
    class Game {
        constructor() {
            this.board = [];
            this.turn = PLAYER;
            this.selectedPiece = null; // {r, c}
            this.validMoves = [];      // Array of {r, c, type...}
            this.isGameOver = false;
            this.lastMove = null;      // {from: {r,c}, to: {r,c}}
            this.isAiThinking = false;
            
            // DOM 缓存
            this.boardEl = document.getElementById('board');
            this.turnIndEl = document.getElementById('turn-indicator');
            this.stateEl = document.getElementById('game-state');
            this.logEl = document.getElementById('game-log');

            this.init();
        }

        // 初始化/重置游戏
        init() {
            this.board = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null));
            this.turn = PLAYER;
            this.isGameOver = false;
            this.selectedPiece = null;
            this.validMoves = [];
            this.lastMove = null;
            this.isAiThinking = false;

            this.setupBoard();
            this.render();
            this.updateStatus("玩家回合");
            this.log("游戏开始,绿方先手。", "system");
            document.getElementById('end-modal').classList.remove('active');
        }

        // 布局棋子
        setupBoard() {
            // 放置 AI (红方, 上方)
            this.board[0][2] = { type: TYPE_KING, owner: AI };
            this.board[0][1] = { type: TYPE_PAWN, owner: AI };
            this.board[0][3] = { type: TYPE_PAWN, owner: AI };
            this.board[1][2] = { type: TYPE_PAWN, owner: AI };

            // 放置 Player (绿方, 下方)
            this.board[5][3] = { type: TYPE_KING, owner: PLAYER };
            this.board[5][2] = { type: TYPE_PAWN, owner: PLAYER };
            this.board[5][4] = { type: TYPE_PAWN, owner: PLAYER };
            this.board[4][3] = { type: TYPE_PAWN, owner: PLAYER };
        }

        // 渲染棋盘
        render() {
            this.boardEl.innerHTML = '';
            
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.r = r;
                    cell.dataset.c = c;

                    // 检查是否是合法移动位置 (吸盘高亮)
                    const move = this.validMoves.find(m => m.r === r && m.c === c);
                    if (move) {
                        cell.classList.add('highlight');
                    }

                    // 检查是否是上一步
                    if (this.lastMove && 
                        ((this.lastMove.from.r === r && this.lastMove.from.c === c) ||
                         (this.lastMove.to.r === r && this.lastMove.to.c === c))) {
                        cell.classList.add('last-move');
                    }

                    // 绘制棋子
                    const pieceData = this.board[r][c];
                    if (pieceData) {
                        const piece = document.createElement('div');
                        piece.className = `piece ${pieceData.owner === PLAYER ? 'player' : 'ai'} ${pieceData.type}`;
                        
                        if (this.selectedPiece && this.selectedPiece.r === r && this.selectedPiece.c === c) {
                            piece.classList.add('selected');
                        }
                        cell.appendChild(piece);
                    }

                    cell.addEventListener('click', () => this.handleCellClick(r, c));
                    this.boardEl.appendChild(cell);
                }
            }
        }

        // 处理点击事件
        handleCellClick(r, c) {
            if (this.isGameOver || this.isAiThinking || this.turn !== PLAYER) return;

            const clickedPiece = this.board[r][c];

            // 1. 选中己方棋子
            if (clickedPiece && clickedPiece.owner === PLAYER) {
                this.selectedPiece = { r, c };
                this.validMoves = this.getValidMoves(this.board, r, c);
                this.render();
                return;
            }

            // 2. 移动到合法位置
            const move = this.validMoves.find(m => m.r === r && m.c === c);
            if (this.selectedPiece && move) {
                this.executeMove(this.selectedPiece, move);
                return;
            }

            // 3. 点击空白或无效处 -> 取消选中
            this.selectedPiece = null;
            this.validMoves = [];
            this.render();
        }

        // 获取合法移动 (包括推挤逻辑)
        getValidMoves(board, r, c) {
            const piece = board[r][c];
            if (!piece) return [];

            const moves = [];
            const directions = [];

            // 定义移动方向
            if (piece.type === TYPE_KING) {
                // 8个方向
                directions.push(
                    {dr: -1, dc: 0}, {dr: 1, dc: 0}, {dr: 0, dc: -1}, {dr: 0, dc: 1},
                    {dr: -1, dc: -1}, {dr: -1, dc: 1}, {dr: 1, dc: -1}, {dr: 1, dc: 1}
                );
            } else {
                // 4个方向
                directions.push(
                    {dr: -1, dc: 0}, {dr: 1, dc: 0}, {dr: 0, dc: -1}, {dr: 0, dc: 1}
                );
            }

            for (let d of directions) {
                const nr = r + d.dr;
                const nc = c + d.dc;

                // 边界检查
                if (nr < 0 || nr >= BOARD_SIZE || nc < 0 || nc >= BOARD_SIZE) continue;

                const target = board[nr][nc];

                if (!target) {
                    // 空地:直接移动
                    moves.push({ r: nr, c: nc, type: 'move' });
                } else if (target.owner !== piece.owner) {
                    // 敌人:尝试推挤
                    const pushR = nr + d.dr;
                    const pushC = nc + d.dc;
                    let isCrush = false;

                    // 检查推挤后的位置状态 (边界或被占用)
                    if (pushR < 0 || pushR >= BOARD_SIZE || pushC < 0 || pushC >= BOARD_SIZE) {
                        isCrush = true; // 推出界
                    } else if (board[pushR][pushC] !== null) {
                        isCrush = true; // 撞到友军或墙壁
                    }

                    moves.push({ 
                        r: nr, c: nc, 
                        type: 'push', 
                        pushTo: {r: pushR, c: pushC}, 
                        crush: isCrush 
                    });
                }
            }
            return moves;
        }

        // 执行移动
        async executeMove(from, move) {
            const piece = this.board[from.r][from.c];
            const target = this.board[move.r][move.c]; // 目标格原有内容(可能是敌人)

            // 记录步数
            this.lastMove = { from: {...from}, to: {r: move.r, c: move.c} };

            if (move.type === 'move') {
                // 普通移动
                this.board[move.r][move.c] = piece;
                this.board[from.r][from.c] = null;
            } else if (move.type === 'push') {
                // 攻击移动
                const actorName = piece.owner === PLAYER ? '玩家' : 'AI';
                
                if (target.type === TYPE_KING) {
                    this.log(`${actorName} 粉碎了敌方主帅!`, piece.owner === PLAYER ? 'player' : 'ai');
                } else {
                    this.log(`${actorName} 推挤了敌方先锋!`, piece.owner === PLAYER ? 'player' : 'ai');
                }

                // 攻击者占据目标位
                this.board[move.r][move.c] = piece;
                this.board[from.r][from.c] = null;

                // 处理被推者
                if (move.crush) {
                    // 粉碎:直接移除
                    // 视觉特效:震动
                    this.shakeBoard();
                } else {
                    // 推移:被推者移动到pushTo
                    this.board[move.pushTo.r][move.pushTo.c] = target;
                }
            }

            // 清理状态
            this.selectedPiece = null;
            this.validMoves = [];
            this.render();

            // 检查胜利
            if (this.checkWin()) return;

            // 切换回合
            this.turn = this.turn === PLAYER ? AI : PLAYER;

            if (this.turn === AI) {
                this.updateStatus("AI 思考中...");
                this.isAiThinking = true;
                setTimeout(() => this.makeAiMove(), 800);
            } else {
                this.updateStatus("玩家回合");
            }
        }

        shakeBoard() {
            const container = document.querySelector('.board-container');
            container.classList.remove('shake');
            void container.offsetWidth; // trigger reflow
            container.classList.add('shake');
        }

        checkWin() {
            let playerKing = false;
            let aiKing = false;
            
            for(let r=0; r<BOARD_SIZE; r++){
                for(let c=0; c<BOARD_SIZE; c++){
                    const p = this.board[r][c];
                    if(p && p.type === TYPE_KING){
                        if(p.owner === PLAYER) playerKing = true;
                        if(p.owner === AI) aiKing = true;
                    }
                }
            }

            if (!playerKing) {
                this.endGame(AI);
                return true;
            }
            if (!aiKing) {
                this.endGame(PLAYER);
                return true;
            }
            return false;
        }

        endGame(winner) {
            this.isGameOver = true;
            this.updateStatus("游戏结束");
            
            const modal = document.getElementById('end-modal');
            const title = document.getElementById('end-title');
            const msg = document.getElementById('end-message');

            modal.classList.add('active');
            if (winner === PLAYER) {
                title.textContent = "胜利!";
                title.style.color = "var(--primary-color)";
                msg.textContent = "恭喜!你成功粉碎了敌方主帅!";
            } else {
                title.textContent = "失败";
                title.style.color = "var(--secondary-color)";
                msg.textContent = "你的主帅被粉碎了,再接再厉。";
            }
        }

        updateStatus(text) {
            this.stateEl.textContent = text;
            this.turnIndEl.className = `turn-badge ${this.turn === PLAYER ? 'turn-player' : 'turn-ai'}`;
            this.turnIndEl.textContent = this.turn === PLAYER ? "玩家回合" : "AI 回合";
        }

        log(msg, type) {
            const div = document.createElement('div');
            div.className = `log-entry log-${type}`;
            div.textContent = `> ${msg}`;
            this.logEl.prepend(div);
        }

        // --- AI 逻辑 ---
        
        makeAiMove() {
            const depth = 3; 
            const bestMove = this.minimaxRoot(depth, true);
            
            if (bestMove) {
                this.executeMove(bestMove.from, bestMove.move);
            } else {
                this.log("AI 无路可走,跳过回合。", "ai");
                this.turn = PLAYER;
                this.updateStatus("玩家回合");
                this.isAiThinking = false;
            }
            this.isAiThinking = false;
        }

        evaluateBoard(board) {
            let score = 0;
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    const piece = board[r][c];
                    if (piece) {
                        let val = 0;
                        // 基础分
                        if (piece.type === TYPE_KING) val = 10000;
                        else val = 100;

                        // 位置分:AI在上方,r越大越接近玩家(攻击性),但也越危险
                        val += (r * 6); 
                        
                        // 中心控制分
                        const centerDist = Math.abs(2.5 - r) + Math.abs(2.5 - c);
                        val -= (centerDist * 3);

                        if (piece.owner === AI) {
                            score += val;
                        } else {
                            score -= val;
                        }
                    }
                }
            }
            return score;
        }

        minimaxRoot(depth, isMaximizing) {
            const moves = this.getAllMoves(this.board, AI);
            let bestMove = null;
            let bestValue = -Infinity;
            moves.sort(() => Math.random() - 0.5); // 增加随机性

            for (let move of moves) {
                const savedBoard = this.cloneBoard(this.board);
                this.simulateMove(savedBoard, move.from, move.move);
                const value = this.minimax(savedBoard, depth - 1, -Infinity, Infinity, !isMaximizing);
                if (value > bestValue) {
                    bestValue = value;
                    bestMove = move;
                }
            }
            return bestMove;
        }

        minimax(board, depth, alpha, beta, isMaximizing) {
            if (depth === 0) {
                return this.evaluateBoard(board);
            }

            // 检查胜负状态
            let aiKing = false;
            let plKing = false;
            for(let r=0; r<BOARD_SIZE; r++) {
                for(let c=0; c<BOARD_SIZE; c++) {
                    if(board[r][c] && board[r][c].type === TYPE_KING) {
                        if(board[r][c].owner === AI) aiKing = true;
                        else plKing = true;
                    }
                }
            }
            if (!aiKing) return -100000;
            if (!plKing) return 100000;

            const turn = isMaximizing ? AI : PLAYER;
            const moves = this.getAllMoves(board, turn);
            
            if (moves.length === 0) return isMaximizing ? -1000 : 1000;

            if (isMaximizing) {
                let maxEval = -Infinity;
                for (let move of moves) {
                    const newBoard = this.cloneBoard(board);
                    this.simulateMove(newBoard, move.from, move.move);
                    const evalVal = this.minimax(newBoard, depth - 1, alpha, beta, false);
                    maxEval = Math.max(maxEval, evalVal);
                    alpha = Math.max(alpha, evalVal);
                    if (beta <= alpha) break;
                }
                return maxEval;
            } else {
                let minEval = Infinity;
                for (let move of moves) {
                    const newBoard = this.cloneBoard(board);
                    this.simulateMove(newBoard, move.from, move.move);
                    const evalVal = this.minimax(newBoard, depth - 1, alpha, beta, true);
                    minEval = Math.min(minEval, evalVal);
                    beta = Math.min(beta, evalVal);
                    if (beta <= alpha) break;
                }
                return minEval;
            }
        }

        getAllMoves(board, player) {
            const allMoves = [];
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    const piece = board[r][c];
                    if (piece && piece.owner === player) {
                        const moves = this.getValidMoves(board, r, c);
                        for (let m of moves) {
                            allMoves.push({ from: { r, c }, move: m });
                        }
                    }
                }
            }
            return allMoves;
        }

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

        simulateMove(board, from, move) {
            const piece = board[from.r][from.c];
            const target = board[move.r][move.c];
            
            if (move.type === 'move') {
                board[move.r][move.c] = piece;
                board[from.r][from.c] = null;
            } else if (move.type === 'push') {
                if (!move.crush) {
                    board[move.pushTo.r][move.pushTo.c] = target;
                }
                board[move.r][move.c] = piece;
                board[from.r][from.c] = null;
            }
        }
    }

    // --- UI 交互函数 ---

    function openRulesModal() {
        document.getElementById('rules-modal').classList.add('active');
    }

    function closeRulesModal() {
        document.getElementById('rules-modal').classList.remove('active');
    }

    function closeEndModal() {
        document.getElementById('end-modal').classList.remove('active');
        game.init();
    }

    // 启动游戏
    const game = new Game();

</script>
</body>
</html>
相关推荐
一颗小青松2 小时前
vue 腾讯地图经纬度转高德地图经纬度
前端·javascript·vue.js
yuuki2332332 小时前
【C++】揭秘STL:stack与queue的底层实现
java·c++·windows
weixin_425023002 小时前
Java开发高频实用技巧汇总(List操作/多线程/反射/监控等)
java·windows·list
alonewolf_993 小时前
深入Spring核心原理:从Bean生命周期到AOP动态代理全解析
java·后端·spring
天远Date Lab3 小时前
Python实现用户消费潜力评估:天远个人消费能力等级API对接全攻略
java·大数据·网络·python
Justin3go10 小时前
HUNT0 上线了——尽早发布,尽早发现
前端·后端·程序员
怕浪猫10 小时前
第一章 JSX 增强特性与函数组件入门
前端·javascript·react.js
铅笔侠_小龙虾10 小时前
Emmet 常用用法指南
前端·vue
没有bug.的程序员10 小时前
服务安全:内部服务如何防止“裸奔”?
java·网络安全·云原生安全·服务安全·零信任架构·微服务安全·内部鉴权