本文目录导读:

我来为您介绍如何使用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>
优化建议
-
性能优化:
- 使用缓存的评估结果
- 限制搜索深度(通常3-5层)
- 只搜索有棋子的周边区域
-
AI难度调整:
- 随机错误率
- 不同的搜索深度
- 评估函数的权重调整
-
其他功能:
- 悔棋功能
- 保存/加载游戏
- 多种AI难度选择
-
技术改进:
- 使用MCTS(蒙特卡洛树搜索)
- 机器学习评估
- 神经网络(需要PHP-ML等库)
这个实现适合教学和中小型游戏项目,对于大型项目,可以考虑使用更多高级算法,或者将AI逻辑放在后端服务中以提高性能。