当前位置: 首页 > news >正文

十倍烈火刀刀爆?伪随机分布(PRD)算法详解与C++实现

用亚索暴击举个栗子🌰

假设亚索面板暴击率 20%,但系统用的 PRD 算法:

  1. 第一刀:实际暴击率只有7.6%(≈1/13概率)
    → 你Q小兵没暴击:“辣鸡机制!”

  2. 继续砍:每刀失败后概率自动上涨

    • 第二刀:15.3%
    • 第三刀:22.9%
    • ...
      → 连砍5刀不暴击时,第六刀概率46%
      “对面亚索怎么刀刀暴击???”
  3. 一旦暴击:概率立刻重置回7.6%
    → 刚暴击完的亚索:“这英雄没暴击玩个锤子?”


最终效果
➤ 实际暴击率还是20%左右
➤ 不会出现「连砍10刀不暴击」的非洲时刻
➤ 也很难「3刀2暴击」变成欧皇
➤ 让暴击手感更接近“偶尔小惊喜,不会太离谱”


亚索100%暴击效果:

  • 普攻刀刀暴击,Q技能「斩钢闪」必定暴击
  • 配合无尽之刃,暴击伤害从180% → 210%(亚索被动减伤后)
  • 对面ADC看到你:"这亚索怎么Q比我的普攻还疼?" 😱

经典老版本回忆:

以前出 「斯塔缇克电刃+幻影之舞」 两件直接100%,现在这两件暴击率都被削了,老玩家落泪 😭

一、伪随机分布算法原理

1.1 真随机与伪随机的区别

在计算机科学中,真随机数生成依赖物理熵源(如热噪声),而伪随机数通过算法生成看似随机的数列。伪随机分布(Pseudo-Random Distribution, PRD)是一种特殊的概率控制算法,广泛用于游戏开发领域。

1.2 PRD算法的核心机制

PRD算法通过动态调整事件触发概率,解决传统均匀分布随机算法的极端分布问题(如连续暴击或长时间不暴击)。其核心公式为:

P(N)=C⋅N

其中:

  • N‌ 表示连续未触发事件的次数(初始为1,触发后重置)
  • C‌ 为概率增量系数,需通过数学方法计算得出
  • P(N)‌ 为第N次尝试时的实际触发概率

当事件触发时,N重置为1;否则N递增,直至触发概率达到100%‌。

1.3 概率增量系数C的计算

C的计算目标是使实际概率均值逼近期望概率(例如25%暴击率)。通过以下步骤迭代求解:

  1. 数学期望公式‌:
    E=∑i=1∞P(i)⋅∏j=1i−1(1−P(j))E=∑i=1∞​P(i)⋅∏j=1i−1​(1−P(j))
  2. 二分逼近法‌:
    在区间(0, 1)内通过二分法迭代计算C,直至满足 |E - 目标概率| < ε(如ε=1e-6)‌

二、C++实现

2.1、完整示例代码

#include <iostream>
#include <cmath>
#include <iomanip>
#include <limits>
#include <utility>

// 根据 C 值估算实际暴击率
double estimateCriticalChanceByC(double c)
{
    const int max_iterations = 1000000; // 防止无限循环
    if (c <= 0.0)
        return 0.0;

    double survival_prob = 1.0; // 存活概率(未暴击的概率)
    double e_pn = 0.0;          // 期望攻击次数的倒数即暴击率

    for (int k = 1; k <= max_iterations; ++k)
    {
        const double kc = k * c;
        const double current_prob = survival_prob * kc;

        e_pn += k * current_prob;
        survival_prob *= (1.0 - kc);

        // 提前终止条件:存活概率趋近于0或精度足够
        if (survival_prob < 1e-12)
            break;
    }

    return (e_pn > 0) ? 1.0 / e_pn : 0.0;
}

// 二分查找法计算最佳 C 值
std::pair<double, double> calculateCByBinarySearch(double target_chance)
{
    const double epsilon = 1e-9;    // 精度阈值
    const int max_iterations = 100; // 最大迭代次数

    double left = 0.0;
    double right = 1.0; // 扩展搜索范围到 [0,1]
    double best_c = 0.0;
    double best_estimate = 0.0;

    for (int iter = 0; iter < max_iterations; ++iter)
    {
        const double mid = (left + right) / 2.0;
        const double estimate = estimateCriticalChanceByC(mid);

        // 记录最接近目标的解
        if (std::fabs(estimate - target_chance) <
            std::fabs(best_estimate - target_chance))
        {
            best_c = mid;
            best_estimate = estimate;
        }

        // 终止条件:达到精度或范围足够小
        if (std::fabs(estimate - target_chance) < epsilon ||
            (right - left) < epsilon)
        {
            break;
        }

        // 调整搜索区间
        if (estimate > target_chance)
        {
            right = mid;
        }
        else
        {
            left = mid;
        }
    }

    return {best_c, best_estimate};
}

void testPrd(double target)
{

    const auto [c, actual] = calculateCByBinarySearch(target);

    std::cout << std::fixed << std::setprecision(10);
    std::cout << "目标暴击率: " << target * 100 << "%\n"
              << "计算 C 值: " << c << "\n"
              << "实际暴击率: " << actual * 100 << "%\n"
              << "-------------------------------\n";
}

int main()
{
    testPrd(0.05);
    testPrd(0.25);
    testPrd(0.50);
    testPrd(0.75);
    return 0;
}

编译运行,

g++ -std=c++17 prd.cc -o prd

 输出结果,

目标暴击率: 5.0000000000%
计算 C 值: 0.0038016583
实际暴击率: 4.9999999869%
-------------------------------
目标暴击率: 25.0000000000%
计算 C 值: 0.0847443668
实际暴击率: 25.0000000418%
-------------------------------
目标暴击率: 50.0000000000%
计算 C 值: 0.3072131593
实际暴击率: 50.0000000805%
-------------------------------
目标暴击率: 75.0000000000%
计算 C 值: 0.8643567767
实际暴击率: 74.9999999742%

2.2、算法步骤解析

1. 暴击率估算函数(estimateCriticalChanceByC)

输入‌:参数C(控制暴击概率增长的系数)

输出‌:实际暴击率的估算值

核心逻辑‌:

  • Step1、初始化存活概率survival_prob(未暴击的累积概率)和期望攻击次数倒数e_pn‌。
  • Step2、遍历攻击次数k(从1到max_iterations):
  1. 计算当前攻击暴击的概率:current_prob = survival_prob * k * C
  2. 累加期望攻击次数的倒数:e_pn += k * current_prob
  3. 更新存活概率:survival_prob *= (1 - k * C)
  4. 若存活概率小于阈值(1e-12),提前终止循环‌。
  • Step3、返回实际暴击率:1.0 / e_pn(期望攻击次数的倒数)。

2. 二分查找法求C值(calculateCByBinarySearch)

输入‌:目标暴击率target_chance

输出‌:最佳C值及对应的实际暴击率

核心逻辑‌:

  • Step1、初始化搜索区间[left, right] = [0.0, 1.0],记录最优解的变量best_cbest_estimate‌。
  • Step2、进行最多max_iterations次二分查找:
  1. 计算中点mid,调用estimateCriticalChanceByC得到估算暴击率。
  2. 更新最优解记录。
  3. 根据估算值与目标的差距调整搜索区间:
    • 若估算值大于目标,缩小右边界。
    • 否则缩小左边界。
  4. 达到精度阈值(epsilon=1e-9)或区间足够小时终止。
  • Step3、返回最优C值和实际暴击率。

3. 测试函数(testPrd)

调用二分查找函数,格式化输出目标暴击率、计算得到的C值和实际暴击率,保留10位小数‌。

2.3、时间复杂度分析

1. 暴击率估算函数

  • 时间复杂度‌:O(max_iterations),即O(1e6)
    • 循环最多执行1e6次,每次循环包含常数时间操作。
    • 实际运行次数由survival_prob衰减速度决定(通常远小于1e6)。

2. 二分查找法

  • 时间复杂度‌:O(max_iterations * T_estimate),其中T_estimate为单次估算的时间复杂度。
    • 二分查找最多迭代100次‌。
    • 每次迭代调用estimateCriticalChanceByC,总复杂度为O(100 * 1e6) = O(1e8)

3. 整体复杂度

  • 测试4个目标值时,总复杂度为4 * O(1e8) = O(4e8),属于可接受的离线计算范围。

2.4、关键设计点

  1. 提前终止优化‌:在暴击率估算中,当存活概率趋近于0时提前终止循环,减少无效计算‌。
  2. 精度控制‌:二分查找的终止条件结合了目标精度(epsilon=1e-9)和搜索区间大小,确保结果稳定性‌。
  3. 数值稳定性‌:使用std::fixedstd::setprecision保证输出精度,避免浮点误差‌。

三、应用场景与优势

特性传统均匀随机PRD算法
极端事件概率较高显著降低
玩家体验不可控可预测且平滑
实现复杂度需数学计算C值

典型应用案例‌:

  1. MOBA游戏暴击机制(如DOTA2)
  2. 抽卡保底系统设计
  3. 玩家技能触发判定‌

四、PRD算法数学优化

针对当前迭代算法进行数值优化:

  • 采用牛顿迭代法替代二分查找,提升收敛速度(迭代次数可降至20次以内)‌
  • 引入动态步长调整机制,当|estimate-target| < 1e-5时切换为精细搜索‌

相关文章:

  • 洛谷P1091
  • 记录排查服务器CPU负载过高
  • 【自学笔记】OpenStack基础知识点总览-持续更新
  • nvidia驱动升级-ubuntu 1804
  • 系统架构设计师—数据库基础篇—关系代数运算
  • FreeRTOS 任务管理与运行时间统计:API 解析与配置实践
  • SQLAlchemy系列教程:集成Pydantic增强数据处理能力
  • 7.自然语言处理(NLP)理论基础——大模型微调的基石
  • 【蓝桥杯集训·每日一题2025】 AcWing 5539. 牛奶交换 python
  • C语言番外篇(4)------------------>VS环境下源码的隐藏
  • Dify部署踩坑指南(Windows+Mac)
  • Spring Boot 项目中 Redis 常见问题及解决方案
  • 常见的限流算法有哪些?
  • 社区智慧养老标准规范全解析
  • Java停车平台高并发抢锁技术方案设计 - 慧停宝开源停车管理平台
  • C语言番外篇(5)-------------->作用域与生命周期
  • 基于ANTLR4的大数据SQL编辑器解析引擎实践|得物技术
  • aws(学习笔记第三十一课) aws cdk深入学习(batch-arm64-instance-type)
  • 贪心算法一
  • python实现的生态模拟系统
  • 《让世界爱中国》新书发布,探讨大变局下对外讲好中国故事
  • 中国首次当选联合国教科文组织1970年《公约》缔约国大会主席国
  • 夜读丨为萤火虫哭泣的夜晚
  • 申伟强任上海申通地铁集团有限公司副总裁
  • 第1现场|俄媒称乌克兰网上出售北约对乌军培训手册
  • 三星“七天机”质保期内屏幕漏液被拒保,澎湃介入后已解决