本文目录导读:

我来帮你设计一个PHP项目统计界外球进攻威胁次数的解决方案,这需要根据你的具体数据结构来调整,我先提供一个通用的方案。
数据库表设计
-- 比赛事件表
CREATE TABLE match_events (
id INT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
team_id INT NOT NULL,
event_type ENUM('throw_in', 'corner', 'goal_kick') NOT NULL,
x_position DECIMAL(5,2), -- 球场X坐标(0-100)
y_position DECIMAL(5,2), -- 球场Y坐标(0-100)
threat_level TINYINT DEFAULT 0, -- 威胁等级1-5
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_match (match_id),
INDEX idx_team (team_id)
);
-- 球队表
CREATE TABLE teams (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL
);
统计类 PHP 代码
<?php
class ThrowInThreatAnalyzer {
private $db;
public function __construct($pdo) {
$this->db = $pdo;
}
/**
* 统计界外球进攻威胁次数
* @param int $matchId 比赛ID
* @param int $teamId 球队ID
* @param string $period 时间段 (可选: 'first_half', 'second_half', 'full_match')
* @return array 统计数据
*/
public function analyzeThreatFrequency($matchId, $teamId, $period = 'full_match') {
// 基础查询
$sql = "SELECT
id,
event_type,
x_position,
y_position,
threat_level,
created_at
FROM match_events
WHERE match_id = :match_id
AND team_id = :team_id
AND event_type = 'throw_in'";
// 添加时间段筛选
if ($period != 'full_match') {
$sql .= " AND ";
if ($period == 'first_half') {
$sql .= "created_at < DATE_ADD((SELECT kickoff_time FROM matches WHERE id = :match_id), INTERVAL 45 MINUTE)";
} else {
$sql .= "created_at >= DATE_ADD((SELECT kickoff_time FROM matches WHERE id = :match_id), INTERVAL 45 MINUTE)";
}
}
$stmt = $this->db->prepare($sql);
$params = ['match_id' => $matchId, 'team_id' => $teamId];
if ($period != 'full_match') {
$params['match_id'] = $matchId; // 重复用于子查询
}
$stmt->execute($params);
$events = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 统计分析
$analysis = [
'total_throw_ins' => count($events),
'threat_events' => 0,
'high_threat_events' => 0,
'by_zone' => [
'attack_third' => 0, // 进攻三区
'middle_third' => 0, // 中场三区
'defensive_third' => 0 // 防守三区
],
'by_position' => [
'left_flank' => 0,
'central' => 0,
'right_flank' => 0
],
'threat_levels' => [
1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0
],
'threat_rate' => 0, // 威胁率
'average_threat' => 0 // 平均威胁值
];
foreach ($events as $event) {
// 判断区域
$zone = $this->getZone($event['x_position']);
$position = $this->getPosition($event['y_position']);
// 统计区域分布
$analysis['by_zone'][$zone]++;
$analysis['by_position'][$position]++;
// 威胁等级统计
$analysis['threat_levels'][$event['threat_level']]++;
// 判断是否为威胁事件 (威胁等级 >= 3)
if ($event['threat_level'] >= 3) {
$analysis['threat_events']++;
}
// 高威胁事件 (威胁等级 >= 4)
if ($event['threat_level'] >= 4) {
$analysis['high_threat_events']++;
}
}
// 计算比例
if ($analysis['total_throw_ins'] > 0) {
$analysis['threat_rate'] = round(($analysis['threat_events'] / $analysis['total_throw_ins']) * 100, 2);
$analysis['average_threat'] = round(array_sum(array_keys($analysis['threat_levels'])), 2);
}
return $analysis;
}
/**
* 获取球场区域
*/
private function getZone($xPosition) {
// 假设球场X坐标为0-100, 0为防守端, 100为进攻端
if ($xPosition < 33.33) {
return 'defensive_third';
} elseif ($xPosition < 66.67) {
return 'middle_third';
} else {
return 'attack_third';
}
}
/**
* 获取位置(左中右)
*/
private function getPosition($yPosition) {
if ($yPosition < 33.33) {
return 'left_flank';
} elseif ($yPosition < 66.67) {
return 'central';
} else {
return 'right_flank';
}
}
/**
* 统计一段时间内的威胁次数
*/
public function threatOverTime($matchId, $teamId, $intervalMinutes = 5) {
$sql = "SELECT
MINUTE(created_at) / :interval_minutes AS time_bucket,
COUNT(*) as total,
SUM(CASE WHEN threat_level >= 3 THEN 1 ELSE 0 END) as threats
FROM match_events
WHERE match_id = :match_id
AND team_id = :team_id
AND event_type = 'throw_in'
GROUP BY time_bucket
ORDER BY time_bucket";
$stmt = $this->db->prepare($sql);
$stmt->execute([
'match_id' => $matchId,
'team_id' => $teamId,
'interval_minutes' => $intervalMinutes
]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 对比两队威胁情况
*/
public function compareTeams($matchId, $teamAId, $teamBId) {
$teamA = $this->analyzeThreatFrequency($matchId, $teamAId);
$teamB = $this->analyzeThreatFrequency($matchId, $teamBId);
return [
'team_a' => $teamA,
'team_b' => $teamB,
'comparison' => [
'a_more_threats' => $teamA['threat_events'] > $teamB['threat_events'],
'difference' => abs($teamA['threat_events'] - $teamB['threat_events']),
'a_threat_rate' => $teamA['threat_rate'],
'b_threat_rate' => $teamB['threat_rate']
]
];
}
}
// 使用示例
try {
$pdo = new PDO("mysql:host=localhost;dbname=football_stats", "username", "password");
$analyzer = new ThrowInThreatAnalyzer($pdo);
// 统计单场比赛
$result = $analyzer->analyzeThreatFrequency(1, 101);
print_r($result);
// 对比两队
$comparison = $analyzer->compareTeams(1, 101, 102);
print_r($comparison);
} catch (PDOException $e) {
echo "数据库连接错误: " . $e->getMessage();
}
?>
更具体的统计方法
<?php
class AdvancedThreatStatistics {
/**
* 分析界外球进攻威胁特征
*/
public function analyzeThreatCharacteristics($pdo, $matchId, $teamId) {
// 统计不同区域的威胁表现
$zoneStats = $this->getZoneThreatStats($pdo, $matchId, $teamId);
// 分析威胁趋势
$trendAnalysis = $this->getThreatTrendAnalysis($pdo, $matchId, $teamId);
// 定义威胁评估标准
$threatCriteria = [
'high_threat_zone' => ['start_x' => 70, 'end_x' => 100], // 进攻三区
'dangerous_zone' => ['start_x' => 80, 'end_x' => 100], // 危险区域
'key_moments' => [85, 90], // 关键时刻(比赛最后5分钟)
'set_piece_potential' => 3 // 任意球/角球转化潜力
];
return [
'zone_stats' => $zoneStats,
'trend' => $trendAnalysis,
'key_findings' => $this->generateKeyFindings($zoneStats, $trendAnalysis, $threatCriteria)
];
}
/**
* 获取区域威胁统计
*/
private function getZoneThreatStats($pdo, $matchId, $teamId) {
$sql = "SELECT
CASE
WHEN x_position >= 70 THEN 'high_threat_zone'
WHEN x_position >= 33.33 THEN 'middle_zone'
ELSE 'defensive_zone'
END as zone,
COUNT(*) as throw_ins,
AVG(threat_level) as avg_threat,
SUM(CASE WHEN threat_level >= 3 THEN 1 ELSE 0 END) as threat_events
FROM match_events
WHERE match_id = ? AND team_id = ? AND event_type = 'throw_in'
GROUP BY zone";
$stmt = $pdo->prepare($sql);
$stmt->execute([$matchId, $teamId]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 填充默认值
$zones = ['high_threat_zone' => 0, 'middle_zone' => 0, 'defensive_zone' => 0];
foreach ($results as $result) {
$zones[$result['zone']] = $result;
}
return $zones;
}
/**
* 趋势分析
*/
private function getThreatTrendAnalysis($pdo, $matchId, $teamId) {
$sql = "SELECT
HOUR(created_at) * 60 + MINUTE(created_at) as game_minute,
threat_level,
x_position,
y_position
FROM match_events
WHERE match_id = ? AND team_id = ? AND event_type = 'throw_in'
ORDER BY created_at";
$stmt = $pdo->prepare($sql);
$stmt->execute([$matchId, $teamId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 生成关键发现
*/
private function generateKeyFindings($zoneStats, $trend, $criteria) {
$findings = [];
// 检查进攻三区的威胁
if ($zoneStats['high_threat_zone']['threat_events'] > 5) {
$findings[] = "进攻三区的界外球形成了明显的威胁,共产生了 {$zoneStats['high_threat_zone']['threat_events']} 次有效威胁";
}
// 检查比赛末段的威胁
$endThreats = array_filter($trend, function($event) use ($criteria) {
foreach ($criteria['key_moments'] as $minute) {
if ($event['game_minute'] >= $minute * 60 - 300) {
return true;
}
}
return false;
});
if (count($endThreats) > 3) {
$findings[] = "比赛末段界外球攻击活跃,可能利用防守方体力下降";
}
return $findings;
}
}
?>
可视化图表生成(可选)
<?php
class ThreatChartGenerator {
public function generateHeatmap($pdo, $matchId, $teamId) {
// 获取位置数据
$sql = "SELECT x_position, y_position, threat_level
FROM match_events
WHERE match_id = ? AND team_id = ? AND event_type = 'throw_in'";
$stmt = $pdo->prepare($sql);
$stmt->execute([$matchId, $teamId]);
$events = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 转换坐标为热力图数据
$heatmapData = [];
foreach ($events as $event) {
$heatmapData[] = [
'x' => round($event['x_position'] / 10) * 10,
'y' => round($event['y_position'] / 10) * 10,
'value' => $event['threat_level']
];
}
// 返回用于前端展示的数据
return json_encode([
'type' => 'heatmap',
'data' => $heatmapData,
'config' => [
'title' => '界外球进攻威胁热力图',
'colors' => ['#00FF00', '#FFFF00', '#FF0000'] // 绿-黄-红
]
]);
}
public function generateLineChart($pdo, $matchId, $teamId) {
$sql = "SELECT MINUTE(created_at) as minute, COUNT(*) as count, AVG(threat_level) as avg_threat
FROM match_events
WHERE match_id = ? AND team_id = ? AND event_type = 'throw_in'
GROUP BY minute";
$stmt = $pdo->prepare($sql);
$stmt->execute([$matchId, $teamId]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
return json_encode([
'type' => 'line',
'data' => $results,
'config' => [
'title' => '界外球威胁趋势',
'xlabel' => '比赛时间(分钟)',
'ylabel' => '威胁值'
]
]);
}
}
?>
使用说明
- 数据要求:需要记录每次界外球的坐标位置和威胁等级
- 字段说明:
x_position: 水平位置(0-100)y_position: 垂直位置(0-100)threat_level: 1-5级威胁等级
- 统计指标:
- 总界外球次数
- 威胁次数(等级≥3)
- 各区域分布
- 威胁率
- 平均威胁值
这个方案可以灵活扩展,根据实际需求调整统计逻辑和展示方式,如果需要更具体的功能或数据结构,请提供更多细节。