网页版五子棋

1、新建一个txt文件
2、打开后将代码复制进去保存

<!DOCTYPE html>
<html>
<head>
    <title>智能五子棋</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            background: #f0f0f0;
            font-family: Arial, sans-serif;
        }
        canvas {
            border: 2px solid #333;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0,0,0,0.3);
            background: #F0D9B5;
            margin: 20px;
        }
        .status {
            font-size: 24px;
            color: #333;
            margin: 10px;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.3s;
        }
        button:hover {
            background: #45a049;
        }
    </style>
</head>
<body>
    <div class="status" id="status">轮到玩家落子</div>
    <canvas id="board" width="600" height="600"></canvas>
    <button onclick="initGame()">重新开始</button>

<script>
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
const SIZE = 40;
const ROWS = 15;
const AI_DEPTH = 3; // 搜索深度

let board = [];
let gameOver = false;

// 初始化游戏
function initGame() {
    board = Array(ROWS).fill().map(() => Array(ROWS).fill(0));
    gameOver = false;
    document.getElementById('status').textContent = '轮到玩家落子';
    drawBoard();
}

// 绘制棋盘
function drawBoard() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 绘制网格
    ctx.strokeStyle = '#666';
    ctx.lineWidth = 1;
    for (let i = 0; i < ROWS; i++) {
        ctx.beginPath();
        ctx.moveTo(SIZE/2, SIZE/2 + i*SIZE);
        ctx.lineTo(canvas.width - SIZE/2, SIZE/2 + i*SIZE);
        ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(SIZE/2 + i*SIZE, SIZE/2);
        ctx.lineTo(SIZE/2 + i*SIZE, canvas.height - SIZE/2);
        ctx.stroke();
    }

    // 绘制星位
    const stars = [3, 7, 11];
    stars.forEach(x => stars.forEach(y => {
        ctx.beginPath();
        ctx.arc(SIZE/2 + x*SIZE, SIZE/2 + y*SIZE, 3, 0, Math.PI*2);
        ctx.fillStyle = '#666';
        ctx.fill();
    }));

    // 绘制棋子
    for (let i = 0; i < ROWS; i++) {
        for (let j = 0; j < ROWS; j++) {
            if (board[i][j] === 1) drawPiece(i, j, '#000');
            else if (board[i][j] === 2) drawPiece(i, j, '#FFF');
        }
    }
}

// 绘制棋子
function drawPiece(x, y, color) {
    ctx.beginPath();
    ctx.arc(SIZE/2 + x*SIZE, SIZE/2 + y*SIZE, SIZE*0.4, 0, Math.PI*2);
    ctx.fillStyle = color;
    ctx.fill();
    ctx.strokeStyle = color === '#000' ? '#fff' : '#000';
    ctx.lineWidth = 1;
    ctx.stroke();
}

// AI核心逻辑
const PATTERNS = {
    FIVE: 100000,
    LIVE_FOUR: 50000,
    DIE_FOUR: 400,
    LIVE_THREE: 400,
    DIE_THREE: 50,
    LIVE_TWO: 50,
    DIE_TWO: 5
};

function aiMove() {
    document.getElementById('status').textContent = 'AI思考中...';
    setTimeout(() => {
        const move = getBestMove();
        board[move.x][move.y] = 2;
        if (checkWin(move.x, move.y, 2)) {
            gameOver = true;
            document.getElementById('status').textContent = 'AI获胜!';
        } else {
            document.getElementById('status').textContent = '轮到玩家落子';
        }
        drawBoard();
    }, 100);
}

function getBestMove() {
    let bestScore = -Infinity;
    let bestMoves = [];
    const candidates = getCandidatePositions();

    candidates.forEach(({x, y}) => {
        board[x][y] = 2;
        let score = minimax(AI_DEPTH - 1, -Infinity, Infinity, false);
        board[x][y] = 0;
        
        if (score > bestScore) {
            bestScore = score;
            bestMoves = [{x, y}];
        } else if (score === bestScore) {
            bestMoves.push({x, y});
        }
    });

    return bestMoves[Math.floor(Math.random() * bestMoves.length)];
}

function minimax(depth, alpha, beta, isMaximizing) {
    if (depth === 0 || checkGameOver()) return evaluateBoard();
    
    if (isMaximizing) {
        let maxScore = -Infinity;
        for (let {x, y} of getCandidatePositions()) {
            board[x][y] = 2;
            let score = minimax(depth - 1, alpha, beta, false);
            board[x][y] = 0;
            maxScore = Math.max(maxScore, score);
            alpha = Math.max(alpha, score);
            if (beta <= alpha) break;
        }
        return maxScore;
    } else {
        let minScore = Infinity;
        for (let {x, y} of getCandidatePositions()) {
            board[x][y] = 1;
            let score = minimax(depth - 1, alpha, beta, true);
            board[x][y] = 0;
            minScore = Math.min(minScore, score);
            beta = Math.min(beta, score);
            if (beta <= alpha) break;
        }
        return minScore;
    }
}

// 辅助函数
function getCandidatePositions() {
    const candidates = [];
    for (let i = 0; i < ROWS; i++) {
        for (let j = 0; j < ROWS; j++) {
            if (board[i][j] === 0 && hasNeighbor(i, j, 2)) {
                candidates.push({x:i, y:j});
            }
        }
    }
    return candidates.length > 0 ? candidates : [{x:7, y:7}];
}

function hasNeighbor(x, y, range) {
    for (let i = -range; i <= range; i++) {
        for (let j = -range; j <= range; j++) {
            const nx = x + i, ny = y + j;
            if (nx >=0 && nx < ROWS && ny >=0 && ny < ROWS && board[nx][ny] !== 0) {
                return true;
            }
        }
    }
    return false;
}

function evaluateBoard() {
    let score = 0;
    [[1,0], [0,1], [1,1], [1,-1]].forEach(([dx, dy]) => {
        for (let i = 0; i < ROWS; i++) {
            for (let j = 0; j < ROWS; j++) {
                if (board[i][j] !== 0) {
                    const pattern = checkPattern(i, j, dx, dy, board[i][j]);
                    score += (board[i][j] === 2 ? pattern : -pattern);
                }
            }
        }
    });
    return score;
}

function checkPattern(x, y, dx, dy, player) {
    let count = 1, block = 0;
    
    // 正方向
    let i = 1;
    while (validPos(x + dx*i, y + dy*i) && board[x + dx*i][y + dy*i] === player) {
        count++;
        i++;
    }
    if (!validPos(x + dx*i, y + dy*i) || board[x + dx*i][y + dy*i] !== 0) block++;
    
    // 反方向
    i = 1;
    while (validPos(x - dx*i, y - dy*i) && board[x - dx*i][y - dy*i] === player) {
        count++;
        i++;
    }
    if (!validPos(x - dx*i, y - dy*i) || board[x - dx*i][y - dy*i] !== 0) block++;
    
    if (count >= 5) return PATTERNS.FIVE;
    if (count === 4) return block === 0 ? PATTERNS.LIVE_FOUR : PATTERNS.DIE_FOUR;
    if (count === 3) return block === 0 ? PATTERNS.LIVE_THREE : PATTERNS.DIE_THREE;
    if (count === 2) return block === 0 ? PATTERNS.LIVE_TWO : PATTERNS.DIE_TWO;
    return 0;
}

function validPos(x, y) {
    return x >=0 && x < ROWS && y >=0 && y < ROWS;
}

function checkGameOver() {
    for (let i = 0; i < ROWS; i++) {
        for (let j = 0; j < ROWS; j++) {
            if (board[i][j] !== 0 && checkWin(i, j, board[i][j])) return true;
        }
    }
    return false;
}

// 胜负判断
function checkWin(x, y, player) {
    const directions = [[1,0], [0,1], [1,1], [1,-1]];
    for (let [dx, dy] of directions) {
        let count = 1;
        for (let i = 1; validPos(x + dx*i, y + dy*i) && board[x + dx*i][y + dy*i] === player; i++) count++;
        for (let i = 1; validPos(x - dx*i, y - dy*i) && board[x - dx*i][y - dy*i] === player; i++) count++;
        if (count >= 5) return true;
    }
    return false;
}

// 玩家交互
canvas.addEventListener('click', (e) => {
    if (gameOver) return;
    
    const rect = canvas.getBoundingClientRect();
    const x = Math.floor((e.clientX - rect.left - SIZE/2) / SIZE);
    const y = Math.floor((e.clientY - rect.top - SIZE/2) / SIZE);
    
    if (validPos(x, y) && board[x][y] === 0) {
        board[x][y] = 1;
        if (checkWin(x, y, 1)) {
            gameOver = true;
            document.getElementById('status').textContent = '玩家获胜!';
        } else {
            aiMove();
        }
        drawBoard();
    }
});

// 启动游戏
initGame();
</script>
</body>
</html>

3、修改文件后缀名为,将txt修改为html
4、打开方式选择浏览器打开,或者打开浏览器直接拖动到里面即可。如果后缀名修改html后,图标显示的是浏览器的图标,直接双击打开即可。
5、效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白嫖不白嫖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值