一个网页版五子棋小游戏,四种难度供您选择对弈。

游戏地址: AI对弈五子棋 https://amitofo.icu/game2.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>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #0f2027 0%, #203a43 50%, #2c5364 100%);
            color: #f0f0f0;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            overflow-x: hidden;
        }
        
        .header {
            text-align: center;
            margin-bottom: 20px;
            width: 100%;
            max-width: 1000px;
        }
        
        h1 {
            color: #4dc3ff;
            font-size: 2.8rem;
            margin-bottom: 10px;
            text-shadow: 0 0 15px rgba(77, 195, 255, 0.7);
            letter-spacing: 2px;
        }
        
        .subtitle {
            color: #a9d1e8;
            font-size: 1.2rem;
            margin-bottom: 25px;
        }
        
        .music-controls {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 15px;
            margin-top: 10px;
        }
        
        .music-btn {
            background: rgba(77, 195, 255, 0.2);
            border: 2px solid rgba(77, 195, 255, 0.5);
            color: #4dc3ff;
            padding: 8px 16px;
            border-radius: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 0.9rem;
            transition: all 0.3s;
        }
        
        .music-btn:hover {
            background: rgba(77, 195, 255, 0.3);
            transform: translateY(-2px);
        }
        
        .game-container {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 40px;
            width: 100%;
            max-width: 1200px;
        }
        
        .board-section {
            flex: 1;
            min-width: 520px;
            max-width: 600px;
        }
        
        .info-section {
            flex: 1;
            min-width: 320px;
            max-width: 450px;
            background-color: rgba(20, 30, 40, 0.85);
            border-radius: 15px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
            border: 1px solid rgba(77, 195, 255, 0.3);
        }
        
        .board-container {
            position: relative;
            background-color: #c19a6b;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 15px 35px rgba(0, 0, 0, 0.8);
            border: 8px solid #8b5a2b;
        }
        
        #game-board {
            display: grid;
            grid-template-columns: repeat(15, 1fr);
            grid-template-rows: repeat(15, 1fr);
            gap: 0;
            width: 100%;
            aspect-ratio: 1 / 1;
            background-color: #e8c9a1;
            position: relative;
        }
        
        .cell {
            border-right: 1px solid #8b5a2b;
            border-bottom: 1px solid #8b5a2b;
            position: relative;
            cursor: pointer;
        }
        
        .cell:hover {
            background-color: rgba(139, 90, 43, 0.15);
        }
        
        .cell:nth-child(15n) {
            border-right: none;
        }
        
        .cell:nth-child(n+211) {
            border-bottom: none;
        }
        
        .stone {
            position: absolute;
            width: 90%;
            height: 90%;
            top: 5%;
            left: 5%;
            border-radius: 50%;
            z-index: 10;
            box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.6), 3px 3px 8px rgba(0, 0, 0, 0.4);
            transition: all 0.3s;
            animation: stoneAppear 0.3s ease-out;
        }
        
        @keyframes stoneAppear {
            0% { transform: scale(0); opacity: 0; }
            70% { transform: scale(1.1); opacity: 0.8; }
            100% { transform: scale(1); opacity: 1; }
        }
        
        .black {
            background: radial-gradient(circle at 30% 30%, #555, #000 70%);
        }
        
        .white {
            background: radial-gradient(circle at 30% 30%, #fff, #aaa 70%);
        }
        
        .last-move {
            box-shadow: 0 0 0 4px rgba(255, 50, 50, 0.9);
        }
        
        .hint-cell {
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0% { background-color: rgba(255, 215, 0, 0.3); }
            50% { background-color: rgba(255, 215, 0, 0.7); }
            100% { background-color: rgba(255, 215, 0, 0.3); }
        }
        
        .game-info {
            margin-bottom: 25px;
        }
        
        .status-panel {
            display: flex;
            align-items: center;
            justify-content: space-between;
            background-color: rgba(30, 40, 50, 0.9);
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 25px;
            border: 2px solid rgba(77, 195, 255, 0.2);
        }
        
        .player-info {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
            flex: 1;
        }
        
        .player-name {
            font-size: 1.3rem;
            font-weight: bold;
        }
        
        .human-player .player-name {
            color: #4dc3ff;
        }
        
        .ai-player .player-name {
            color: #ff6b6b;
        }
        
        .player-icon {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.8rem;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
        }
        
        .human-icon {
            background: radial-gradient(circle at 30% 30%, #4dc3ff, #1a8cff);
            color: white;
        }
        
        .ai-icon {
            background: radial-gradient(circle at 30% 30%, #ff6b6b, #ff3333);
            color: white;
        }
        
        .active-player {
            transform: scale(1.1);
            box-shadow: 0 0 20px rgba(77, 195, 255, 0.9);
            transition: all 0.3s;
        }
        
        .vs-text {
            font-size: 1.8rem;
            font-weight: bold;
            color: #ffd700;
            margin: 0 20px;
        }
        
        .game-controls {
            margin-bottom: 30px;
        }
        
        .control-title {
            font-size: 1.3rem;
            margin-bottom: 15px;
            color: #4dc3ff;
        }
        
        .difficulty-selector {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }
        
        .difficulty-btn {
            flex: 1;
            min-width: 80px;
            padding: 10px 15px;
            border: none;
            border-radius: 8px;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s;
            background-color: rgba(60, 80, 100, 0.8);
            color: #ccc;
        }
        
        .difficulty-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .difficulty-btn.active {
            background-color: #4dc3ff;
            color: white;
            box-shadow: 0 0 15px rgba(77, 195, 255, 0.7);
        }
        
        .btn-group {
            display: flex;
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .btn {
            flex: 1;
            min-width: 120px;
            padding: 12px 20px;
            border: none;
            border-radius: 8px;
            font-size: 1.1rem;
            font-weight: bold;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            transition: all 0.3s;
        }
        
        .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .btn:active {
            transform: translateY(0);
        }
        
        .btn-new-game {
            background: linear-gradient(to right, #00b09b, #96c93d);
            color: white;
        }
        
        .btn-undo {
            background: linear-gradient(to right, #ff9966, #ff5e62);
            color: white;
        }
        
        .btn-hint {
            background: linear-gradient(to right, #ffcc00, #ff9900);
            color: white;
        }
        
        .btn-settings {
            background: linear-gradient(to right, #9d50bb, #6e48aa);
            color: white;
        }
        
        .game-stats {
            background-color: rgba(30, 40, 50, 0.9);
            padding: 20px;
            border-radius: 10px;
            border: 2px solid rgba(77, 195, 255, 0.2);
        }
        
        .stats-title {
            font-size: 1.3rem;
            margin-bottom: 15px;
            color: #ffd700;
            border-bottom: 1px solid #555;
            padding-bottom: 8px;
        }
        
        .stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }
        
        .stat-item {
            display: flex;
            flex-direction: column;
        }
        
        .stat-label {
            font-size: 0.9rem;
            color: #aaa;
            margin-bottom: 5px;
        }
        
        .stat-value {
            font-size: 1.5rem;
            font-weight: bold;
            color: #fff;
        }
        
        .ai-thinking {
            display: none;
            text-align: center;
            margin-top: 15px;
            padding: 10px;
            background-color: rgba(255, 107, 107, 0.2);
            border-radius: 8px;
            color: #ffcc00;
            font-style: italic;
        }
        
        .thinking-dots {
            display: inline-block;
            animation: dots 1.5s infinite;
        }
        
        @keyframes dots {
            0%, 20% { content: "."; }
            40% { content: ".."; }
            60%, 100% { content: "..."; }
        }
        
        .winner-message {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: rgba(0, 0, 0, 0.95);
            color: white;
            padding: 40px 60px;
            border-radius: 15px;
            text-align: center;
            z-index: 100;
            display: none;
            box-shadow: 0 0 50px rgba(77, 195, 255, 0.8);
            border: 3px solid #4dc3ff;
            animation: popIn 0.5s;
            min-width: 400px;
        }
        
        @keyframes popIn {
            0% { transform: translate(-50%, -50%) scale(0.5); opacity: 0; }
            100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
        }
        
        .winner-title {
            font-size: 2.5rem;
            color: #ffd700;
            margin-bottom: 20px;
        }
        
        .winner-desc {
            font-size: 1.3rem;
            margin-bottom: 30px;
        }
        
        .winner-buttons {
            display: flex;
            gap: 15px;
            justify-content: center;
        }
        
        .btn-close {
            background-color: #4dc3ff;
            color: #000;
            font-weight: bold;
            padding: 12px 30px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1.1rem;
            flex: 1;
        }
        
        .btn-rematch {
            background-color: #ffd700;
            color: #000;
            font-weight: bold;
            padding: 12px 30px;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1.1rem;
            flex: 1;
        }
        
        .footer {
            margin-top: 40px;
            text-align: center;
            color: #88aabb;
            font-size: 0.9rem;
            width: 100%;
            max-width: 1000px;
        }
        
        .rules {
            margin-top: 15px;
            font-size: 0.9rem;
            color: #aaccdd;
            line-height: 1.5;
            max-width: 800px;
            margin-left: auto;
            margin-right: auto;
        }
        
        .volume-control {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
            justify-content: center;
        }
        
        .volume-slider {
            width: 150px;
        }
        
        @media (max-width: 1100px) {
            .game-container {
                flex-direction: column;
                align-items: center;
            }
            
            .board-section, .info-section {
                min-width: 90%;
            }
        }
        
        @media (max-width: 600px) {
            h1 {
                font-size: 2rem;
            }
            
            .board-section {
                min-width: 95%;
            }
            
            #game-board {
                grid-template-columns: repeat(15, 1fr);
                grid-template-rows: repeat(15, 1fr);
            }
            
            .status-panel {
                flex-direction: column;
                gap: 20px;
            }
            
            .vs-text {
                margin: 10px 0;
            }
            
            .winner-message {
                min-width: 90%;
                padding: 30px 20px;
            }
            
            .btn {
                min-width: 100%;
            }
            
            .music-controls {
                flex-direction: column;
                gap: 10px;
            }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1><i class="fas fa-robot"></i> 五子棋 </h1>
        <p class="subtitle">享受沉浸式AI对弈体验</p>
        
        <div class="music-controls">
            <button class="music-btn" id="toggle-music">
                <i class="fas fa-music"></i> <span id="music-text">背景音乐: 开</span>
            </button>
            <button class="music-btn" id="toggle-sound">
                <i class="fas fa-volume-up"></i> <span id="sound-text">音效: 开</span>
            </button>
            
            <div class="volume-control">
                <i class="fas fa-volume-down"></i>
                <input type="range" min="0" max="100" value="70" class="volume-slider" id="volume-slider">
                <i class="fas fa-volume-up"></i>
            </div>
        </div>
    </div>
    
    <div class="game-container">
        <div class="board-section">
            <div class="board-container">
                <div id="game-board"></div>
            </div>
        </div>
        
        <div class="info-section">
            <div class="game-info">
                <h2>对战状态</h2>
                <div class="status-panel">
                    <div class="player-info human-player">
                        <div class="player-icon human-icon active-player" id="human-icon">
                            <i class="fas fa-user"></i>
                        </div>
                        <div class="player-name">玩家 (黑子)</div>
                        <div class="player-status" id="human-status">你的回合</div>
                    </div>
                    
                    <div class="vs-text">VS</div>
                    
                    <div class="player-info ai-player">
                        <div class="player-icon ai-icon" id="ai-icon">
                            <i class="fas fa-robot"></i>
                        </div>
                        <div class="player-name" id="ai-name">电脑 (白子)</div>
                        <div class="player-status" id="ai-status">等待中</div>
                    </div>
                </div>
                
                <div class="ai-thinking" id="ai-thinking">
                    <i class="fas fa-cog fa-spin"></i> AI思考中<span class="thinking-dots"></span>
                </div>
            </div>
            
            <div class="game-controls">
                <h3 class="control-title">AI等级</h3>
                <div class="difficulty-selector">
                    <button class="difficulty-btn active" data-level="easy">声闻</button>
                    <button class="difficulty-btn" data-level="medium">圆觉</button>
                    <button class="difficulty-btn" data-level="hard">菩萨</button>
                    <button class="difficulty-btn" data-level="expert">佛陀</button>
                </div>
                
                <div class="btn-group">
                    <button class="btn btn-new-game" id="new-game">
                        <i class="fas fa-play-circle"></i> 新游戏
                    </button>
                    <button class="btn btn-undo" id="undo">
                        <i class="fas fa-undo"></i> 悔棋
                    </button>
                    <button class="btn btn-hint" id="hint">
                        <i class="fas fa-lightbulb"></i> 提示
                    </button>
                    <button class="btn btn-settings" id="toggle-first">
                        <i class="fas fa-chess-board"></i> 玩家先手
                    </button>
                </div>
            </div>
            
            <div class="game-stats">
                <h3 class="stats-title">游戏三昧</h3>
                <div class="stats-grid">
                    <div class="stat-item">
                        <div class="stat-label">功德数</div>
                        <div class="stat-value" id="move-count">0</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-label">入定时间</div>
                        <div class="stat-value" id="game-time">00:00</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-label">玩家胜局</div>
                        <div class="stat-value" id="human-wins">0</div>
                    </div>
                    <div class="stat-item">
                        <div class="stat-label">AI胜局</div>
                        <div class="stat-value" id="ai-wins">0</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <div class="winner-message" id="winner-message">
        <h2 class="winner-title" id="winner-title">游戏结束!</h2>
        <p class="winner-desc" id="winner-text">恭喜您获得胜利!</p>
        <div class="winner-buttons">
            <button class="btn-rematch" id="rematch">再来一局</button>
            <button class="btn-close" id="close-winner">关闭</button>
        </div>
    </div>
    
    <div class="footer">
        <p>© 2026 五子棋</p>
        <div class="rules">
            <p><strong>游戏说明:</strong> 玩家执黑子,AI执白子。轮流在棋盘上放置棋子,先形成横、竖、斜方向连续五个或以上相同棋子的一方获胜。</p>
            <p><strong>音效说明:</strong> 游戏开始时自动播放背景音乐,可在上方控制面板调节音量。</p>
        </div>
    </div>

    <!-- 音频元素 - 使用本地文件 -->
    <audio id="background-music" loop>
        <source src="beijing.ogg" type="audio/ogg">
        <source src="beijing.mp3" type="audio/mpeg">
        您的浏览器不支持音频元素。
    </audio>
    
    <audio id="move-sound">
        <source src="xiaochu.mp3" type="audio/mpeg">
        您的浏览器不支持音频元素。
    </audio>
    
    <audio id="ai-move-sound">
        <source src="ai.mp3" type="audio/mpeg">
        您的浏览器不支持音频元素。
    </audio>
    
    <audio id="win-sound">
        <source src="win.mp3" type="audio/mpeg">
        您的浏览器不支持音频元素。
    </audio>

    <script>
        // 游戏状态变量
        let board = [];
        let currentPlayer = 'human'; // 'human' 或 'ai'
        let gameOver = false;
        let moveHistory = [];
        let scores = { human: 0, ai: 0 };
        let moveCount = 0;
        let gameStartTime = null;
        let gameTimer = null;
        let lastMoveCell = null;
        let hintCell = null;
        let playerFirst = true;
        let aiDifficulty = 'medium';
        let aiThinking = false;
        
        // 音效控制变量
        let musicEnabled = true;
        let soundEnabled = true;
        let backgroundMusic = document.getElementById('background-music');
        let moveSound = document.getElementById('move-sound');
        let aiMoveSound = document.getElementById('ai-move-sound');
        let winSound = document.getElementById('win-sound');
        
        // 音频播放状态
        let userInteracted = false;
        
        // DOM元素
        const gameBoard = document.getElementById('game-board');
        const humanWinsEl = document.getElementById('human-wins');
        const aiWinsEl = document.getElementById('ai-wins');
        const moveCountEl = document.getElementById('move-count');
        const gameTimeEl = document.getElementById('game-time');
        const humanIcon = document.getElementById('human-icon');
        const aiIcon = document.getElementById('ai-icon');
        const humanStatus = document.getElementById('human-status');
        const aiStatus = document.getElementById('ai-status');
        const aiName = document.getElementById('ai-name');
        const aiThinkingEl = document.getElementById('ai-thinking');
        const newGameBtn = document.getElementById('new-game');
        const undoBtn = document.getElementById('undo');
        const hintBtn = document.getElementById('hint');
        const toggleFirstBtn = document.getElementById('toggle-first');
        const difficultyBtns = document.querySelectorAll('.difficulty-btn');
        const winnerMessage = document.getElementById('winner-message');
        const winnerTitle = document.getElementById('winner-title');
        const winnerText = document.getElementById('winner-text');
        const closeWinnerBtn = document.getElementById('close-winner');
        const rematchBtn = document.getElementById('rematch');
        const toggleMusicBtn = document.getElementById('toggle-music');
        const toggleSoundBtn = document.getElementById('toggle-sound');
        const volumeSlider = document.getElementById('volume-slider');
        const musicText = document.getElementById('music-text');
        const soundText = document.getElementById('sound-text');
        
        // 初始化游戏
        function initGame() {
            // 清空棋盘
            board = [];
            for (let i = 0; i < 15; i++) {
                board[i] = [];
                for (let j = 0; j < 15; j++) {
                    board[i][j] = '';
                }
            }
            
            // 清空游戏板
            gameBoard.innerHTML = '';
            
            // 创建棋盘格子
            for (let i = 0; i < 15 * 15; i++) {
                const cell = document.createElement('div');
                cell.classList.add('cell');
                cell.dataset.row = Math.floor(i / 15);
                cell.dataset.col = i % 15;
                
                cell.addEventListener('click', () => makeMove(cell));
                gameBoard.appendChild(cell);
            }
            
            // 重置游戏状态
            currentPlayer = playerFirst ? 'human' : 'ai';
            gameOver = false;
            moveHistory = [];
            moveCount = 0;
            moveCountEl.textContent = moveCount;
            aiThinking = false;
            aiThinkingEl.style.display = 'none';
            
            // 清除提示
            if (hintCell) {
                hintCell.classList.remove('hint-cell');
                hintCell = null;
            }
            
            // 重置计时器
            if (gameTimer) {
                clearInterval(gameTimer);
            }
            gameStartTime = new Date();
            gameTimer = setInterval(updateGameTime, 1000);
            updateGameTime();
            
            // 更新玩家指示器
            updatePlayerIndicator();
            
            // 隐藏获胜消息
            winnerMessage.style.display = 'none';
            
            // 清除最后一步标记
            if (lastMoveCell) {
                lastMoveCell.classList.remove('last-move');
                lastMoveCell = null;
            }
            
            // 更新AI名称
            updateAIName();
            
            // 预加载音频
            preloadAudio();
            
            // 尝试播放背景音乐
            setTimeout(() => {
                playBackgroundMusic();
            }, 500);
            
            // 如果AI先手,则AI先走
            if (currentPlayer === 'ai') {
                setTimeout(() => aiMakeMove(), 1000);
            }
        }
        
        // 预加载音频
        function preloadAudio() {
            try {
                backgroundMusic.load();
                moveSound.load();
                aiMoveSound.load();
                winSound.load();
            } catch (e) {
                console.log("音频预加载失败:", e);
            }
        }
        
        // 播放背景音乐
        function playBackgroundMusic() {
            if (!musicEnabled || !userInteracted) return;
            
            try {
                const volume = volumeSlider.value / 100;
                backgroundMusic.volume = volume;
                
                // 重置并播放
                backgroundMusic.currentTime = 0;
                const playPromise = backgroundMusic.play();
                
                if (playPromise !== undefined) {
                    playPromise.catch(error => {
                        console.log("背景音乐播放失败:", error);
                    });
                }
            } catch (e) {
                console.log("播放背景音乐时出错:", e);
            }
        }
        
        // 播放落子音效(玩家)
        function playMoveSound() {
            if (!soundEnabled || !userInteracted) return;
            
            try {
                const volume = volumeSlider.value / 100;
                moveSound.volume = volume;
                moveSound.currentTime = 0;
                moveSound.play().catch(e => {
                    console.log("落子音效播放失败:", e);
                });
            } catch (e) {
                console.log("播放落子音效时出错:", e);
            }
        }
        
        // 播放AI落子音效
        function playAiMoveSound() {
            if (!soundEnabled || !userInteracted) return;
            
            try {
                const volume = volumeSlider.value / 100;
                aiMoveSound.volume = volume;
                aiMoveSound.currentTime = 0;
                aiMoveSound.play().catch(e => {
                    console.log("AI落子音效播放失败:", e);
                });
            } catch (e) {
                console.log("播放AI落子音效时出错:", e);
            }
        }
        
        // 播放胜利音效
        function playWinSound() {
            if (!soundEnabled || !userInteracted) return;
            
            try {
                const volume = volumeSlider.value / 100;
                winSound.volume = volume;
                winSound.currentTime = 0;
                winSound.play().catch(e => {
                    console.log("胜利音效播放失败:", e);
                });
            } catch (e) {
                console.log("播放胜利音效时出错:", e);
            }
        }
        
        // 更新AI名称
        function updateAIName() {
            const difficultyNames = {
                'easy': '声闻AI',
                'medium': '圆觉AI',
                'hard': '菩萨AI',
                'expert': '佛陀AI'
            };
            aiName.textContent = `${difficultyNames[aiDifficulty]} (白子)`;
        }
        
        // 更新玩家指示器
        function updatePlayerIndicator() {
            if (currentPlayer === 'human') {
                humanIcon.classList.add('active-player');
                aiIcon.classList.remove('active-player');
                humanStatus.textContent = '你的回合';
                aiStatus.textContent = '等待中';
            } else {
                aiIcon.classList.add('active-player');
                humanIcon.classList.remove('active-player');
                humanStatus.textContent = '等待中';
                aiStatus.textContent = '思考中';
            }
        }
        
        // 更新游戏时间
        function updateGameTime() {
            if (!gameStartTime) return;
            
            const now = new Date();
            const diff = Math.floor((now - gameStartTime) / 1000);
            const minutes = Math.floor(diff / 60).toString().padStart(2, '0');
            const seconds = (diff % 60).toString().padStart(2, '0');
            
            gameTimeEl.textContent = `${minutes}:${seconds}`;
        }
        
        // 玩家落子
        function makeMove(cell) {
            if (gameOver || currentPlayer !== 'human' || aiThinking) return;
            
            const row = parseInt(cell.dataset.row);
            const col = parseInt(cell.dataset.col);
            
            // 如果该位置已有棋子,则忽略
            if (board[row][col] !== '') return;
            
            // 放置棋子
            board[row][col] = 'black';
            moveHistory.push({row, col, player: 'human'});
            moveCount++;
            moveCountEl.textContent = moveCount;
            
            // 创建棋子元素
            const stone = document.createElement('div');
            stone.classList.add('stone', 'black');
            cell.appendChild(stone);
            
            // 清除提示
            if (hintCell) {
                hintCell.classList.remove('hint-cell');
                hintCell = null;
            }
            
            // 标记最后一步
            if (lastMoveCell) {
                lastMoveCell.classList.remove('last-move');
            }
            cell.classList.add('last-move');
            lastMoveCell = cell;
            
            // 播放落子音效
            playMoveSound();
            
            // 检查胜负
            if (checkWin(row, col, 'black')) {
                endGame('human');
                return;
            }
            
            // 检查平局
            if (moveCount >= 15 * 15) {
                endGame('draw');
                return;
            }
            
            // 切换玩家
            currentPlayer = 'ai';
            updatePlayerIndicator();
            
            // AI思考
            setTimeout(() => aiMakeMove(), 500);
        }
        
        // AI落子
        function aiMakeMove() {
            if (gameOver || currentPlayer !== 'ai') return;
            
            aiThinking = true;
            aiThinkingEl.style.display = 'block';
            
            // 根据难度设置不同的思考时间
            const thinkTime = aiDifficulty === 'easy' ? 300 : 
                             aiDifficulty === 'medium' ? 600 : 
                             aiDifficulty === 'hard' ? 900 : 1200;
            
            setTimeout(() => {
                const move = getAIMove();
                if (!move) return;
                
                const {row, col} = move;
                board[row][col] = 'white';
                moveHistory.push({row, col, player: 'ai'});
                moveCount++;
                moveCountEl.textContent = moveCount;
                
                // 创建棋子元素
                const cellIndex = row * 15 + col;
                const cell = gameBoard.children[cellIndex];
                const stone = document.createElement('div');
                stone.classList.add('stone', 'white');
                cell.appendChild(stone);
                
                // 标记最后一步
                if (lastMoveCell) {
                    lastMoveCell.classList.remove('last-move');
                }
                cell.classList.add('last-move');
                lastMoveCell = cell;
                
                // 播放AI落子音效
                playAiMoveSound();
                
                // 检查胜负
                if (checkWin(row, col, 'white')) {
                    endGame('ai');
                    return;
                }
                
                // 检查平局
                if (moveCount >= 15 * 15) {
                    endGame('draw');
                    return;
                }
                
                // 切换玩家
                currentPlayer = 'human';
                aiThinking = false;
                aiThinkingEl.style.display = 'none';
                updatePlayerIndicator();
                
            }, thinkTime);
        }
        
        // 获取AI移动位置
        function getAIMove() {
            const emptyCells = [];
            for (let i = 0; i < 15; i++) {
                for (let j = 0; j < 15; j++) {
                    if (board[i][j] === '') {
                        emptyCells.push({row: i, col: j});
                    }
                }
            }
            
            if (emptyCells.length === 0) return null;
            
            // 简单难度:随机选择
            if (aiDifficulty === 'easy') {
                return emptyCells[Math.floor(Math.random() * emptyCells.length)];
            }
            
            // 其他难度:使用启发式评估
            let bestScore = -Infinity;
            let bestMoves = [];
            
            for (const cell of emptyCells) {
                const {row, col} = cell;
                let score = 0;
                
                // 进攻:评估自己的潜在连线
                board[row][col] = 'white';
                score += evaluatePosition(row, col, 'white') * 2;
                board[row][col] = '';
                
                // 防守:评估对手的潜在连线
                board[row][col] = 'black';
                score += evaluatePosition(row, col, 'black');
                board[row][col] = '';
                
                // 中心偏好
                const centerDist = Math.abs(row - 7) + Math.abs(col - 7);
                score += (14 - centerDist) * 0.5;
                
                // 根据难度调整进攻/防守权重
                if (aiDifficulty === 'medium') {
                    score += Math.random() * 10; // 增加随机性
                } else if (aiDifficulty === 'hard' || aiDifficulty === 'expert') {
                    // 高级策略:优先形成四连、三连
                    board[row][col] = 'white';
                    const whiteLines = getLineCounts(row, col, 'white');
                    score += whiteLines.four * 1000 + whiteLines.three * 100 + whiteLines.two * 10;
                    board[row][col] = '';
                    
                    // 阻止对手形成四连、三连
                    board[row][col] = 'black';
                    const blackLines = getLineCounts(row, col, 'black');
                    score += blackLines.four * 800 + blackLines.three * 80;
                    board[row][col] = '';
                    
                    // 专家难度额外考虑更远的位置
                    if (aiDifficulty === 'expert') {
                        // 评估两步后的情况
                        score += evaluateTwoStep(row, col, 'white') * 0.5;
                    }
                }
                
                if (score > bestScore) {
                    bestScore = score;
                    bestMoves = [cell];
                } else if (score === bestScore) {
                    bestMoves.push(cell);
                }
            }
            
            // 从最佳选择中随机选一个(增加不可预测性)
            return bestMoves[Math.floor(Math.random() * bestMoves.length)];
        }
        
        // 评估位置得分
        function evaluatePosition(row, col, player) {
            const directions = [[0, 1], [1, 0], [1, 1], [1, -1]];
            let totalScore = 0;
            
            for (const [dx, dy] of directions) {
                let line = 1; // 当前位置
                let openEnds = 0;
                
                // 正向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row + dx * i;
                    const newCol = col + dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        line++;
                    } else if (board[newRow][newCol] === '') {
                        openEnds++;
                        break;
                    } else {
                        break;
                    }
                }
                
                // 反向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row - dx * i;
                    const newCol = col - dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        line++;
                    } else if (board[newRow][newCol] === '') {
                        openEnds++;
                        break;
                    } else {
                        break;
                    }
                }
                
                // 根据连线长度和开放端评分
                if (line >= 5) {
                    totalScore += 100000; // 胜利
                } else if (line === 4) {
                    totalScore += openEnds === 2 ? 10000 : openEnds === 1 ? 1000 : 0;
                } else if (line === 3) {
                    totalScore += openEnds === 2 ? 1000 : openEnds === 1 ? 100 : 0;
                } else if (line === 2) {
                    totalScore += openEnds === 2 ? 100 : openEnds === 1 ? 10 : 0;
                }
            }
            
            return totalScore;
        }
        
        // 获取连线数量
        function getLineCounts(row, col, player) {
            const directions = [[0, 1], [1, 0], [1, 1], [1, -1]];
            const counts = {two: 0, three: 0, four: 0};
            
            for (const [dx, dy] of directions) {
                let line = 1;
                
                // 正向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row + dx * i;
                    const newCol = col + dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        line++;
                    } else {
                        break;
                    }
                }
                
                // 反向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row - dx * i;
                    const newCol = col - dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        line++;
                    } else {
                        break;
                    }
                }
                
                if (line >= 5) {
                    // 胜利情况已经在别处处理
                } else if (line === 4) {
                    counts.four++;
                } else if (line === 3) {
                    counts.three++;
                } else if (line === 2) {
                    counts.two++;
                }
            }
            
            return counts;
        }
        
        // 评估两步后的情况(简化版)
        function evaluateTwoStep(row, col, player) {
            let score = 0;
            
            // 模拟在此位置落子
            board[row][col] = player;
            
            // 检查对手的最佳应对
            const opponent = player === 'white' ? 'black' : 'white';
            let bestOpponentScore = 0;
            
            // 简单评估对手可能的反击
            for (let i = 0; i < 15; i++) {
                for (let j = 0; j < 15; j++) {
                    if (board[i][j] === '') {
                        board[i][j] = opponent;
                        const opponentScore = evaluatePosition(i, j, opponent);
                        if (opponentScore > bestOpponentScore) {
                            bestOpponentScore = opponentScore;
                        }
                        board[i][j] = '';
                    }
                }
            }
            
            // 还原棋盘
            board[row][col] = '';
            
            // 自己的得分减去对手的最佳得分
            const myScore = evaluatePosition(row, col, player);
            score = myScore - bestOpponentScore * 0.5;
            
            return score;
        }
        
        // 检查是否获胜
        function checkWin(row, col, player) {
            const directions = [
                [0, 1],   // 水平
                [1, 0],   // 垂直
                [1, 1],   // 对角线
                [1, -1]   // 反对角线
            ];
            
            for (const [dx, dy] of directions) {
                let count = 1;
                
                // 正向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row + dx * i;
                    const newCol = col + dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        count++;
                    } else {
                        break;
                    }
                }
                
                // 反向检查
                for (let i = 1; i <= 4; i++) {
                    const newRow = row - dx * i;
                    const newCol = col - dy * i;
                    
                    if (newRow < 0 || newRow >= 15 || newCol < 0 || newCol >= 15) break;
                    if (board[newRow][newCol] === player) {
                        count++;
                    } else {
                        break;
                    }
                }
                
                if (count >= 5) {
                    return true;
                }
            }
            
            return false;
        }
        
        // 结束游戏
        function endGame(winner) {
            gameOver = true;
            aiThinking = false;
            aiThinkingEl.style.display = 'none';
            clearInterval(gameTimer);
            
            // 播放胜利音效
            playWinSound();
            
            if (winner === 'human') {
                scores.human++;
                humanWinsEl.textContent = scores.human;
                winnerTitle.textContent = "恭喜你获胜!";
                winnerText.textContent = "玩家(黑子)获得胜利!";
            } else if (winner === 'ai') {
                scores.ai++;
                aiWinsEl.textContent = scores.ai;
                winnerTitle.textContent = "AI获胜!";
                winnerText.textContent = `${aiName.textContent}获得胜利!`;
            } else {
                winnerTitle.textContent = "平局!";
                winnerText.textContent = "棋盘已满,双方平手!";
            }
            
            winnerMessage.style.display = 'block';
        }
        
        // 悔棋
        function undoMove() {
            if (moveHistory.length === 0 || gameOver || aiThinking) return;
            
            // 悔一步(如果是玩家的回合,需要悔两步,因为上一步是AI走的)
            let stepsToUndo = currentPlayer === 'human' ? 2 : 1;
            stepsToUndo = Math.min(stepsToUndo, moveHistory.length);
            
            for (let i = 0; i < stepsToUndo; i++) {
                const lastMove = moveHistory.pop();
                const {row, col} = lastMove;
                
                // 从棋盘移除棋子
                board[row][col] = '';
                moveCount--;
                moveCountEl.textContent = moveCount;
                
                // 从DOM移除棋子
                const cellIndex = row * 15 + col;
                const cell = gameBoard.children[cellIndex];
                cell.innerHTML = '';
                cell.classList.remove('last-move');
            }
            
            // 恢复上一步的最后一步标记
            if (moveHistory.length > 0) {
                const prevMove = moveHistory[moveHistory.length - 1];
                const prevCellIndex = prevMove.row * 15 + prevMove.col;
                const prevCell = gameBoard.children[prevCellIndex];
                prevCell.classList.add('last-move');
                lastMoveCell = prevCell;
                
                // 更新当前玩家
                currentPlayer = prevMove.player === 'human' ? 'human' : 'ai';
            } else {
                lastMoveCell = null;
                currentPlayer = playerFirst ? 'human' : 'ai';
            }
            
            updatePlayerIndicator();
        }
        
        // 提示功能
        function showHint() {
            if (gameOver || currentPlayer !== 'human' || aiThinking) return;
            
            // 清除之前的提示
            if (hintCell) {
                hintCell.classList.remove('hint-cell');
            }
            
            // 获取AI推荐的位置
            const hint = getAIMove();
            if (!hint) return;
            
            const cellIndex = hint.row * 15 + hint.col;
            hintCell = gameBoard.children[cellIndex];
            hintCell.classList.add('hint-cell');
        }
        
        // 事件监听
        newGameBtn.addEventListener('click', initGame);
        
        undoBtn.addEventListener('click', undoMove);
        
        hintBtn.addEventListener('click', showHint);
        
        toggleFirstBtn.addEventListener('click', () => {
            playerFirst = !playerFirst;
            toggleFirstBtn.innerHTML = playerFirst ? 
                '<i class="fas fa-chess-board"></i> 玩家先手' : 
                '<i class="fas fa-robot"></i> AI先手';
            initGame();
        });
        
        // 难度选择
        difficultyBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                difficultyBtns.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                aiDifficulty = btn.dataset.level;
                updateAIName();
                
                // 如果游戏正在进行,重新开始
                if (moveCount > 0) {
                    if (confirm("切换难度将重新开始游戏,确定吗?")) {
                        initGame();
                    } else {
                        // 恢复之前的难度
                        difficultyBtns.forEach(b => {
                            if (b.dataset.level === aiDifficulty) {
                                b.classList.remove('active');
                            }
                        });
                        difficultyBtns.forEach(b => {
                            if (b.dataset.level === aiDifficulty) {
                                b.classList.add('active');
                            }
                        });
                    }
                }
            });
        });
        
        closeWinnerBtn.addEventListener('click', () => {
            winnerMessage.style.display = 'none';
        });
        
        rematchBtn.addEventListener('click', () => {
            winnerMessage.style.display = 'none';
            initGame();
        });
        
        // 音乐控制
        toggleMusicBtn.addEventListener('click', () => {
            musicEnabled = !musicEnabled;
            musicText.textContent = `背景音乐: ${musicEnabled ? '开' : '关'}`;
            
            if (musicEnabled) {
                playBackgroundMusic();
            } else {
                backgroundMusic.pause();
            }
        });
        
        // 音效控制
        toggleSoundBtn.addEventListener('click', () => {
            soundEnabled = !soundEnabled;
            soundText.textContent = `音效: ${soundEnabled ? '开' : '关'}`;
        });
        
        // 音量控制
        volumeSlider.addEventListener('input', () => {
            const volume = volumeSlider.value / 100;
            backgroundMusic.volume = volume;
            moveSound.volume = volume;
            aiMoveSound.volume = volume;
            winSound.volume = volume;
            
            // 如果用户调整音量,视为用户交互
            userInteracted = true;
        });
        
        // 用户交互处理(解决音频自动播放问题)
        document.addEventListener('click', () => {
            if (!userInteracted) {
                userInteracted = true;
                // 用户第一次点击后播放背景音乐
                if (musicEnabled && backgroundMusic.paused) {
                    playBackgroundMusic();
                }
            }
        });
        
        document.addEventListener('keydown', () => {
            if (!userInteracted) {
                userInteracted = true;
                // 用户第一次按键后播放背景音乐
                if (musicEnabled && backgroundMusic.paused) {
                    playBackgroundMusic();
                }
            }
        });
        
        // 初始化游戏
        initGame();
        
        // 添加键盘快捷键
        document.addEventListener('keydown', (e) => {
            if (e.key === 'n' || e.key === 'N') {
                initGame();
            } else if (e.key === 'z' && e.ctrlKey) {
                undoMove();
            } else if (e.key === 'h' || e.key === 'H') {
                showHint();
            } else if (e.key === 'Escape') {
                winnerMessage.style.display = 'none';
            } else if (e.key === 'f' || e.key === 'F') {
                playerFirst = !playerFirst;
                toggleFirstBtn.innerHTML = playerFirst ? 
                    '<i class="fas fa-chess-board"></i> 玩家先手' : 
                    '<i class="fas fa-robot"></i> AI先手';
                initGame();
            } else if (e.key === 'm' || e.key === 'M') {
                musicEnabled = !musicEnabled;
                musicText.textContent = `背景音乐: ${musicEnabled ? '开' : '关'}`;
                if (musicEnabled) {
                    playBackgroundMusic();
                } else {
                    backgroundMusic.pause();
                }
            }
        });
        
        // 显示音频使用说明
        console.log("游戏音频说明:");
        console.log("1. 背景音乐: beijing.ogg (循环播放)");
        console.log("2. 玩家落子音效: xiaochu.mp3");
        console.log("3. AI落子音效: ai.mp3");
        console.log("4. 胜利音效: win.mp3");
        console.log("请确保这些文件与HTML文件在同一目录下");
    </script>
</body>
</html>

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐