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>
相关推荐
benbenAItalk6 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
sunshine22 girl6 小时前
Java学习二 基本语法2, 算术运算符
java·学习
niucloud-admin6 小时前
JAVA V6 多商户商城 开发文档——插件目录结构
java·开发语言
2601_962885726 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
滕州市燕猫虎计算机科技工作室个体工商户6 小时前
Java锁
java·开发语言
西瓜太郎12347 小时前
Claude Code、Codex CLI、Gemini CLI 能否共用一枚 Key?先看协议选择矩阵
前端·api 网关·claude code·gemini cli·codex cli
shehuiyuelaiyuehao8 小时前
1计算机是如何工作的
java·计算机网络
陈随易9 小时前
在Finch用了62亿词元,我认为这是新一代Agent工具之神
前端·人工智能·后端
Jae den9 小时前
网络延迟为什么会影响游戏和实时业务?
网络·游戏
letisgo59 小时前
JAVA 高级进阶07篇《@Transactional失效的8个场景:代理机制到传播行为》
java·面试·transactional·spring事务·aop动态代理