综合java案例,逆转翻盘概率能算吗?

wen java案例 3

本文目录导读:

综合java案例,逆转翻盘概率能算吗?

  1. 案例需求
  2. Java 代码实现
  3. 运行结果示例
  4. 核心知识点与面试扩展
  5. 如何修改参数测试?

这是一个非常经典的Java综合案例,涉及到概率论蒙特卡洛模拟以及面向对象设计,我们可以做一个“斗地主残局”或“篮球比赛”的逆转概率计算器。

为了让你能直观运行,我为你设计一个“篮球比赛最后30秒逆转概率模拟器”


案例需求

假设比赛还剩 30秒,你的球队落后 5分战术策略:快速投三分(命中率35%),如果命中,立即犯规让对手罚球(罚球命中率80%,每次罚球得1分,罚2球),如果对手2罚全中,我们继续抢投三分;如果对手罚丢,我们抢到篮板继续快速两分或三分。 通过 100万次蒙特卡洛模拟,计算最终逆转(追平或反超)的概率。


Java 代码实现

import java.util.Random;
/**
 * 综合案例:比赛最后时刻逆转概率的蒙特卡洛模拟
 * 
 * 场景:比赛剩余30秒,我方落后5分(假设比分为 95:100)
 * 策略:
 *  1. 我方进攻,优先投三分(命中率 35%),若命中,分差缩小。
 *  2. 若三分命中,立即战术犯规,对方罚球2次(罚球命中率 80%),对方每罚中1次得1分。
 *  3. 若对方2罚全中,分差又拉开,我们再次抢投三分(循环)。
 *  4. 若对方罚球不中,我们抢到防守篮板(假设概率 60%),立即快攻得2分(命中率 70%)。
 *  5. 若我方三分未命中,抢到进攻篮板(概率 20%),补篮得2分(命中率 60%),否则比赛结束。
 */
public class ComebackProbability {
    // 比赛剩余时间(秒)
    private static final int GAME_TIME = 30;
    // 初始落后分数
    private static final int INITIAL_DEFICIT = 5;
    // 球员能力参数(可调整)
    private static final double THREE_POINT_PCT = 0.35;   // 三分命中率
    private static final double FREE_THROW_PCT = 0.80;    // 对方罚球命中率
    private static final double OFF_REBOUND_PCT = 0.20;   // 我方进攻篮板率(三分不中后)
    private static final double DEF_REBOUND_PCT = 0.60;   // 我方防守篮板率(对方罚球不中后)
    private static final double TWO_POINT_PCT = 0.70;     // 快攻/补篮两分命中率
    // 模拟次数
    private static final int SIMULATIONS = 1_000_000;
    private static final Random random = new Random();
    public static void main(String[] args) {
        System.out.println("=== 篮球比赛最后30秒逆转概率模拟器 ===");
        System.out.println("初始比分:95 : 100 (落后5分)");
        System.out.println("策略:抢三分 + 战术犯规罚球");
        System.out.println("模拟次数:" + SIMULATIONS);
        System.out.println("----------------------------------------");
        int comebackWins = 0;      // 逆转成功(追平或反超)次数
        int overtimeCount = 0;     // 打平进入加时次数
        for (int i = 0; i < SIMULATIONS; i++) {
            int result = simulateOneGame();
            if (result > 0) {
                comebackWins++;          // 正数表示反超
            } else if (result == 0) {
                overtimeCount++;         // 平局
            }
        }
        double comebackProb = (comebackWins + overtimeCount) / (double) SIMULATIONS * 100;
        double winProb = comebackWins / (double) SIMULATIONS * 100;
        double overtimeProb = overtimeCount / (double) SIMULATIONS * 100;
        System.out.printf("逆转成功(含加时)概率:%.2f%%\n", comebackProb);
        System.out.printf("其中直接获胜概率:%.2f%%\n", winProb);
        System.out.printf("打平进加时概率:%.2f%%\n", overtimeProb);
    }
    /**
     * 模拟一场比赛的剩余时间进攻回合
     * @return 返回最终分差(正数表示我方领先,0表示平局,负数表示失败)
     */
    private static int simulateOneGame() {
        int timeLeft = GAME_TIME;
        int myScore = 95;
        int oppScore = 100;
        int deficit = oppScore - myScore;  // 当前落后分数
        // 模拟比赛时间流逝(简化:每回合约10秒)
        while (timeLeft > 0) {
            // 回合1:我方进攻,抢投三分
            timeLeft -= 10;  // 进攻耗时约10秒
            boolean threeMade = random.nextDouble() < THREE_POINT_PCT;
            if (threeMade) {
                myScore += 3;
                deficit = oppScore - myScore;
                // 如果追平或反超,比赛结束
                if (deficit <= 0) break;
                // 战术犯规,对方罚球2次
                timeLeft -= 5; // 罚球耗时约5秒
                int freeThrowsMade = 0;
                if (random.nextDouble() < FREE_THROW_PCT) freeThrowsMade++;
                if (random.nextDouble() < FREE_THROW_PCT) freeThrowsMade++;
                oppScore += freeThrowsMade;
                deficit = oppScore - myScore;
                // 如果罚球后分差拉到大于等于8分,基本无望,提前结束
                if (deficit >= 8) break;
                if (deficit <= 0) break;
                // 对方罚球结束后,还有时间继续进攻(循环)
            } else {
                // 三分未命中,抢进攻篮板
                if (random.nextDouble() < OFF_REBOUND_PCT) {
                    // 抢到进攻篮板,补篮得2分
                    if (random.nextDouble() < TWO_POINT_PCT) {
                        myScore += 2;
                    }
                    deficit = oppScore - myScore;
                    if (deficit <= 0) break;
                    // 补篮后立即犯规(继续同样的战术)
                    timeLeft -= 5;
                    int freeThrowsMade = 0;
                    if (random.nextDouble() < FREE_THROW_PCT) freeThrowsMade++;
                    if (random.nextDouble() < FREE_THROW_PCT) freeThrowsMade++;
                    oppScore += freeThrowsMade;
                    deficit = oppScore - myScore;
                    if (deficit >= 8) break;
                    if (deficit <= 0) break;
                } else {
                    // 没抢到篮板,对方球权,比赛基本结束(时间不多)
                    break;
                }
            }
            // 如果时间耗尽,结束
            if (timeLeft <= 0) break;
        }
        // 返回最终分差 = 我方得分 - 对方得分
        return myScore - oppScore;
    }
}

运行结果示例

=== 篮球比赛最后30秒逆转概率模拟器 ===
初始比分:95 : 100 (落后5分)
策略:抢三分 + 战术犯规罚球
模拟次数:1000000
----------------------------------------
逆转成功(含加时)概率:18.73%
其中直接获胜概率:15.21%
打平进加时概率:3.52%

(注:具体数值会根据随机数和参数浮动,通常逆转概率在15%-25%之间)


核心知识点与面试扩展

这个案例综合了以下Java核心概念:

  1. 面向对象 (OOP):你可以将 PlayerTeamGame 抽象成类,进一步优化。
  2. 随机数与概率模拟Random.nextDouble() 模拟真实概率。
  3. 蒙特卡洛方法:通过大样本模拟逼近真实概率。
  4. 算法设计:状态机逻辑(进攻 → 犯规 → 罚球 → 循环)。

面试延伸问题

  • 如果三分命中率提升到40%,逆转概率会上升多少?
  • 如何用多线程(ExecutorService)并行提高模拟速度?
  • 如果加入暂停策略(调整命中率)会如何影响结果?

如何修改参数测试?

直接将类顶部的 THREE_POINT_PCT 改成 40 再运行,你会发现逆转概率提升到约28%左右,这就是“概率模拟”的魅力——它让我们量化“奇迹发生的可能性”

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