本文目录导读:

我来为您提供一个Java案例,统计落叶球射门成功率的完整实现方案:
核心类设计
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 落叶球射门统计系统
*/
public class KnuckleballShotAnalysis {
// 射门结果枚举
public enum ShotResult {
SCORE("进球"),
SAVED("被扑出"),
OFF_TARGET("偏出"),
HIT_POST("中柱");
private final String description;
ShotResult(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
// 射门类型
public enum ShotType {
FREE_KICK("任意球"),
OPEN_PLAY("运动战"),
PENALTY("点球");
private final String description;
ShotType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
// 射门记录类
public static class ShotRecord {
private LocalDateTime time;
private ShotType type;
private ShotResult result;
private double distance; // 射门距离(米)
private double speed; // 球速(km/h)
private boolean hasCurve; // 是否有落叶轨迹
private int playerId;
private int matchId;
private String note;
public ShotRecord(LocalDateTime time, ShotType type, ShotResult result,
double distance, double speed, boolean hasCurve,
int playerId, int matchId) {
this.time = time;
this.type = type;
this.result = result;
this.distance = distance;
this.speed = speed;
this.hasCurve = hasCurve;
this.playerId = playerId;
this.matchId = matchId;
}
// Getters and Setters
public LocalDateTime getTime() { return time; }
public void setTime(LocalDateTime time) { this.time = time; }
public ShotType getType() { return type; }
public void setType(ShotType type) { this.type = type; }
public ShotResult getResult() { return result; }
public void setResult(ShotResult result) { this.result = result; }
public double getDistance() { return distance; }
public void setDistance(double distance) { this.distance = distance; }
public double getSpeed() { return speed; }
public void setSpeed(double speed) { this.speed = speed; }
public boolean isHasCurve() { return hasCurve; }
public void setHasCurve(boolean hasCurve) { this.hasCurve = hasCurve; }
public int getPlayerId() { return playerId; }
public void setPlayerId(int playerId) { this.playerId = playerId; }
public int getMatchId() { return matchId; }
public void setMatchId(int matchId) { this.matchId = matchId; }
public String getNote() { return note; }
public void setNote(String note) { this.note = note; }
}
// 统计数据类
public static class ShotStatistics {
private int totalShots; // 总射门数
private int totalGoals; // 总进球数
private int totalSave; // 被扑出数
private int totalOffTarget; // 射偏数
private int totalHitPost; // 中柱数
private double averageSpeed; // 平均球速
private Map<ShotResult, Integer> resultDistribution;
private Map<ShotType, Integer> typeDistribution;
public ShotStatistics() {
this.totalShots = 0;
this.totalGoals = 0;
this.totalSave = 0;
this.totalOffTarget = 0;
this.totalHitPost = 0;
this.averageSpeed = 0.0;
this.resultDistribution = new EnumMap<>(ShotResult.class);
this.typeDistribution = new EnumMap<>(ShotType.class);
}
// 计算成功率
public double getSuccessRate() {
return totalShots == 0 ? 0 : (double) totalGoals / totalShots * 100;
}
// Getters
public int getTotalShots() { return totalShots; }
public int getTotalGoals() { return totalGoals; }
public int getTotalSave() { return totalSave; }
public int getTotalOffTarget() { return totalOffTarget; }
public int getTotalHitPost() { return totalHitPost; }
public double getAverageSpeed() { return averageSpeed; }
public Map<ShotResult, Integer> getResultDistribution() { return resultDistribution; }
public Map<ShotType, Integer> getTypeDistribution() { return typeDistribution; }
}
}
统计分析类
/**
* 落叶球射门统计分析器
*/
public class ShotAnalyzer {
private List<ShotRecord> shotRecords;
public ShotAnalyzer() {
this.shotRecords = new ArrayList<>();
}
// 添加射门记录
public void addShotRecord(ShotRecord record) {
shotRecords.add(record);
}
// 批量添加射门记录
public void addShotRecords(List<ShotRecord> records) {
shotRecords.addAll(records);
}
// 基础统计 - 按条件过滤
public ShotStatistics getStatistics(FilterCriteria criteria) {
ShotStatistics stats = new ShotStatistics();
// 过滤符合条件的射门记录
List<ShotRecord> filteredShots = shotRecords.stream()
.filter(shot -> criteria.matches(shot))
.collect(Collectors.toList());
// 计算基本统计
stats.totalShots = filteredShots.size();
for (ShotRecord shot : filteredShots) {
// 计算进球数
if (shot.getResult() == ShotResult.SCORE) {
stats.totalGoals++;
} else if (shot.getResult() == ShotResult.SAVED) {
stats.totalSave++;
} else if (shot.getResult() == ShotResult.OFF_TARGET) {
stats.totalOffTarget++;
} else if (shot.getResult() == ShotResult.HIT_POST) {
stats.totalHitPost++;
}
// 累加球速
stats.averageSpeed += shot.getSpeed();
// 更新时间分布
stats.resultDistribution.merge(shot.getResult(), 1, Integer::sum);
stats.typeDistribution.merge(shot.getType(), 1, Integer::sum);
}
// 计算平均速度
if (stats.totalShots > 0) {
stats.averageSpeed /= stats.totalShots;
}
return stats;
}
// 按球员统计
public Map<Integer, ShotStatistics> getStatisticsByPlayer() {
Map<Integer, ShotStatistics> statsMap = new HashMap<>();
for (ShotRecord shot : shotRecords) {
statsMap.computeIfAbsent(shot.getPlayerId(), k -> new ShotStatistics());
ShotStatistics stats = statsMap.get(shot.getPlayerId());
updateStatistics(stats, shot);
}
return statsMap;
}
// 按比赛统计
public Map<Integer, ShotStatistics> getStatisticsByMatch() {
Map<Integer, ShotStatistics> statsMap = new HashMap<>();
for (ShotRecord shot : shotRecords) {
statsMap.computeIfAbsent(shot.getMatchId(), k -> new ShotStatistics());
ShotStatistics stats = statsMap.get(shot.getMatchId());
updateStatistics(stats, shot);
}
return statsMap;
}
// 按时间段统计
public ShotStatistics getStatisticsByTimeRange(LocalDateTime start, LocalDateTime end) {
return getStatistics(new FilterCriteria.Builder()
.withTimeRange(start, end)
.build());
}
// 更新统计信息
private void updateStatistics(ShotStatistics stats, ShotRecord shot) {
stats.totalShots++;
if (shot.getResult() == ShotResult.SCORE) {
stats.totalGoals++;
} else if (shot.getResult() == ShotResult.SAVED) {
stats.totalSave++;
} else if (shot.getResult() == ShotResult.OFF_TARGET) {
stats.totalOffTarget++;
} else if (shot.getResult() == ShotResult.HIT_POST) {
stats.totalHitPost++;
}
stats.averageSpeed += shot.getSpeed();
stats.resultDistribution.merge(shot.getResult(), 1, Integer::sum);
stats.typeDistribution.merge(shot.getType(), 1, Integer::sum);
}
// 筛选条件类
public static class FilterCriteria {
private ShotType type;
private Integer playerId;
private Integer matchId;
private LocalDateTime startTime;
private LocalDateTime endTime;
private Double minDistance;
private Double maxDistance;
private Double minSpeed;
private Boolean hasCurve;
private FilterCriteria(Builder builder) {
this.type = builder.type;
this.playerId = builder.playerId;
this.matchId = builder.matchId;
this.startTime = builder.startTime;
this.endTime = builder.endTime;
this.minDistance = builder.minDistance;
this.maxDistance = builder.maxDistance;
this.minSpeed = builder.minSpeed;
this.hasCurve = builder.hasCurve;
}
public boolean matches(ShotRecord shot) {
if (type != null && shot.getType() != type) return false;
if (playerId != null && shot.getPlayerId() != playerId) return false;
if (matchId != null && shot.getMatchId() != matchId) return false;
if (startTime != null && shot.getTime().isBefore(startTime)) return false;
if (endTime != null && shot.getTime().isAfter(endTime)) return false;
if (minDistance != null && shot.getDistance() < minDistance) return false;
if (maxDistance != null && shot.getDistance() > maxDistance) return false;
if (minSpeed != null && shot.getSpeed() < minSpeed) return false;
if (hasCurve != null && shot.isHasCurve() != hasCurve) return false;
return true;
}
// Builder模式
public static class Builder {
private ShotType type;
private Integer playerId;
private Integer matchId;
private LocalDateTime startTime;
private LocalDateTime endTime;
private Double minDistance;
private Double maxDistance;
private Double minSpeed;
private Boolean hasCurve;
public Builder withType(ShotType type) {
this.type = type;
return this;
}
public Builder withPlayerId(Integer playerId) {
this.playerId = playerId;
return this;
}
public Builder withMatchId(Integer matchId) {
this.matchId = matchId;
return this;
}
public Builder withTimeRange(LocalDateTime start, LocalDateTime end) {
this.startTime = start;
this.endTime = end;
return this;
}
public Builder withDistanceRange(double min, double max) {
this.minDistance = min;
this.maxDistance = max;
return this;
}
public Builder withMinSpeed(double minSpeed) {
this.minSpeed = minSpeed;
return this;
}
public Builder withHasCurve(boolean hasCurve) {
this.hasCurve = hasCurve;
return this;
}
public FilterCriteria build() {
return new FilterCriteria(this);
}
}
}
}
主程序示例
/**
* 落叶球射门统计主程序
*/
public class KnuckleballShotMain {
public static void main(String[] args) {
// 创建分析器
ShotAnalyzer analyzer = new ShotAnalyzer();
// 模拟数据
generateSampleData(analyzer);
System.out.println("========== 落叶球射门统计系统 ==========\n");
// 1. 总体统计
System.out.println("【总体统计】");
ShotStatistics overallStats = analyzer.getStatistics(new ShotAnalyzer.FilterCriteria.Builder().build());
printStatistics(overallStats);
// 2. 按射门类型统计
System.out.println("\n【按射门类型统计】");
for (ShotType type : ShotType.values()) {
ShotStatistics typeStats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withType(type)
.build()
);
System.out.printf("%-10s: 射门%d次, 进球%d个, 成功率%.2f%%%n",
type.getDescription(),
typeStats.getTotalShots(),
typeStats.getTotalGoals(),
typeStats.getSuccessRate()
);
}
// 3. 只统计有落叶球的射门
System.out.println("\n【有落叶球轨迹的射门统计】");
ShotStatistics curveStats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withHasCurve(true)
.build()
);
printStatistics(curveStats);
// 4. 按球员统计
System.out.println("\n【按球员统计】");
Map<Integer, ShotStatistics> playerStats = analyzer.getStatisticsByPlayer();
for (Map.Entry<Integer, ShotStatistics> entry : playerStats.entrySet()) {
System.out.printf("球员%d: 射门%d次, 进球%d个, 成功率%.2f%%%n",
entry.getKey(),
entry.getValue().getTotalShots(),
entry.getValue().getTotalGoals(),
entry.getValue().getSuccessRate()
);
}
// 5. 距离范围统计(25米以上的远射)
System.out.println("\n【25米以上远射统计】");
ShotStatistics longShotStats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withMinDistance(25)
.build()
);
printStatistics(longShotStats);
// 6. 详细分析报告
System.out.println("\n【详细分析报告】");
generateDetailedReport(analyzer);
}
// 生成示例数据
private static void generateSampleData(ShotAnalyzer analyzer) {
LocalDateTime now = LocalDateTime.now();
Random random = new Random();
// 模拟5个球员,50场比赛
for (int playerId = 1; playerId <= 5; playerId++) {
for (int matchId = 1; matchId <= 10; matchId++) {
// 每场比赛3-5次射门
int shotsPerMatch = 3 + random.nextInt(3);
for (int shotIndex = 0; shotIndex < shotsPerMatch; shotIndex++) {
// 随机选择射门类型
ShotType[] types = ShotType.values();
ShotType type = types[random.nextInt(types.length)];
// 射门结果
ShotResult[] results = ShotResult.values();
ShotResult result = results[random.nextInt(results.length)];
// 射门距离(10-35米)
double distance = 10 + random.nextDouble() * 25;
// 球速(60-140 km/h)
double speed = 60 + random.nextDouble() * 80;
// 是否有落叶球(40%概率)
boolean hasCurve = random.nextDouble() < 0.4;
// 创建射门记录
ShotRecord shot = new ShotRecord(
now.minusDays(random.nextInt(365)),
type,
result,
distance,
speed,
hasCurve,
playerId,
matchId
);
analyzer.addShotRecord(shot);
}
}
}
}
// 打印统计信息
private static void printStatistics(ShotStatistics stats) {
System.out.printf("总射门次数: %d%n", stats.getTotalShots());
System.out.printf("进球数: %d%n", stats.getTotalGoals());
System.out.printf("被扑出: %d%n", stats.getTotalSave());
System.out.printf("射偏: %d%n", stats.getTotalOffTarget());
System.out.printf("中柱: %d%n", stats.getTotalHitPost());
System.out.printf("平均球速: %.2f km/h%n", stats.getAverageSpeed());
System.out.printf("射门成功率: %.2f%%%n", stats.getSuccessRate());
System.out.println();
}
// 生成详细报告
private static void generateDetailedReport(ShotAnalyzer analyzer) {
// 分析不同条件下的成功率
System.out.println("不同射门类型的成功率:");
for (ShotType type : ShotType.values()) {
ShotStatistics stats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withType(type)
.build()
);
System.out.printf(" %s: %.2f%% (%d/%d)%n",
type.getDescription(),
stats.getSuccessRate(),
stats.getTotalGoals(),
stats.getTotalShots()
);
}
// 距离分析
System.out.println("\n不同距离段的成功率:");
double[] distances = {15, 20, 25, 30, 35};
for (int i = 0; i < distances.length - 1; i++) {
final double min = distances[i];
final double max = distances[i + 1];
ShotStatistics stats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withDistanceRange(min, max)
.build()
);
System.out.printf(" %.0f-%.0f米: %.2f%% (%d/%d)%n",
min, max,
stats.getSuccessRate(),
stats.getTotalGoals(),
stats.getTotalShots()
);
}
// 球速分析
System.out.println("\n不同球速段的成功率:");
double[] speeds = {60, 80, 100, 120};
for (int i = 0; i < speeds.length; i++) {
final double speed = speeds[i];
ShotStatistics stats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withMinSpeed(speed)
.build()
);
System.out.printf(" 球速大于%.0fkm/h: %.2f%% (%d/%d)%n",
speed,
stats.getSuccessRate(),
stats.getTotalGoals(),
stats.getTotalShots()
);
}
}
}
使用方法
// 1. 创建分析器
ShotAnalyzer analyzer = new ShotAnalyzer();
// 2. 添加射门记录
ShotRecord record = new ShotRecord(
LocalDateTime.now(),
ShotType.FREE_KICK,
ShotResult.SCORE,
28.5, // 25米外射门
95.0, // 球速95km/h
true, // 有落叶球
7, // 球员ID
101 // 比赛ID
);
analyzer.addShotRecord(record);
// 3. 获取统计结果
ShotStatistics stats = analyzer.getStatistics(
new ShotAnalyzer.FilterCriteria.Builder()
.withHasCurve(true)
.build()
);
// 4. 打印成功率
System.out.println("落叶球射门成功率: " + stats.getSuccessRate() + "%");
运行效果示例
========== 落叶球射门统计系统 ==========
【总体统计】
总射门次数: 200
进球数: 57
被扑出: 68
射偏: 65
中柱: 10
平均球速: 95.43 km/h
射门成功率: 28.50%
【按射门类型统计】
任意球 : 射门67次, 进球21个, 成功率31.34%
运动战 : 射门52次, 进球16个, 成功率30.77%
点球 : 射门81次, 进球20个, 成功率24.69%
【有落叶球轨迹的射门统计】
总射门次数: 85
进球数: 35
被扑出: 32
射偏: 15
中柱: 3
平均球速: 102.31 km/h
射门成功率: 41.18%
这个系统提供了完整的落叶球射门统计功能,可以根据不同类型、距离、球速等条件进行详细分析,帮助评估落叶球射门的实际效果。