五子棋游戏 body { font-family: Arial, sans-serif; background-color: #f0f0f0; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; }
    #game-container {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    
    #game-board {
        background-color: #f3d2b5;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        cursor: pointer;
    }
    
    #info {
        font-size: 20px;
        margin-top: 20px;
        text-align: center;
        height: 30px;
    }
    
    #restart-btn {
        margin-top: 20px;
        padding: 8px 16px;
        font-size: 16px;
        background-color: #4CAF50;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    }
    
    #restart-btn:hover {
        background-color: #45a049;
    }
</style>
重新开始
<script>
    document.addEventListener('DOMContentLoaded', () => {
        const canvas = document.getElementById('game-board');
        const ctx = canvas.getContext('2d');
        const infoDiv = document.getElementById('info');
        const restartBtn = document.getElementById('restart-btn');
        
        const BOARD_SIZE = 15;
        const CELL_SIZE = canvas.width / BOARD_SIZE;
        const PIECE_RADIUS = CELL_SIZE * 0.4;
        
        let board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(0));
        let currentPlayer = 1; // 1: 黑棋(先手), 2: 白棋
        let gameOver = false;
        let playerColor = Math.random() < 0.5 ? 1 : 2;
        let aiColor = playerColor === 1 ? 2 : 1;
        
        // 棋型评分常量
        const SCORE = {
            FIVE: 100000,
            LIVE_FOUR: 10000,
            DIE_FOUR: 1000,
            LIVE_THREE: 1000,
            DIE_THREE: 100,
            LIVE_TWO: 100,
            DIE_TWO: 10,
            SINGLE: 1
        };
        
        function initGame() {
            board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(0));
            currentPlayer = 1;
            playerColor = Math.random() < 0.5 ? 1 : 2;
            aiColor = playerColor === 1 ? 2 : 1;
            gameOver = false;
            drawBoard();
            updateInfo();
            
            if (currentPlayer === 1 && aiColor === 1) {
                setTimeout(aiMove, 500);
            }
        }
        
        function drawBoard() {
            ctx.fillStyle = '#f3d2b5';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            ctx.strokeStyle = '#000';
            ctx.lineWidth = 1;
            
            for (let i = 0; i < BOARD_SIZE; i++) {
                ctx.beginPath();
                ctx.moveTo(CELL_SIZE / 2, i * CELL_SIZE + CELL_SIZE / 2);
                ctx.lineTo(canvas.width - CELL_SIZE / 2, i * CELL_SIZE + CELL_SIZE / 2);
                ctx.stroke();
                
                ctx.beginPath();
                ctx.moveTo(i * CELL_SIZE + CELL_SIZE / 2, CELL_SIZE / 2);
                ctx.lineTo(i * CELL_SIZE + CELL_SIZE / 2, canvas.height - CELL_SIZE / 2);
                ctx.stroke();
            }
            
            for (let i = 0; i < BOARD_SIZE; i++) {
                for (let j = 0; j < BOARD_SIZE; j++) {
                    if (board[i][j] === 1) {
                        drawPiece(j, i, 'black');
                    } else if (board[i][j] === 2) {
                        drawPiece(j, i, 'white');
                    }
                }
            }
        }
        
        function drawPiece(x, y, color) {
            const centerX = x * CELL_SIZE + CELL_SIZE / 2;
            const centerY = y * CELL_SIZE + CELL_SIZE / 2;
            
            ctx.beginPath();
            ctx.arc(centerX, centerY, PIECE_RADIUS, 0, Math.PI * 2);
            ctx.fillStyle = color;
            ctx.fill();
            
            if (color === 'white') {
                ctx.strokeStyle = '#000';
                ctx.lineWidth = 1;
                ctx.stroke();
            }
        }
        
        function updateInfo() {
            if (gameOver) return;
            
            if (currentPlayer === playerColor) {
                infoDiv.textContent = `你的回合 (${playerColor === 1 ? '黑棋' : '白棋'})`;
            } else {
                infoDiv.textContent = `AI思考中 (${aiColor === 1 ? '黑棋' : '白棋'})...`;
            }
        }
        
        function placePiece(x, y) {
            if (gameOver || currentPlayer !== playerColor) return;
            
            const gridX = Math.round((x - CELL_SIZE / 2) / CELL_SIZE);
            const gridY = Math.round((y - CELL_SIZE / 2) / CELL_SIZE);
            
            if (gridX >= 0 && gridX < BOARD_SIZE && gridY >= 0 && gridY < BOARD_SIZE && board[gridY][gridX] === 0) {
                board[gridY][gridX] = currentPlayer;
                drawBoard();
                
                if (checkWin(gridX, gridY, currentPlayer)) {
                    gameOver = true;
                    infoDiv.textContent = `恭喜你赢了! (${playerColor === 1 ? '黑棋' : '白棋'})`;
                    return;
                }
                
                currentPlayer = currentPlayer === 1 ? 2 : 1;
                updateInfo();
                
                setTimeout(aiMove, 500);
            }
        }
        
        function aiMove() {
            if (gameOver || currentPlayer !== aiColor) return;
            
            // 1. 检查AI是否能直接获胜
            const winMove = findWinningMove(aiColor);
            if (winMove) {
                makeAIMove(winMove.x, winMove.y);
                return;
            }
            
            // 2. 检查是否需要防守玩家即将获胜
            const blockWinMove = findWinningMove(playerColor);
            if (blockWinMove) {
                makeAIMove(blockWinMove.x, blockWinMove.y);
                return;
            }
            
            // 3. 增强的活三检测和防守
            const blockThreeMove = findBlockThreeMove();
            if (blockThreeMove) {
                makeAIMove(blockThreeMove.x, blockThreeMove.y);
                return;
            }
            
            // 4. 尝试创建活四或冲四
            const createFourMove = findBestScoreMove(aiColor, ['LIVE_FOUR', 'DIE_FOUR']);
            if (createFourMove) {
                makeAIMove(createFourMove.x, createFourMove.y);
                return;
            }
            
            // 5. 阻止玩家形成活二
            const blockTwoMove = findBestScoreMove(playerColor, ['LIVE_TWO']);
            if (blockTwoMove) {
                makeAIMove(blockTwoMove.x, blockTwoMove.y);
                return;
            }
            
            // 6. 尝试创建活三
            const createThreeMove = findBestScoreMove(aiColor, ['LIVE_THREE']);
            if (createThreeMove) {
                makeAIMove(createThreeMove.x, createThreeMove.y);
                return;
            }
            
            // 7. 最佳落子点
            const bestMove = findBestPosition();
            if (bestMove) {
                makeAIMove(bestMove.x, bestMove.y);
                return;
            }
        }
        
        // 增强的活三检测函数
        function findBlockThreeMove() {
            const directions = [
                [1, 0], [0, 1], [1, 1], [1, -1]
            ];
            
            let bestDefense = null;
            let maxThreat = 0;
            
            for (let y = 0; y < BOARD_SIZE; y++) {
                for (let x = 0; x < BOARD_SIZE; x++) {
                    if (board[y][x] === 0) {
                        let threatLevel = 0;
                        let defensePoints = [];
                        
                        for (const [dx, dy] of directions) {
                            // 检查正方向
                            let count = 0;
                            let emptyCount = 0;
                            let blockCount = 0;
                            
                            // 正方向
                            let i = 1;
                            while (true) {
                                const nx = x + i * dx;
                                const ny = y + i * dy;
                                
                                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                                    blockCount++;
                                    break;
                                }
                                
                                if (board[ny][nx] === playerColor) {
                                    count++;
                                    i++;
                                } else if (board[ny][nx] === 0) {
                                    emptyCount++;
                                    break;
                                } else {
                                    blockCount++;
                                    break;
                                }
                            }
                            
                            // 负方向
                            i = 1;
                            while (true) {
                                const nx = x - i * dx;
                                const ny = y - i * dy;
                                
                                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                                    blockCount++;
                                    break;
                                }
                                
                                if (board[ny][nx] === playerColor) {
                                    count++;
                                    i++;
                                } else if (board[ny][nx] === 0) {
                                    emptyCount++;
                                    break;
                                } else {
                                    blockCount++;
                                    break;
                                }
                            }
                            
                            // 判断是否是活三威胁
                            if (count === 3 && emptyCount >= 1) {
                                // 连活三
                                if (emptyCount === 2) {
                                    threatLevel += SCORE.LIVE_THREE * 2;
                                    defensePoints.push({x, y, direction: [dx, dy]});
                                } 
                                // 跳活三
                                else {
                                    // 检查是否是跳活三
                                    const jumpThree = checkJumpThree(x, y, dx, dy, playerColor);
                                    if (jumpThree) {
                                        threatLevel += SCORE.LIVE_THREE;
                                        defensePoints.push(jumpThree);
                                    }
                                }
                            }
                        }
                        
                        // 选择威胁最大的防守点
                        if (threatLevel > maxThreat) {
                            maxThreat = threatLevel;
                            if (defensePoints.length > 0) {
                                // 优先选择能同时防守多个方向的点
                                bestDefense = defensePoints[0];
                            }
                        }
                    }
                }
            }
            
            return bestDefense;
        }
        
        // 检查跳活三
        function checkJumpThree(x, y, dx, dy, color) {
            // 检查正方向跳活三
            let pattern1 = [
                [0, 0],
                [dx, dy],
                [2*dx, 2*dy],
                [3*dx, 3*dy]
            ];
            
            let pattern2 = [
                [0, 0],
                [dx, dy],
                [3*dx, 3*dy],
                [4*dx, 4*dy]
            ];
            
            // 检查第一种跳活三模式:_OO_O
            let match1 = true;
            for (const [px, py] of pattern1) {
                const nx = x + px;
                const ny = y + py;
                
                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                    match1 = false;
                    break;
                }
                
                if ((px === 0 && py === 0) || (px === 3*dx && py === 3*dy)) {
                    if (board[ny][nx] !== 0) {
                        match1 = false;
                        break;
                    }
                } else {
                    if (board[ny][nx] !== color) {
                        match1 = false;
                        break;
                    }
                }
            }
            
            if (match1) {
                return {x: x + 3*dx, y: y + 3*dy};
            }
            
            // 检查第二种跳活三模式:_O_OO
            let match2 = true;
            for (const [px, py] of pattern2) {
                const nx = x + px;
                const ny = y + py;
                
                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                    match2 = false;
                    break;
                }
                
                if ((px === 0 && py === 0) || (px === dx && py === dy)) {
                    if (board[ny][nx] !== 0) {
                        match2 = false;
                        break;
                    }
                } else {
                    if (board[ny][nx] !== color) {
                        match2 = false;
                        break;
                    }
                }
            }
            
            if (match2) {
                return {x: x + dx, y: y + dy};
            }
            
            return null;
        }
        
        function makeAIMove(x, y) {
            board[y][x] = aiColor;
            drawBoard();
            
            if (checkWin(x, y, aiColor)) {
                gameOver = true;
                infoDiv.textContent = `AI赢了! (${aiColor === 1 ? '黑棋' : '白棋'})`;
                return;
            }
            
            if (isDraw()) {
                gameOver = true;
                infoDiv.textContent = "平局!";
                return;
            }
            
            currentPlayer = playerColor;
            updateInfo();
        }
        
        function isDraw() {
            for (let y = 0; y < BOARD_SIZE; y++) {
                for (let x = 0; x < BOARD_SIZE; x++) {
                    if (board[y][x] === 0) return false;
                }
            }
            return true;
        }
        
        function findWinningMove(color) {
            for (let y = 0; y < BOARD_SIZE; y++) {
                for (let x = 0; x < BOARD_SIZE; x++) {
                    if (board[y][x] === 0) {
                        board[y][x] = color;
                        if (checkWin(x, y, color)) {
                            board[y][x] = 0;
                            return {x, y};
                        }
                        board[y][x] = 0;
                    }
                }
            }
            return null;
        }
        
        function findBestScoreMove(color, patterns) {
            let bestScore = -1;
            let bestMove = null;
            
            for (let y = 0; y < BOARD_SIZE; y++) {
                for (let x = 0; x < BOARD_SIZE; x++) {
                    if (board[y][x] === 0) {
                        const score = evaluatePosition(x, y, color, patterns);
                        if (score > bestScore) {
                            bestScore = score;
                            bestMove = {x, y};
                        }
                    }
                }
            }
            
            return bestMove;
        }
        
        function evaluatePosition(x, y, color, patterns) {
            const directions = [
                [1, 0], [0, 1], [1, 1], [1, -1]
            ];
            
            let totalScore = 0;
            
            for (const [dx, dy] of directions) {
                const pattern = evaluateDirection(x, y, dx, dy, color);
                if (patterns.includes(pattern.type)) {
                    totalScore += SCORE[pattern.type];
                }
            }
            
            // 增加位置分(中心区域更高)
            const centerX = BOARD_SIZE / 2;
            const centerY = BOARD_SIZE / 2;
            const distanceToCenter = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
            totalScore += (BOARD_SIZE - distanceToCenter) * 2;
            
            // 增加邻近棋子分
            totalScore += getNearbyScore(x, y, color);
            
            return totalScore;
        }
        
        function evaluateDirection(x, y, dx, dy, color) {
            let count = 1;
            let emptyEnds = 0;
            let blockEnds = 0;
            
            // 正方向
            let i = 1;
            while (true) {
                const nx = x + i * dx;
                const ny = y + i * dy;
                
                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                    blockEnds++;
                    break;
                }
                
                if (board[ny][nx] === color) {
                    count++;
                    i++;
                } else if (board[ny][nx] === 0) {
                    emptyEnds++;
                    break;
                } else {
                    blockEnds++;
                    break;
                }
            }
            
            // 负方向
            i = 1;
            while (true) {
                const nx = x - i * dx;
                const ny = y - i * dy;
                
                if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
                    blockEnds++;
                    break;
                }
                
                if (board[ny][nx] === color) {
                    count++;
                    i++;
                } else if (board[ny][nx] === 0) {
                    emptyEnds++;
                    break;
                } else {
                    blockEnds++;
                    break;
                }
            }
            
            // 判断棋型
            if (count >= 5) return {type: 'FIVE'};
            if (count === 4) {
                if (emptyEnds === 2) return {type: 'LIVE_FOUR'};
                if (emptyEnds === 1) return {type: 'DIE_FOUR'};
            }
            if (count === 3) {
                if (emptyEnds === 2) return {type: 'LIVE_THREE'};
                if (emptyEnds === 1) return {type: 'DIE_THREE'};
            }
            if (count === 2) {
                if (emptyEnds === 2) return {type: 'LIVE_TWO'};
                if (emptyEnds === 1) return {type: 'DIE_TWO'};
            }
            
            return {type: 'SINGLE'};
        }
        
        function getNearbyScore(x, y, color) {
            let score = 0;
            const directions = [
                [-1, -1], [-1, 0], [-1, 1],
                [0, -1],           [0, 1],
                [1, -1],  [1, 0],  [1, 1]
            ];
            
            for (const [dx, dy] of directions) {
                const nx = x + dx;
                const ny = y + dy;
                
                if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) {
                    if (board[ny][nx] === color) {
                        score += 5;
                    } else if (board[ny][nx] !== 0) {
                        score += 3;
                    }
                }
            }
            
            return score;
        }
        
        function findBestPosition() {
            let bestScore = -1;
            let bestMove = null;
            
            // 优先寻找靠近已有棋子的位置
            for (let y = 0; y < BOARD_SIZE; y++) {
                for (let x = 0; x < BOARD_SIZE; x++) {
                    if (board[y][x] === 0) {
                        // 评估位置价值
                        let score = 0;
                        
                        // 1. 中心区域价值更高
                        const centerX = BOARD_SIZE / 2;
                        const centerY = BOARD_SIZE / 2;
                        const distanceToCenter = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
                        score += (BOARD_SIZE - distanceToCenter) * 2;
                        
                        // 2. 靠近AI棋子的位置价值更高
                        score += getNearbyScore(x, y, aiColor) * 2;
                        
                        // 3. 靠近玩家棋子的位置也有一定价值(防守)
                        score += getNearbyScore(x, y, playerColor);
                        
                        if (score > bestScore) {
                            bestScore = score;
                            bestMove = {x, y};
                        }
                    }
                }
            }
            
            return bestMove;
        }
        
        function checkWin(x, y, color) {
            const directions = [
                [1, 0], [0, 1], [1, 1], [1, -1]
            ];
            
            for (const [dx, dy] of directions) {
                let count = 1;
                
                // 正方向
                let i = 1;
                while (x + i * dx >= 0 && x + i * dx < BOARD_SIZE && 
                       y + i * dy >= 0 && y + i * dy < BOARD_SIZE && 
                       board[y + i * dy][x + i * dx] === color) {
                    count++;
                    i++;
                }
                
                // 负方向
                i = 1;
                while (x - i * dx >= 0 && x - i * dx < BOARD_SIZE && 
                       y - i * dy >= 0 && y - i * dy < BOARD_SIZE && 
                       board[y - i * dy][x - i * dx] === color) {
                    count++;
                    i++;
                }
                
                if (count >= 5) {
                    return true;
                }
            }
            
            return false;
        }
        
        canvas.addEventListener('click', (e) => {
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            placePiece(x, y);
        });
        
        restartBtn.addEventListener('click', initGame);
        
        initGame();
    });
</script>