php项目统计犯规战术阻止反击几次?

wen PHP项目 1

本文目录导读:

php项目统计犯规战术阻止反击几次?

  1. 核心判断逻辑(关键)
  2. 数据库设计示例(MySQL)
  3. PHP 代码实现(核心统计函数)
  4. 如何使用
  5. 如果要查询历史所有比赛的总次数
  6. 优化与实际建议

在PHP项目中,统计“犯规战术阻止反击”的次数通常需要结合业务逻辑数据模型来设计,由于“犯规战术”和“反击”在代码中通常是两个事件,我们需要定义如何判断一次犯规是一次“战术犯规”

以下是一个通用的、可落地的实现思路,包含数据库设计、核心判断逻辑和统计示例:

核心判断逻辑(关键)

“战术犯规阻止反击”需要满足以下条件:

  1. 犯规行为:比赛事件表中存在 foul 类型的事件。
  2. 反击状态:在犯规发生的前几秒(例如前5秒),该队的控球权是从防守成功(抢断、拦截、门将扑救)开始的,且没有丢球。
  3. 位置:犯规通常发生在中前场(为了阻止快攻,往往在中场),且需要满足“非最后一名防守球员的战术性拉拽”(这在数据中较难自动判断,通常需要人工标记或使用高级数据分析)。

数据库设计示例(MySQL)

假设我们有基础事件表 match_events

CREATE TABLE match_events (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    match_id BIGINT NOT NULL,
    team_id BIGINT NOT NULL,          -- 犯规队伍
    player_id BIGINT,
    event_type ENUM('foul', 'turnover', 'interception', 'clearance', 'goal_attempt', 'save') NOT NULL,
    action_subtype VARCHAR(50),       -- 'tactical', 'normal' (人工标记)
    tick_time INT NOT NULL,           -- 比赛时间(秒),用于判断“前后关系”
    x_coord DECIMAL(5,2),             -- 可能存在的坐标
    created_at TIMESTAMP
);
-- 索引优化查询
CREATE INDEX idx_match_time ON match_events(match_id, tick_time);
CREATE INDEX idx_team ON match_events(match_id, team_id);

PHP 代码实现(核心统计函数)

以下代码用于自动识别满足条件的犯规,并统计次数。

<?php
class TacticalFoulCounter
{
    private PDO $pdo;
    private int $timeWindowSeconds = 5; // 反击窗口:丢失球权后5秒内犯规
    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }
    /**
     * 统计某场比赛中,某球队的“战术犯规阻止反击”次数
     */
    public function countTacticalFouls(int $matchId, int $teamId): int
    {
        $count = 0;
        // 1. 获取该队的犯规事件
        $foulEvents = $this->getFouls($matchId, $teamId);
        foreach ($foulEvents as $foul) {
            // 2. 判断是否为人工标记的战术犯规(如果有)
            if (isset($foul['action_subtype']) && $foul['action_subtype'] === 'tactical') {
                $count++;
                continue;
            }
            // 3. 自动判断:是否在犯规前发生了“对方球队”的控球权转换(即反击开始)
            if ($this->wasOpponentCounterAttacking($foul)) {
                $count++;
            }
        }
        return $count;
    }
    /**
     * 获取球队的所有犯规事件
     */
    private function getFouls(int $matchId, int $teamId): array
    {
        $stmt = $this->pdo->prepare(
            "SELECT * FROM match_events 
             WHERE match_id = ? AND team_id = ? AND event_type = 'foul'
             ORDER BY tick_time ASC"
        );
        $stmt->execute([$matchId, $teamId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    /**
     * 判断这次犯规是否阻止了反击
     * 逻辑:在犯规时间点之前的 $timeWindowSeconds 秒内,
     * 对方(对手)是否获得了控球权(如拦截、抢断、对方传球失误等)
     */
    private function wasOpponentCounterAttacking(array $foul): bool
    {
        $foulTime = $foul['tick_time'];
        $opponentTeamId = $this->getOpponentTeamId($foul['match_id'], $foul['team_id']);
        // 时间范围:犯规前几秒到犯规时刻
        $startTime = max(0, $foulTime - $this->timeWindowSeconds);
        // 查找在这段时间内,对方队伍发生的“获得球权”事件
        $stmt = $this->pdo->prepare(
            "SELECT id FROM match_events 
             WHERE match_id = ? 
               AND team_id = ? 
               AND event_type IN ('interception', 'turnover', 'save', 'clearance') 
               AND tick_time BETWEEN ? AND ?
             LIMIT 1"
        );
        $stmt->execute([$foul['match_id'], $opponentTeamId, $startTime, $foulTime]);
        // 如果找到了“对方获得球权”的事件,说明对方正在反击,这次犯规就是战术犯规
        return $stmt->fetch() !== false;
    }
    /**
     * 获取比赛中的对手ID(假设只有两个队)
     */
    private function getOpponentTeamId(int $matchId, int $teamId): int
    {
        $stmt = $this->pdo->prepare(
            "SELECT DISTINCT team_id FROM match_events WHERE match_id = ? AND team_id != ?"
        );
        $stmt->execute([$matchId, $teamId]);
        return (int) $stmt->fetchColumn();
    }
}

如何使用

$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$counter = new TacticalFoulCounter($pdo);
// 统计某球队在某场比赛中的战术犯规次数
$matchId = 101;
$teamId = 2;
$foulCount = $counter->countTacticalFouls($matchId, $teamId);
echo "球队 {$teamId} 在比赛 {$matchId} 中通过犯规阻止反击的次数为:{$foulCount} 次";

如果要查询历史所有比赛的总次数

如果你想统计“整个赛季/所有比赛”的次数,并对球员或球队进行排名,可以写一个聚合SQL

SELECT 
    e.team_id,
    COUNT(*) AS tactical_foul_count
FROM match_events e
INNER JOIN (
    -- 这是子查询:找出所有犯规前存在对方反击行为的犯规事件ID
    SELECT f.id
    FROM match_events f
    WHERE f.event_type = 'foul'
    AND EXISTS (
        SELECT 1 FROM match_events as counter
        WHERE counter.match_id = f.match_id
          AND counter.team_id != f.team_id 
          AND counter.event_type IN ('interception', 'turnover', 'save')
          AND counter.tick_time BETWEEN (f.tick_time - 5) AND f.tick_time
    )
) AS tactical ON e.id = tactical.id
GROUP BY e.team_id
ORDER BY tactical_foul_count DESC;

优化与实际建议

  1. 数据准确性:纯粹的自动判定可能产生误判(例如对方后场控球不算反击),建议在比赛中由数据录入员手动标记 action_subtype = 'tactical',自动逻辑作为辅助或补充。
  2. 性能优化:如果数据量巨大(几十万条事件),上述子查询可能会很慢,建议为 match_events 建立复合索引 (match_id, tick_time, event_type)
  3. 防守位置判断:高级统计会使用 x_coord,如果犯规发生在本方禁区前沿,可能不算“阻止反击”,可以添加条件:
    if ($foul['x_coord'] < 50) { // 假设坐标0-100
        return false;
    }

方案提供了从数据库设计到PHP逻辑的完整闭环,你可以根据项目实际情况调整 timeWindowSeconds 和事件类型。

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