五子棋,一键生成

 

 

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋游戏</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#8B5A2B',
                        secondary: '#D2B48C',
                        board: '#DEB887',
                        black: '#000000',
                        white: '#FFFFFF',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .board-shadow {
                box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
            }
            .piece-transition {
                transition: all 0.2s ease-out;
            }
            .hover-cell:hover::before {
                content: '';
                position: absolute;
                width: 80%;
                height: 80%;
                border-radius: 50%;
                background-color: rgba(0, 0, 0, 0.1);
            }
        }
    </style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center p-4">
    <div class="max-w-4xl w-full bg-white rounded-xl shadow-lg overflow-hidden">
        <!-- 游戏标题 -->
        <div class="bg-primary text-white text-center py-4 px-6">
            <h1 class="text-2xl md:text-3xl font-bold flex items-center justify-center">
                <i class="fa fa-gamepad mr-3"></i>五子棋
            </h1>
        </div>
        
        <!-- 游戏区域 -->
        <div class="flex flex-col md:flex-row p-4 md:p-6">
            <!-- 左侧游戏信息 -->
            <div class="w-full md:w-1/4 mb-6 md:mb-0 md:pr-6">
                <div class="bg-gray-50 rounded-lg p-4 h-full flex flex-col">
                    <div class="mb-4">
                        <h2 class="text-lg font-semibold mb-2 text-gray-800 flex items-center">
                            <i class="fa fa-info-circle mr-2"></i>游戏信息
                        </h2>
                        <div class="space-y-3">
                            <div class="flex items-center">
                                <div class="w-6 h-6 rounded-full bg-black mr-3"></div>
                                <span>黑方先行</span>
                            </div>
                            <div class="flex items-center">
                                <div class="w-6 h-6 rounded-full bg-white border border-gray-300 mr-3"></div>
                                <span>白方后行</span>
                            </div>
                        </div>
                    </div>
                    
                    <div class="mb-4">
                        <h2 class="text-lg font-semibold mb-2 text-gray-800 flex items-center">
                            <i class="fa fa-trophy mr-2"></i>游戏状态
                        </h2>
                        <div id="status" class="py-2 px-3 bg-secondary/30 rounded-md text-center font-medium">
                            黑方回合
                        </div>
                    </div>
                    
                    <div class="mt-auto">
                        <button id="restartBtn" class="w-full py-3 px-4 bg-primary hover:bg-primary/90 text-white rounded-lg transition-all duration-300 flex items-center justify-center">
                            <i class="fa fa-refresh mr-2"></i>重新开始
                        </button>
                    </div>
                </div>
            </div>
            
            <!-- 右侧棋盘 -->
            <div class="w-full md:w-3/4 flex justify-center">
                <div class="relative">
                    <div id="board" class="bg-board rounded-lg board-shadow relative">
                        <!-- 棋盘将通过JavaScript动态生成 -->
                    </div>
                    
                    <!-- 胜利提示 -->
                    <div id="winMessage" class="hidden absolute inset-0 bg-black/50 flex items-center justify-center rounded-lg">
                        <div class="bg-white p-6 rounded-xl text-center shadow-xl">
                            <h2 class="text-2xl font-bold mb-4" id="winnerText"></h2>
                            <button id="newGameBtn" class="py-2 px-6 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
                                开始新游戏
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 游戏控制 -->
        <div class="bg-gray-50 p-4 border-t border-gray-200">
            <div class="flex flex-wrap justify-center gap-4">
                <button id="undoBtn" class="py-2 px-4 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors flex items-center">
                    <i class="fa fa-undo mr-2"></i>悔棋
                </button>
                <button id="hintBtn" class="py-2 px-4 bg-blue-100 hover:bg-blue-200 text-blue-800 rounded-lg transition-colors flex items-center">
                    <i class="fa fa-lightbulb-o mr-2"></i>提示
                </button>
                <button id="settingsBtn" class="py-2 px-4 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-lg transition-colors flex items-center">
                    <i class="fa fa-cog mr-2"></i>设置
                </button>
            </div>
        </div>
    </div>
    
    <!-- 设置模态框 -->
    <div id="settingsModal" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
        <div class="bg-white rounded-xl p-6 max-w-md w-full shadow-2xl">
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-xl font-bold">游戏设置</h2>
                <button id="closeSettingsBtn" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times"></i>
                </button>
            </div>
            
            <div class="space-y-4">
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">棋盘大小</label>
                    <select id="boardSize" class="w-full p-2 border border-gray-300 rounded-md">
                        <option value="11">11 x 11</option>
                        <option value="15" selected>15 x 15</option>
                        <option value="19">19 x 19</option>
                    </select>
                </div>
                
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">难度级别</label>
                    <select id="difficulty" class="w-full p-2 border border-gray-300 rounded-md">
                        <option value="easy">简单</option>
                        <option value="medium" selected>中等</option>
                        <option value="hard">困难</option>
                    </select>
                </div>
                
                <div class="pt-4">
                    <button id="saveSettingsBtn" class="w-full py-2 px-4 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
                        保存设置
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // 游戏常量
            const BOARD_SIZE = 15; // 默认棋盘大小
            const CELL_SIZE = 40; // 单元格大小(像素)
            const PIECE_SIZE = CELL_SIZE * 0.8; // 棋子大小
            
            // 游戏状态
            let currentPlayer = 'black'; // 'black' 或 'white'
            let gameBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
            let gameOver = false;
            let moveHistory = []; // 记录下棋历史
            let hintPosition = null; // 提示位置
            
            // DOM 元素
            const boardElement = document.getElementById('board');
            const statusElement = document.getElementById('status');
            const winMessageElement = document.getElementById('winMessage');
            const winnerTextElement = document.getElementById('winnerText');
            const restartBtn = document.getElementById('restartBtn');
            const undoBtn = document.getElementById('undoBtn');
            const hintBtn = document.getElementById('hintBtn');
            const settingsBtn = document.getElementById('settingsBtn');
            const settingsModal = document.getElementById('settingsModal');
            const closeSettingsBtn = document.getElementById('closeSettingsBtn');
            const saveSettingsBtn = document.getElementById('saveSettingsBtn');
            const boardSizeSelect = document.getElementById('boardSize');
            const difficultySelect = document.getElementById('difficulty');
            const newGameBtn = document.getElementById('newGameBtn');
            
            // 初始化棋盘
            function initializeBoard() {
                // 设置棋盘尺寸
                const boardDimension = CELL_SIZE * (BOARD_SIZE - 1);
                boardElement.style.width = `${boardDimension}px`;
                boardElement.style.height = `${boardDimension}px`;
                
                // 清空棋盘
                boardElement.innerHTML = '';
                
                // 创建棋盘单元格
                for (let row = 0; row < BOARD_SIZE; row++) {
                    for (let col = 0; col < BOARD_SIZE; col++) {
                        const cell = document.createElement('div');
                        cell.classList.add('absolute', 'hover-cell');
                        cell.style.width = `${CELL_SIZE}px`;
                        cell.style.height = `${CELL_SIZE}px`;
                        cell.style.left = `${col * CELL_SIZE}px`;
                        cell.style.top = `${row * CELL_SIZE}px`;
                        cell.dataset.row = row;
                        cell.dataset.col = col;
                        
                        // 添加棋盘线
                        const line = document.createElement('div');
                        line.classList.add('absolute', 'bg-gray-700');
                        
                        // 水平线
                        if (row === 0) {
                            line.style.width = '100%';
                            line.style.height = '1px';
                            line.style.top = '50%';
                        } else if (row === BOARD_SIZE - 1) {
                            line.style.width = '100%';
                            line.style.height = '1px';
                            line.style.bottom = '50%';
                        } else {
                            line.style.width = '100%';
                            line.style.height = '2px';
                            line.style.top = '50%';
                            line.style.transform = 'translateY(-50%)';
                        }
                        cell.appendChild(line.cloneNode(true));
                        
                        // 垂直线
                        if (col === 0) {
                            line.style.width = '1px';
                            line.style.height = '100%';
                            line.style.left = '50%';
                            line.style.top = '0';
                        } else if (col === BOARD_SIZE - 1) {
                            line.style.width = '1px';
                            line.style.height = '100%';
                            line.style.right = '50%';
                            line.style.top = '0';
                        } else {
                            line.style.width = '2px';
                            line.style.height = '100%';
                            line.style.left = '50%';
                            line.style.transform = 'translateX(-50%)';
                        }
                        cell.appendChild(line);
                        
                        // 添加天元和星位(仅15x15棋盘)
                        if (BOARD_SIZE === 15 && 
                            ((row === 3 || row === 7 || row === 11) && (col === 3 || col === 7 || col === 11))) {
                            const dot = document.createElement('div');
                            dot.classList.add('absolute', 'bg-gray-800', 'rounded-full');
                            dot.style.width = '6px';
                            dot.style.height = '6px';
                            dot.style.left = '50%';
                            dot.style.top = '50%';
                            dot.style.transform = 'translate(-50%, -50%)';
                            cell.appendChild(dot);
                        }
                        
                        // 点击落子
                        cell.addEventListener('click', () => {
                            if (!gameOver && !gameBoard[row][col]) {
                                placePiece(row, col);
                            }
                        });
                        
                        boardElement.appendChild(cell);
                    }
                }
                
                // 重置游戏状态
                gameBoard = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(null));
                currentPlayer = 'black';
                gameOver = false;
                moveHistory = [];
                updateStatus();
                clearHints();
            }
            
            // 放置棋子
            function placePiece(row, col) {
                // 记录历史
                moveHistory.push({row, col, player: currentPlayer});
                
                // 更新游戏板
                gameBoard[row][col] = currentPlayer;
                
                // 渲染棋子
                renderPiece(row, col, currentPlayer);
                
                // 检查胜利条件
                if (checkWin(row, col, currentPlayer)) {
                    gameOver = true;
                    const winner = currentPlayer === 'black' ? '黑方' : '白方';
                    winnerTextElement.textContent = `${winner}获胜!`;
                    winMessageElement.classList.remove('hidden');
                    return;
                }
                
                // 切换玩家
                currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
                updateStatus();
                
                // 简单AI自动落子(如果是电脑玩家)
                if (gameOver === false && currentPlayer === 'white') {
                    setTimeout(() => {
                        const aiMove = getAIMove();
                        placePiece(aiMove.row, aiMove.col);
                    }, 500);
                }
            }
            
            // 渲染棋子
            function renderPiece(row, col, player) {
                const piece = document.createElement('div');
                piece.classList.add('absolute', 'rounded-full', 'piece-transition');
                piece.style.width = `${PIECE_SIZE}px`;
                piece.style.height = `${PIECE_SIZE}px`;
                piece.style.left = `${col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2}px`;
                piece.style.top = `${row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2}px`;
                piece.style.zIndex = '10';
                
                if (player === 'black') {
                    piece.classList.add('bg-black');
                    piece.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1)';
                } else {
                    piece.classList.add('bg-white', 'border', 'border-gray-300');
                    piece.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1)';
                }
                
                // 添加动画效果
                piece.style.transform = 'scale(0)';
                piece.style.opacity = '0';
                
                boardElement.appendChild(piece);
                
                // 触发重排,然后应用动画
                setTimeout(() => {
                    piece.style.transform = 'scale(1)';
                    piece.style.opacity = '1';
                }, 10);
                
                // 如果是历史步骤的一部分,添加标记
                if (hintPosition && hintPosition.row === row && hintPosition.col === col) {
                    clearHints();
                }
            }
            
            // 清除提示标记
            function clearHints() {
                const hintElements = document.querySelectorAll('.hint-marker');
                hintElements.forEach(el => el.remove());
                hintPosition = null;
            }
            
            // 显示提示
            function showHint() {
                clearHints();
                
                // 简单AI计算最佳位置
                const hintMove = getAIMove();
                hintPosition = hintMove;
                
                // 创建提示标记
                const hintMarker = document.createElement('div');
                hintMarker.classList.add('absolute', 'hint-marker', 'rounded-full', 'bg-yellow-300', 'opacity-50');
                hintMarker.style.width = `${PIECE_SIZE * 1.2}px`;
                hintMarker.style.height = `${PIECE_SIZE * 1.2}px`;
                hintMarker.style.left = `${hintMove.col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE * 1.2) / 2}px`;
                hintMarker.style.top = `${hintMove.row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE * 1.2) / 2}px`;
                hintMarker.style.zIndex = '5';
                
                boardElement.appendChild(hintMarker);
            }
            
            // 简单AI计算最佳落子位置
            function getAIMove() {
                const difficulty = difficultySelect.value;
                let bestScore = -Infinity;
                let bestMove = {row: 0, col: 0};
                
                // 简单的评分系统:检查每个空位,找到能形成最长连续棋子的位置
                for (let row = 0; row < BOARD_SIZE; row++) {
                    for (let col = 0; col < BOARD_SIZE; col++) {
                        if (!gameBoard[row][col]) {
                            // 计算AI在此位置落子的分数
                            const aiScore = evaluateMove(row, col, 'white');
                            
                            // 计算玩家在此位置落子的分数(防守)
                            const playerScore = evaluateMove(row, col, 'black');
                            
                            // 综合得分 = 进攻得分 + 防守得分 * 权重
                            const score = aiScore + playerScore * 0.8;
                            
                            // 根据难度添加随机性
                            let randomFactor = 1;
                            if (difficulty === 'easy') {
                                randomFactor = 0.7 + Math.random() * 0.3; // 70%-100% 的准确度
                            } else if (difficulty === 'medium') {
                                randomFactor = 0.85 + Math.random() * 0.15; // 85%-100% 的准确度
                            } else {
                                randomFactor = 0.95 + Math.random() * 0.05; // 95%-100% 的准确度
                            }
                            
                            const weightedScore = score * randomFactor;
                            
                            if (weightedScore > bestScore) {
                                bestScore = weightedScore;
                                bestMove = {row, col};
                            }
                        }
                    }
                }
                
                return bestMove;
            }
            
            // 评估落子位置的分数
            function evaluateMove(row, col, player) {
                const directions = [
                    [0, 1],  // 水平
                    [1, 0],  // 垂直
                    [1, 1],  // 对角线
                    [1, -1]  // 反对角线
                ];
                
                let maxScore = 0;
                
                // 检查四个方向
                for (const [dx, dy] of directions) {
                    let score = 0;
                    let count = 1;  // 当前位置算一个
                    let blockedEnds = 0;
                    
                    // 正向检查
                    for (let i = 1; i < 5; i++) {
                        const r = row + i * dx;
                        const c = col + i * dy;
                        
                        if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
                            blockedEnds++;
                            break;
                        }
                        
                        if (gameBoard[r][c] === player) {
                            count++;
                        } else if (gameBoard[r][c] !== null) {
                            blockedEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 反向检查
                    for (let i = 1; i < 5; i++) {
                        const r = row - i * dx;
                        const c = col - i * dy;
                        
                        if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
                            blockedEnds++;
                            break;
                        }
                        
                        if (gameBoard[r][c] === player) {
                            count++;
                        } else if (gameBoard[r][c] !== null) {
                            blockedEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 评分规则
                    if (count >= 5) {
                        return 10000;  // 五连,必胜
                    } else if (count === 4 && blockedEnds === 0) {
                        score = 1000;  // 活四
                    } else if (count === 4 && blockedEnds === 1) {
                        score = 100;   // 冲四
                    } else if (count === 3 && blockedEnds === 0) {
                        score = 50;    // 活三
                    } else if (count === 3 && blockedEnds === 1) {
                        score = 10;    // 冲三
                    } else if (count === 2 && blockedEnds === 0) {
                        score = 5;     // 活二
                    }
                    
                    if (score > maxScore) {
                        maxScore = score;
                    }
                }
                
                return maxScore;
            }
            
            // 检查胜利条件
            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 < 5; i++) {
                        const r = row + i * dx;
                        const c = col + i * dy;
                        
                        if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
                            break;
                        }
                        
                        count++;
                    }
                    
                    // 反向检查
                    for (let i = 1; i < 5; i++) {
                        const r = row - i * dx;
                        const c = col - i * dy;
                        
                        if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
                            break;
                        }
                        
                        count++;
                    }
                    
                    // 五连子获胜
                    if (count >= 5) {
                        // 高亮显示获胜的棋子
                        highlightWinningPieces(row, col, dx, dy, player);
                        return true;
                    }
                }
                
                return false;
            }
            
            // 高亮显示获胜的棋子
            function highlightWinningPieces(row, col, dx, dy, player) {
                // 存储所有获胜的棋子位置
                let winningPositions = [{row, col}];
                
                // 正向检查
                for (let i = 1; i < 5; i++) {
                    const r = row + i * dx;
                    const c = col + i * dy;
                    
                    if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
                        break;
                    }
                    
                    winningPositions.push({row: r, col: c});
                }
                
                // 反向检查
                for (let i = 1; i < 5; i++) {
                    const r = row - i * dx;
                    const c = col - i * dy;
                    
                    if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE || gameBoard[r][c] !== player) {
                        break;
                    }
                    
                    winningPositions.push({row: r, col: c});
                }
                
                // 高亮显示
                setTimeout(() => {
                    for (const pos of winningPositions) {
                        const x = pos.col * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2;
                        const y = pos.row * CELL_SIZE + (CELL_SIZE - PIECE_SIZE) / 2;
                        
                        const highlight = document.createElement('div');
                        highlight.classList.add('absolute', 'rounded-full', 'z-20');
                        highlight.style.width = `${PIECE_SIZE * 1.1}px`;
                        highlight.style.height = `${PIECE_SIZE * 1.1}px`;
                        highlight.style.left = `${x - (PIECE_SIZE * 0.1) / 2}px`;
                        highlight.style.top = `${y - (PIECE_SIZE * 0.1) / 2}px`;
                        
                        if (player === 'black') {
                            highlight.classList.add('border-2', 'border-yellow-400');
                        } else {
                            highlight.classList.add('border-2', 'border-red-400');
                        }
                        
                        boardElement.appendChild(highlight);
                        
                        // 添加闪烁动画
                        highlight.animate([
                            { opacity: 0.7 },
                            { opacity: 1 },
                            { opacity: 0.7 }
                        ], {
                            duration: 1500,
                            iterations: Infinity
                        });
                    }
                }, 100);
            }
            
            // 更新游戏状态显示
            function updateStatus() {
                if (gameOver) {
                    statusElement.textContent = '游戏结束';
                } else {
                    const playerText = currentPlayer === 'black' ? '黑方' : '白方';
                    statusElement.textContent = `${playerText}回合`;
                    
                    // 更新状态背景色
                    if (currentPlayer === 'black') {
                        statusElement.classList.remove('bg-white', 'border-gray-300');
                        statusElement.classList.add('bg-black', 'text-white');
                    } else {
                        statusElement.classList.remove('bg-black', 'text-white');
                        statusElement.classList.add('bg-white', 'border', 'border-gray-300');
                    }
                }
            }
            
            // 悔棋
            function undoMove() {
                if (moveHistory.length > 0 && !gameOver) {
                    const lastMove = moveHistory.pop();
                    gameBoard[lastMove.row][lastMove.col] = null;
                    
                    // 移除最后一个棋子
                    const pieces = boardElement.querySelectorAll('.piece-transition');
                    if (pieces.length > 0) {
                        const lastPiece = pieces[pieces.length - 1];
                        lastPiece.style.transform = 'scale(0)';
                        lastPiece.style.opacity = '0';
                        
                        setTimeout(() => {
                            lastPiece.remove();
                        }, 200);
                    }
                    
                    // 切换回上一个玩家
                    currentPlayer = lastMove.player;
                    updateStatus();
                }
            }
            
            // 事件监听器
            restartBtn.addEventListener('click', initializeBoard);
            undoBtn.addEventListener('click', undoMove);
            hintBtn.addEventListener('click', showHint);
            
            // 设置相关
            settingsBtn.addEventListener('click', () => {
                settingsModal.classList.remove('hidden');
            });
            
            closeSettingsBtn.addEventListener('click', () => {
                settingsModal.classList.add('hidden');
            });
            
            saveSettingsBtn.addEventListener('click', () => {
                const newBoardSize = parseInt(boardSizeSelect.value);
                if (newBoardSize !== BOARD_SIZE) {
                    // 重新初始化棋盘
                    initializeBoard();
                }
                settingsModal.classList.add('hidden');
            });
            
            newGameBtn.addEventListener('click', () => {
                winMessageElement.classList.add('hidden');
                initializeBoard();
            });
            
            // 点击模态框外部关闭
            settingsModal.addEventListener('click', (e) => {
                if (e.target === settingsModal) {
                    settingsModal.classList.add('hidden');
                }
            });
            
            // 初始化棋盘
            initializeBoard();
        });
    </script>
</body>
</html>
    

 

五子棋

游戏信息

 
黑方先行
 
白方后行

游戏状态

黑方回合
posted @ 2025-06-16 11:50  aiplus  阅读(24)  评论(0)    收藏  举报
悬浮按钮示例