PHP 怎么PHP下棋AI

wen PHP项目 2

本文目录导读:

PHP 怎么PHP下棋AI

  1. 基础实现(简单AI)
  2. 中级AI(评估函数法)
  3. 高级AI(Minimax + Alpha-Beta剪枝)
  4. 完整应用示例
  5. HTML前端示例
  6. 优化建议

我来为您介绍如何使用PHP实现一个下棋AI,这里以五子棋为例,提供几种不同难度的实现方案:

基础实现(简单AI)

<?php
class TicTacToeAI {
    private $board;
    private $player = 'X';
    private $ai = 'O';
    public function __construct($board) {
        $this->board = $board;
    }
    // 简单AI:随机下棋
    public function randomMove() {
        $emptyCells = [];
        foreach ($this->board as $row => $cols) {
            foreach ($cols as $col => $value) {
                if ($value === '') {
                    $emptyCells[] = [$row, $col];
                }
            }
        }
        if (empty($emptyCells)) {
            return null; // 棋盘已满
        }
        return $emptyCells[rand(0, count($emptyCells) - 1)];
    }
    // 中等AI:优先中心位置
    public function smartRandomMove() {
        // 优先中心
        if ($this->board[1][1] === '') {
            return [1, 1];
        }
        // 其次四角
        $corners = [[0,0], [0,2], [2,0], [2,2]];
        foreach ($corners as $corner) {
            if ($this->board[$corner[0]][$corner[1]] === '') {
                return $corner;
            }
        }
        return $this->randomMove();
    }
}
?>

中级AI(评估函数法)

<?php
class GomokuAI {
    private $board;
    private $size = 15;
    private $player = 1;  // 玩家棋子
    private $ai = 2;      // AI棋子
    public function __construct($size = 15) {
        $this->size = $size;
        $this->board = array_fill(0, $size, array_fill(0, $size, 0));
    }
    // 评估函数 - 计算某位置的得分
    private function evaluatePosition($row, $col, $player) {
        $score = 0;
        $directions = [[0,1], [1,0], [1,1], [1,-1]];
        foreach ($directions as $dir) {
            $score += $this->evaluateDirection($row, $col, $dir[0], $dir[1], $player);
        }
        return $score;
    }
    // 评估特定方向
    private function evaluateDirection($row, $col, $dr, $dc, $player) {
        $count = 1;
        $blocked = 0;
        $empty = 0;
        // 正向检查
        for ($i = 1; $i < 5; $i++) {
            $nr = $row + $dr * $i;
            $nc = $col + $dc * $i;
            if ($nr < 0 || $nr >= $this->size || $nc < 0 || $nc >= $this->size) {
                $blocked++;
                break;
            }
            if ($this->board[$nr][$nc] === $player) {
                $count++;
            } elseif ($this->board[$nr][$nc] === 0) {
                $empty++;
                break;
            } else {
                $blocked++;
                break;
            }
        }
        // 反向检查
        for ($i = 1; $i < 5; $i++) {
            $nr = $row - $dr * $i;
            $nc = $col - $dc * $i;
            if ($nr < 0 || $nr >= $this->size || $nc < 0 || $nc >= $this->size) {
                $blocked++;
                break;
            }
            if ($this->board[$nr][$nc] === $player) {
                $count++;
            } elseif ($this->board[$nr][$nc] === 0) {
                $empty++;
                break;
            } else {
                $blocked++;
                break;
            }
        }
        // 根据连子数和阻塞情况计算得分
        if ($count >= 5) return 100000;
        if ($count === 4) {
            return $empty > 0 ? ($blocked === 0 ? 10000 : 1000) : 0;
        }
        if ($count === 3) {
            return $empty > 0 ? ($blocked === 0 ? 1000 : 100) : 0;
        }
        if ($count === 2) {
            return $empty > 0 ? ($blocked === 0 ? 100 : 10) : 0;
        }
        return $count * 10;
    }
    // 找到最佳位置
    public function findBestMove() {
        $bestScore = -INF;
        $bestMove = null;
        for ($row = 0; $row < $this->size; $row++) {
            for ($col = 0; $col < $this->size; $col++) {
                if ($this->board[$row][$col] !== 0) continue;
                // 跳过太远的位置(优化性能)
                if (!$this->hasNeighbor($row, $col)) continue;
                // 计算进攻和防守得分
                $attackScore = $this->evaluatePosition($row, $col, $this->ai);
                $defenseScore = $this->evaluatePosition($row, $col, $this->player);
                // 综合得分(防守优先略低)
                $totalScore = $attackScore + $defenseScore * 0.8;
                if ($totalScore > $bestScore) {
                    $bestScore = $totalScore;
                    $bestMove = [$row, $col];
                }
            }
        }
        return $bestMove;
    }
    // 检查是否有相邻棋子(用于优化)
    private function hasNeighbor($row, $col) {
        for ($i = max(0, $row-2); $i <= min($this->size-1, $row+2); $i++) {
            for ($j = max(0, $col-2); $j <= min($this->size-1, $col+2); $j++) {
                if ($this->board[$i][$j] !== 0) {
                    return true;
                }
            }
        }
        return false;
    }
}
?>

高级AI(Minimax + Alpha-Beta剪枝)

<?php
class AdvancedChessAI {
    private $board;
    private $size = 15;
    // Minimax算法(简化版,适用于小棋盘)
    public function minimax($depth, $isMaximizing) {
        // 检查终端状态
        $winner = $this->checkWinner();
        if ($winner !== null) {
            return $winner === 1 ? -100000 + $depth : 100000 - $depth;
        }
        if ($depth === 0) {
            return $this->evaluateBoard();
        }
        if ($isMaximizing) {
            $maxEval = -INF;
            foreach ($this->getPossibleMoves() as $move) {
                $this->makeMove($move[0], $move[1], 2);
                $eval = $this->minimax($depth - 1, false);
                $this->undoMove($move[0], $move[1]);
                $maxEval = max($maxEval, $eval);
            }
            return $maxEval;
        } else {
            $minEval = INF;
            foreach ($this->getPossibleMoves() as $move) {
                $this->makeMove($move[0], $move[1], 1);
                $eval = $this->minimax($depth - 1, true);
                $this->undoMove($move[0], $move[1]);
                $minEval = min($minEval, $eval);
            }
            return $minEval;
        }
    }
    // Alpha-Beta剪枝优化
    public function alphaBeta($depth, $alpha, $beta, $isMaximizing) {
        $winner = $this->checkWinner();
        if ($winner !== null) {
            return $winner === 1 ? -100000 + $depth : 100000 - $depth;
        }
        if ($depth === 0) {
            return $this->evaluateBoard();
        }
        if ($isMaximizing) {
            $maxEval = -INF;
            foreach ($this->getPossibleMoves() as $move) {
                $this->makeMove($move[0], $move[1], 2);
                $eval = $this->alphaBeta($depth - 1, $alpha, $beta, false);
                $this->undoMove($move[0], $move[1]);
                $maxEval = max($maxEval, $eval);
                $alpha = max($alpha, $eval);
                if ($beta <= $alpha) break; // 剪枝
            }
            return $maxEval;
        } else {
            $minEval = INF;
            foreach ($this->getPossibleMoves() as $move) {
                $this->makeMove($move[0], $move[1], 1);
                $eval = $this->alphaBeta($depth - 1, $alpha, $beta, true);
                $this->undoMove($move[0], $move[1]);
                $minEval = min($minEval, $eval);
                $beta = min($beta, $eval);
                if ($beta <= $alpha) break; // 剪枝
            }
            return $minEval;
        }
    }
    // 棋盘评估(简化版)
    private function evaluateBoard() {
        $score = 0;
        // 统计棋子数量
        foreach ($this->board as $row) {
            foreach ($row as $cell) {
                if ($cell === 1) $score -= 10;
                if ($cell === 2) $score += 10;
            }
        }
        return $score;
    }
}
?>

完整应用示例

<?php
// 使用示例
session_start();
class GomokuGame {
    private $ai;
    private $gameId;
    public function __construct() {
        $this->gameId = $_SESSION['game_id'] ?? uniqid();
        $this->initGame();
    }
    private function initGame() {
        if (!isset($_SESSION['board'])) {
            $_SESSION['board'] = array_fill(0, 15, array_fill(0, 15, 0));
            $_SESSION['current_turn'] = 1; // 1=玩家, 2=AI
        }
    }
    public function playerMove($row, $col) {
        $board = $_SESSION['board'];
        // 检查位置是否有效
        if ($row < 0 || $row >= 15 || $col < 0 || $col >= 15) {
            return ['error' => '无效位置'];
        }
        if ($board[$row][$col] !== 0) {
            return ['error' => '该位置已有棋子'];
        }
        // 玩家下棋
        $board[$row][$col] = 1;
        $_SESSION['board'] = $board;
        // 检查玩家是否获胜
        if ($this->checkWin($board, $row, $col, 1)) {
            return ['status' => 'win', 'player' => 'human'];
        }
        // AI下棋
        $this->ai = new GomokuAI();
        $this->ai->board = $board;
        $aiMove = $this->ai->findBestMove();
        if ($aiMove) {
            $board[$aiMove[0]][$aiMove[1]] = 2;
            $_SESSION['board'] = $board;
            if ($this->checkWin($board, $aiMove[0], $aiMove[1], 2)) {
                return ['status' => 'win', 'player' => 'ai'];
            }
        }
        return ['status' => 'continue', 'board' => $board];
    }
    private function checkWin($board, $row, $col, $player) {
        $directions = [[0,1], [1,0], [1,1], [1,-1]];
        foreach ($directions as $dir) {
            $count = 1;
            // 正向
            for ($i = 1; $i < 5; $i++) {
                $nr = $row + $dir[0] * $i;
                $nc = $col + $dir[1] * $i;
                if ($nr < 0 || $nr >= 15 || $nc < 0 || $nc >= 15) break;
                if ($board[$nr][$nc] === $player) $count++;
                else break;
            }
            // 反向
            for ($i = 1; $i < 5; $i++) {
                $nr = $row - $dir[0] * $i;
                $nc = $col - $dir[1] * $i;
                if ($nr < 0 || $nr >= 15 || $nc < 0 || $nc >= 15) break;
                if ($board[$nr][$nc] === $player) $count++;
                else break;
            }
            if ($count >= 5) return true;
        }
        return false;
    }
}
// API端点
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $game = new GomokuGame();
    $data = json_decode(file_get_contents('php://input'), true);
    if (isset($data['row']) && isset($data['col'])) {
        $result = $game->playerMove($data['row'], $data['col']);
        echo json_encode($result);
    }
}
?>

HTML前端示例

<!DOCTYPE html>
<html>
<head>PHP 五子棋AI</title>
    <style>
        .board {
            display: grid;
            grid-template-columns: repeat(15, 30px);
            gap: 1px;
            background: #d4a574;
            padding: 10px;
        }
        .cell {
            width: 30px;
            height: 30px;
            background: #f0d9b5;
            border: 1px solid #999;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .cell.black::after {
            content: '';
            width: 20px;
            height: 20px;
            background: black;
            border-radius: 50%;
        }
        .cell.white::after {
            content: '';
            width: 20px;
            height: 20px;
            background: white;
            border-radius: 50%;
            border: 1px solid #999;
        }
    </style>
</head>
<body>
    <div id="gameBoard" class="board"></div>
    <div id="status"></div>
    <script>
        let board = [];
        function initBoard() {
            const gameBoard = document.getElementById('gameBoard');
            gameBoard.innerHTML = '';
            for (let row = 0; row < 15; row++) {
                for (let col = 0; col < 15; col++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.row = row;
                    cell.dataset.col = col;
                    cell.addEventListener('click', () => makeMove(row, col));
                    gameBoard.appendChild(cell);
                }
            }
        }
        async function makeMove(row, col) {
            const response = await fetch('api.php', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({row, col})
            });
            const result = await response.json();
            updateBoard(result.board || board);
            if (result.status === 'win') {
                document.getElementById('status').textContent = 
                    result.player === 'human' ? '你赢了!' : 'AI赢了!';
            }
        }
        function updateBoard(newBoard) {
            board = newBoard;
            const cells = document.querySelectorAll('.cell');
            cells.forEach((cell, index) => {
                const row = Math.floor(index / 15);
                const col = index % 15;
                cell.className = 'cell';
                if (newBoard[row][col] === 1) cell.classList.add('black');
                if (newBoard[row][col] === 2) cell.classList.add('white');
            });
        }
        initBoard();
    </script>
</body>
</html>

优化建议

  1. 性能优化

    • 使用缓存的评估结果
    • 限制搜索深度(通常3-5层)
    • 只搜索有棋子的周边区域
  2. AI难度调整

    • 随机错误率
    • 不同的搜索深度
    • 评估函数的权重调整
  3. 其他功能

    • 悔棋功能
    • 保存/加载游戏
    • 多种AI难度选择
  4. 技术改进

    • 使用MCTS(蒙特卡洛树搜索)
    • 机器学习评估
    • 神经网络(需要PHP-ML等库)

这个实现适合教学和中小型游戏项目,对于大型项目,可以考虑使用更多高级算法,或者将AI逻辑放在后端服务中以提高性能。

抱歉,评论功能暂时关闭!