实时php项目显示场上谁更占优势?

wen PHP项目 2

PHP 实时项目:显示场上谁更占优势

这是一个很常见的需求,比如体育比赛、电竞对战、辩论赛等场景,下面给你一套完整的实现思路和代码。

实时php项目显示场上谁更占优势?

整体架构

前端(JS定时轮询/WebSocket) ←→ PHP后端(API) ←→ 数据库(比分/状态)
                                      ↓
                                 优势算法

数据表设计

CREATE TABLE matches (
    id INT PRIMARY KEY AUTO_INCREMENT,
    team_a VARCHAR(50),
    team_b VARCHAR(50),
    score_a INT DEFAULT 0,
    score_b INT DEFAULT 0,
    -- 进阶统计
    possession_a DECIMAL(5,2) DEFAULT 50,  -- 控球率
    shots_a INT DEFAULT 0,
    shots_b INT DEFAULT 0,
    status TINYINT DEFAULT 0,  -- 0未开始 1进行中 2结束
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

优势算法(核心)

不要只看比分,要综合多维度加权计算:

<?php
/**
 * 计算双方优势指数
 * 返回 -100 ~ +100,正数A占优,负数B占优
 */
function calcAdvantage(array $m): float
{
    // 1. 比分差(权重最高,且随时间放大)
    $scoreDiff = $m['score_a'] - $m['score_b'];
    $scoreScore = $scoreDiff * 25;
    // 2. 控球率差
    $possDiff = ($m['possession_a'] - 50) * 0.4;
    // 3. 射门差
    $shotDiff = ($m['shots_a'] - $m['shots_b']) * 1.5;
    // 4. 时间因子:比分领先在后期更"稳"
    $timeWeight = 1.0;
    if (isset($m['elapsed_min'])) {
        $timeWeight = 1 + ($m['elapsed_min'] / 90) * 0.5;
    }
    $advantage = $scoreScore * $timeWeight + $possDiff + $shotDiff;
    // 归一化到 -100 ~ 100
    return max(-100, min(100, round($advantage, 1)));
}
/**
 * 转换为文字描述
 */
function advantageText(float $adv, string $a, string $b): string
{
    $abs = abs($adv);
    if ($abs < 10)  return "势均力敌";
    if ($abs < 30)  return $adv > 0 ? "{$a}略占上风" : "{$b}略占上风";
    if ($abs < 60)  return $adv > 0 ? "{$a}明显占优" : "{$b}明显占优";
    return $adv > 0 ? "{$a}全面压制" : "{$b}全面压制";
}

API 接口

<?php
// api/advantage.php
header('Content-Type: application/json; charset=utf-8');
$pdo = new PDO('mysql:host=localhost;dbname=game;charset=utf8mb4', 'user', 'pass');
$id = (int)($_GET['id'] ?? 0);
$stmt = $pdo->prepare("SELECT * FROM matches WHERE id = ?");
$stmt->execute([$id]);
$m = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$m) {
    echo json_encode(['error' => 'not found']);
    exit;
}
$adv = calcAdvantage($m);
echo json_encode([
    'team_a'   => $m['team_a'],
    'team_b'   => $m['team_b'],
    'score'    => "{$m['score_a']} : {$m['score_b']}",
    'advantage'=> $adv,                     // -100~100
    'percent_a'=> round((100 + $adv) / 2),  // 0~100,方便画进度条
    'text'     => advantageText($adv, $m['team_a'], $m['team_b']),
    'updated'  => $m['updated_at'],
], JSON_UNESCAPED_UNICODE);

前端实时展示

方案 A:轮询(简单)

<div id="box">
    <span id="a">A</span>
    <div class="bar">
        <div id="barA" style="width:50%"></div>
        <div id="barB" style="width:50%"></div>
    </div>
    <span id="b">B</span>
    <p id="text"></p>
</div>
<style>
.bar{display:flex;height:20px;background:#eee;border-radius:10px;overflow:hidden}
#barA{background:#2196f3;transition:width .6s}
#barB{background:#f44336;transition:width .6s}
</style>
<script>
async function refresh() {
    const r = await fetch('api/advantage.php?id=1');
    const d = await r.json();
    document.getElementById('a').textContent = d.team_a;
    document.getElementById('b').textContent = d.team_b;
    document.getElementById('barA').style.width = d.percent_a + '%';
    document.getElementById('barB').style.width = (100 - d.percent_a) + '%';
    document.getElementById('text').textContent =
        `${d.score} — ${d.text}`;
}
refresh();
setInterval(refresh, 3000);  // 每3秒刷新
</script>

方案 B:WebSocket(更高实时性)

推荐用 Workerman 或 Swoole,比分一有变动就 push 给所有客户端,无需轮询。

// Workerman 示例
use Workerman\Worker;
require 'vendor/autoload.php';
$ws = new Worker('websocket://0.0.0.0:2346');
$ws->onConnect = function($conn) {
    $conn->send(json_encode(['msg' => 'connected']));
};
$ws->onMessage = function($conn, $data) use ($ws) {
    // 收到比分更新,广播给所有人
    foreach ($ws->connections as $c) $c->send($data);
};
Worker::runAll();

进阶提升建议

提升点 做法
算法更准 引入 Elo / 泊松模型 / 历史胜率
性能 优势结果缓存到 Redis,30秒过期
实时性 WebSocket 或 SSE 替代轮询
可视化 ECharts 半圆仪表盘展示优势值
多场次 前端用 setInterval 只拉当前页可见的比赛

告诉我你的具体场景(体育?电竞?辩论?),我可以帮你把算法权重和字段调整得更贴合,另外你想用轮询还是 WebSocket?我可以给完整可运行的代码。

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