java案例如何评估门将扑救反应速度?

wen java案例 1

本文目录导读:

java案例如何评估门将扑救反应速度?

  1. 系统设计思路
  2. 完整实现代码
  3. 测试结果示例
  4. 扩展功能建议

我来提供一个基于Java的门将扑救反应速度评估系统的设计方案和代码示例。

系统设计思路

核心评估指标

  • 反应时间:从球射出到门将开始移动的时间
  • 扑救成功率:成功扑救次数/总射门次数
  • 移动速度:门将移动到扑救点的时间
  • 判断准确率:正确判断球方向的比例

完整实现代码

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
// 扑救事件类
class SaveEvent {
    private final String shotDirection;  // 射门方向
    private final double shotSpeed;      // 球速 (m/s)
    private final double shotDistance;   // 射门距离 (m)
    private final Instant shotTime;      // 射门时间
    private Instant reactionTime;        // 反应时间
    private Instant movementTime;        // 移动完成时间
    private boolean isSaved;             // 是否扑救成功
    public SaveEvent(String direction, double speed, double distance) {
        this.shotDirection = direction;
        this.shotSpeed = speed;
        this.shotDistance = distance;
        this.shotTime = Instant.now();
    }
    // Getters and Setters
    public String getShotDirection() { return shotDirection; }
    public double getShotSpeed() { return shotSpeed; }
    public double getShotDistance() { return shotDistance; }
    public Instant getShotTime() { return shotTime; }
    public Instant getReactionTime() { return reactionTime; }
    public void setReactionTime(Instant reactionTime) { this.reactionTime = reactionTime; }
    public Instant getMovementTime() { return movementTime; }
    public void setMovementTime(Instant movementTime) { this.movementTime = movementTime; }
    public boolean isSaved() { return isSaved; }
    public void setSaved(boolean saved) { isSaved = saved; }
    // 计算反应时间(毫秒)
    public long getReactionTimeMs() {
        if (reactionTime == null) return -1;
        return Duration.between(shotTime, reactionTime).toMillis();
    }
    // 计算总扑救时间
    public long getTotalSaveTimeMs() {
        if (movementTime == null) return -1;
        return Duration.between(shotTime, movementTime).toMillis();
    }
}
// 门将扑救模拟器
class GoalkeeperSimulator {
    private final String goalkeeperName;
    private final List<SaveEvent> saveEvents = new ArrayList<>();
    private double baseReactionTime;  // 基础反应时间(毫秒)
    public GoalkeeperSimulator(String name, double baseReactionTime) {
        this.goalkeeperName = name;
        this.baseReactionTime = baseReactionTime;
    }
    // 模拟一次射门事件
    public SaveEvent simulateShot() {
        // 随机生成射门参数
        String[] directions = {"left", "right", "center", "top-left", "top-right", "bottom-left", "bottom-right"};
        String direction = directions[ThreadLocalRandom.current().nextInt(directions.length)];
        double speed = ThreadLocalRandom.current().nextDouble(20, 35);  // 球速 20-35 m/s
        double distance = ThreadLocalRandom.current().nextDouble(5, 12); // 距离 5-12 米
        SaveEvent event = new SaveEvent(direction, speed, distance);
        // 模拟门将反应时间
        // 考虑球速和距离对反应时间的影响
        double reactionFactor = 1.0;
        // 球速影响:球速越快,反应时间越短(但更难以扑救)
        if (speed > 30) {
            reactionFactor *= 0.8;
        } else if (speed > 25) {
            reactionFactor *= 0.9;
        }
        // 射门距离影响:距离越远,有更多时间反应
        double distanceFactor = 1.0 + (distance - 8) * 0.05;
        reactionFactor *= distanceFactor;
        // 计算实际反应时间
        double actualReactionTime = baseReactionTime * reactionFactor;
        actualReactionTime += ThreadLocalRandom.current().nextDouble(-50, 50); // 添加随机波动
        // 设置反应时间
        Thread.sleep(1); // 小延迟确保时间戳不同
        event.setReactionTime(Instant.now());
        // 模拟移动时间(基于反应速度和扑救难度)
        double movementTime = actualReactionTime * 0.8 + 
                             ThreadLocalRandom.current().nextDouble(100, 250);
        // 模拟扑救结果
        Thread.sleep(1);
        event.setMovementTime(Instant.now());
        // 计算扑救成功率
        double saveProbability = calculateSaveProbability(event, actualReactionTime, movementTime);
        boolean isSaved = ThreadLocalRandom.current().nextDouble(100) < saveProbability * 100;
        event.setSaved(isSaved);
        saveEvents.add(event);
        return event;
    }
    // 计算扑救概率
    private double calculateSaveProbability(SaveEvent event, double reactionTime, double movementTime) {
        double probability = 0.5; // 基础概率
        // 反应时间因素(每快50ms,提高5%成功率)
        double reactionBonus = (250 - reactionTime) / 50 * 0.05;
        probability += reactionBonus;
        // 移动时间因素
        double movementBonus = (400 - movementTime) / 100 * 0.08;
        probability += movementBonus;
        // 方向因素(中间位置更容易扑救)
        if (event.getShotDirection().equals("center")) {
            probability += 0.1;
        } else if (event.getShotDirection().startsWith("top") || 
                  event.getShotDirection().startsWith("bottom")) {
            probability -= 0.1; // 上下角更难扑救
        }
        // 球速因素
        if (event.getShotSpeed() > 30) {
            probability -= 0.1;
        }
        // 限制在合理范围
        return Math.max(0.1, Math.min(0.95, probability));
    }
    // 模拟一段时间的表现
    public void simulateSession(int numberOfShots) {
        System.out.printf("\n===== %s 的门将扑救模拟 =====%n", goalkeeperName);
        System.out.println("射门次数: " + numberOfShots);
        System.out.println("基础反应时间: " + baseReactionTime + "ms");
        System.out.println("\n模拟开始...\n");
        for (int i = 0; i < numberOfShots; i++) {
            SaveEvent event = simulateShot();
            printEventResult(i + 1, event);
        }
    }
    // 打印单个事件结果
    private void printEventResult(int shotNumber, SaveEvent event) {
        System.out.printf("射门 #%d | 方向: %-10s | 速度: %.1f m/s | " +
                         "反应时间: %dms | 扑救时间: %dms | 结果: %s%n",
                shotNumber,
                event.getShotDirection(),
                event.getShotSpeed(),
                event.getReactionTimeMs(),
                event.getTotalSaveTimeMs(),
                event.isSaved() ? "✓ 扑救成功" : "✗ 进球");
    }
    // 统计分析
    public void generateStatistics() {
        if (saveEvents.isEmpty()) {
            System.out.println("暂无数据");
            return;
        }
        int totalShots = saveEvents.size();
        long successfulSaves = saveEvents.stream().filter(SaveEvent::isSaved).count();
        // 计算平均反应时间
        double avgReactionTime = saveEvents.stream()
                .mapToLong(SaveEvent::getReactionTimeMs)
                .filter(t -> t >= 0)
                .average()
                .orElse(0);
        // 计算平均总扑救时间
        double avgTotalTime = saveEvents.stream()
                .mapToLong(SaveEvent::getTotalSaveTimeMs)
                .filter(t -> t >= 0)
                .average()
                .orElse(0);
        // 最佳和最差表现
        OptionalLong fastestReaction = saveEvents.stream()
                .mapToLong(SaveEvent::getReactionTimeMs)
                .filter(t -> t >= 0)
                .min();
        OptionalLong slowestReaction = saveEvents.stream()
                .mapToLong(SaveEvent::getReactionTimeMs)
                .filter(t -> t >= 0)
                .max();
        // 各方向统计
        Map<String, Long> directionStats = new HashMap<>();
        Map<String, Long> saveStats = new HashMap<>();
        for (SaveEvent event : saveEvents) {
            directionStats.merge(event.getShotDirection(), 1L, Long::sum);
            if (event.isSaved()) {
                saveStats.merge(event.getShotDirection(), 1L, Long::sum);
            }
        }
        // 输出统计报告
        System.out.println("\n========== 数据分析报告 ==========");
        System.out.printf("门将: %s%n", goalkeeperName);
        System.out.printf("总射门次数: %d%n", totalShots);
        System.out.printf("扑救成功次数: %d (%d%%)%n", 
                successfulSaves, 
                (int)((double)successfulSaves/totalShots*100));
        System.out.printf("扑救成功率: %.1f%%%n", 
                (double)successfulSaves/totalShots*100);
        System.out.println("\n反应时间分析:");
        System.out.printf("  平均反应时间: %.0fms%n", avgReactionTime);
        System.out.printf("  最快反应时间: %dms%n", fastestReaction.orElse(-1));
        System.out.printf("  最慢反应时间: %dms%n", slowestReaction.orElse(-1));
        System.out.printf("  平均总扑救时间: %.0fms%n", avgTotalTime);
        System.out.println("\n各方向表现:");
        for (String direction : directionStats.keySet()) {
            long shots = directionStats.get(direction);
            long saves = saveStats.getOrDefault(direction, 0L);
            double saveRate = (double) saves / shots * 100;
            System.out.printf("  %-10s: %d次射门, %d次扑救 (%d%%)%n", 
                    direction, shots, saves, (int)saveRate);
        }
        // 评分系统(0-100分)
        int score = calculateOverallScore(avgReactionTime, 
                                        (double)successfulSaves/totalShots);
        System.out.printf("\n门将综合评价: %d/100 分%n", score);
        if (score >= 90) {
            System.out.println("评级: 世界级门将");
        } else if (score >= 80) {
            System.out.println("评级: 精英级门将");
        } else if (score >= 70) {
            System.out.println("评级: 优秀门将");
        } else if (score >= 60) {
            System.out.println("评级: 中游水平门将");
        } else {
            System.out.println("评级: 需要改进的门将");
        }
    }
    // 计算综合评分
    private int calculateOverallScore(double avgReactionTime, double saveRate) {
        // 反应时间评分 (200ms=100分, 400ms=0分)
        int reactionScore = Math.max(0, Math.min(100, 
                (int)(100 - ((avgReactionTime - 200) / 2))));
        // 扑救成功率评分
        int saveScore = (int)(saveRate * 100);
        // 加权平均
        return (int)(reactionScore * 0.4 + saveScore * 0.6);
    }
    // 实时性能监控系统
    public void performanceMonitor() {
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                if (!saveEvents.isEmpty()) {
                    SaveEvent lastEvent = saveEvents.get(saveEvents.size() - 1);
                    System.out.printf("实时监控 | 最近反应: %dms | 保存率: %.1f%% | 活性: %.2f%n",
                            lastEvent.getReactionTimeMs(),
                            (double)saveEvents.stream().filter(SaveEvent::isSaved).count() / 
                            saveEvents.size() * 100,
                            Math.max(0, 1.0 - lastEvent.getReactionTimeMs() / 500.0));
                }
            }
        };
        // 每5秒输出一次实时状态
        timer.scheduleAtFixedRate(task, 0, 5000);
    }
}
// 主程序入口
public class GoalkeeperReactionTest {
    public static void main(String[] args) {
        // 测试用例1:优秀门将(快速反应)
        System.out.println("=== 测试用例1: 优秀门将 ===");
        GoalkeeperSimulator eliteGK = new GoalkeeperSimulator("优秀门将", 180);
        eliteGK.simulateSession(20);
        eliteGK.generateStatistics();
        // 测试用例2:普通门将(中等反应)
        System.out.println("\n=== 测试用例2: 普通门将 ===");
        GoalkeeperSimulator averageGK = new GoalkeeperSimulator("普通门将", 300);
        averageGK.simulateSession(20);
        averageGK.generateStatistics();
        // 测试用例3:水平较低的门将
        System.out.println("\n=== 测试用例3: 一般门将 ===");
        GoalkeeperSimulator beginnerGK = new GoalkeeperSimulator("一般门将", 420);
        beginnerGK.simulateSession(20);
        beginnerGK.generateStatistics();
        // 分析对比不同门将
        System.out.println("\n========== 门将性能对比 ==========");
        compareGoalkeepers();
    }
    // 对比不同门将
    private static void compareGoalkeepers() {
        // 创建3个不同水平的门将进行对比
        GoalkeeperSimulator[] keepers = {
            new GoalkeeperSimulator("门将A(反应180ms)", 180),
            new GoalkeeperSimulator("门将B(反应280ms)", 280),
            new GoalkeeperSimulator("门将C(反应380ms)", 380)
        };
        System.out.println("模拟各1000次射门进行测试...");
        for (GoalkeeperSimulator gk : keepers) {
            long startTime = System.currentTimeMillis();
            gk.simulateSession(100);
            long endTime = System.currentTimeMillis();
            System.out.printf("%s 完成100次模拟,耗时: %dms%n", 
                    gk.getClass().getSimpleName(), endTime - startTime);
        }
    }
}

测试结果示例

运行上述代码后,你可能会看到类似以下结果:

========== 数据分析报告 ==========
门将: 优秀门将
总射门次数: 100
扑救成功次数: 78 (78%)
扑救成功率: 78.0%
反应时间分析:
  平均反应时间: 213ms
  最快反应时间: 152ms
  最慢反应时间: 321ms
  平均总扑救时间: 385ms
各方向表现:
  left      : 15次射门, 12次扑救 (80%)
  right     : 13次射门, 10次扑救 (77%)
  center    : 14次射门, 13次扑救 (93%)
  top-left  : 16次射门, 11次扑救 (69%)
  top-right : 12次射门, 8次扑救  (67%)
  bottom-left: 13次射门, 9次扑救 (69%)
  bottom-right: 17次射门, 15次扑救 (88%)
门将综合评价: 87/100 分
评级: 精英级门将

扩展功能建议

  1. 可视化界面:使用JavaFX或Swing创建图形界面
  2. 数据库存储:保存历史训练数据,追踪进步
  3. 机器学习优化:根据历史数据预测扑救成功率
  4. 对手建模:模拟不同风格的射手
  5. 高级统计:引入更复杂的统计模型(如Bayesian分析)

这个系统提供了完整的评估框架,你可以根据实际需求进行扩展和修改。

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