游戏算法专题之PRD算法:听说你想凭运气抽中荣耀水晶?

PRD

PRD算法全称Pseudo-Random Distribution。是概率分布中的一种常见算法,在游戏开发领域中很常用。

PRD用于控制随机事件的触发概率,使其表现得更加符合预期,相比于传统得随机数生成,PRD算法可以平滑得控制随机事件的触发次数,确保不会出现过于极端的情况,比如长时间未触发或者频繁触发。

如果你觉得它离你很远,那么举个栗子,玩“王者荣耀”的多少都知道其中有一个道具叫荣耀水晶,这玩意就是靠抽奖的方式获得的,而根据官方抽奖的方式与概率公布等信息来看,抽取荣耀水晶的算法大概率也是PRD或者它的变种算法。

在游戏中,PRD算法的主要应用场景包括掉落系统、抽奖系统等。这些场景下,开发者通常希望在随机事件的发生上保持某种平衡,而PRD算法正是为了解决这一问题。


基本原理

PRD算法通过调整事件发生的概率来实现分布平滑。简单来说,它会随着事件未触发的次数增加,动态提升触发的概率,直到事件发生。一旦事件触发,概率会重置为初始值,重新开始计算。

PRD的公式通常为:$ P(n) = \frac{1}{k-f(n)}$

其中,P(n) 是事件在第 n 次尝试时的概率,k 是一个常数(通常设为 1),f(n) 是一个随尝试次数递增的函数,用于控制概率的增长。这个公式的作用是保证随着尝试次数的增加,概率不断增大,直至事件发生。


基本实现

下面就以使用PRD算法模拟抽取荣耀水晶的方式带着各位实现一下PRD算法吧!

  • 初始概率与递增概率:使用PRD算法,逐步提高未中奖后的中奖概率。

  • 保底次数:设置一个保底的次数上限,在达到该上限时,无论当前概率如何,玩家都会中奖。

  • 中奖后重置:当玩家中奖后,概率重置为初始值,并重新开始计算。


#include<iostream>
#include<cstdlib>
#include<ctime>
class PRDWithPity
{
private:double initialProb; // 初始中奖概率double increment; // 每次中奖时增加的概率double currentProb; // 当前中奖概率int pityLimit; // 保底次数int currentTry; // 当前抽奖次数public:// 构造函数、初始化初始概率、递增概率和保底次数PRDWithPity (double initProb = 0.05,double inc = 0.02,int pity = 10) :initialProb(initProb),increment(inc),currentProb(initProb),pityLimit(pity),currentTry(0) {}bool draw(){currentTry++;// 达到保底,直接中奖if (currentTry >= pityLimit){reset();return true;}// 生成0-1随机数double randNum = static_cast<double>(rand()) / RAND_MAX;// 如果随机数小于当前概率、表示中奖if (randNum < currentProb){reset();return true;}else{currentProb += increment;return false;}}// reset函数void reset(){currentProb = initialProb;currentTry = 0;}
};

实现代码大致如上,没什么复杂的逻辑,关键地方也都添加了注释,这里就不再赘述了。

下面模拟测试一下看看效果

int main()
{srand(static_cast<unsigned>(time(0)));  // 初始化随机数种子PRDWithPity prd(0.000001, 0.0000002, 360);  // 初始中奖概率0.05,每次未中奖增加0.02,保底次数10次for (int i = 1; i <= 365; ++i) {if (prd.draw()) {std::cout << "恭喜屏幕前这位大佬第 " << i << " 次抽中一颗[荣耀水晶]" << std::endl;} else {std::cout << "第 " << i << " 次抽奖未中奖,幸运值+1,幸运值为: "<< prd.getCurrentTry()<< ",幸运值达到360必中一颗[荣耀水晶]。" << std::endl;}}return 0;
}

由于我们必须保证在触发保底之前中奖的概率足够低,因此这里直接将初始中奖率设置为0.000001也就是十万分之一,每次抽奖后递增中奖率也不能过高,比如可以设置在0.0000002(百万分之一)。这样可以保证在触发保底之前你大概率是不会抽到 荣耀水晶的,只能通过氪金不断的获取抽奖机会,直到抽够360次触发保底。

下面是本次抽奖的模拟结果:

第 1 次抽奖未中奖,幸运值+1,幸运值为: 1,幸运值达到360必中一颗[荣耀水晶]。
第 2 次抽奖未中奖,幸运值+1,幸运值为: 2,幸运值达到360必中一颗[荣耀水晶]。
第 3 次抽奖未中奖,幸运值+1,幸运值为: 3,幸运值达到360必中一颗[荣耀水晶]。
第 4 次抽奖未中奖,幸运值+1,幸运值为: 4,幸运值达到360必中一颗[荣耀水晶]。
第 5 次抽奖未中奖,幸运值+1,幸运值为: 5,幸运值达到360必中一颗[荣耀水晶]。
第 6 次抽奖未中奖,幸运值+1,幸运值为: 6,幸运值达到360必中一颗[荣耀水晶]。
第 7 次抽奖未中奖,幸运值+1,幸运值为: 7,幸运值达到360必中一颗[荣耀水晶]。
第 8 次抽奖未中奖,幸运值+1,幸运值为: 8,幸运值达到360必中一颗[荣耀水晶]。
第 9 次抽奖未中奖,幸运值+1,幸运值为: 9,幸运值达到360必中一颗[荣耀水晶]。
第 10 次抽奖未中奖,幸运值+1,幸运值为: 10,幸运值达到360必中一颗[荣耀水晶]。
第 11 次抽奖未中奖,幸运值+1,幸运值为: 11,幸运值达到360必中一颗[荣耀水晶]。
第 12 次抽奖未中奖,幸运值+1,幸运值为: 12,幸运值达到360必中一颗[荣耀水晶]。
第 13 次抽奖未中奖,幸运值+1,幸运值为: 13,幸运值达到360必中一颗[荣耀水晶]。
第 14 次抽奖未中奖,幸运值+1,幸运值为: 14,幸运值达到360必中一颗[荣耀水晶]。

[次数省略好多行]…

第 348 次抽奖未中奖,幸运值+1,幸运值为: 348,幸运值达到360必中一颗[荣耀水晶]。
第 349 次抽奖未中奖,幸运值+1,幸运值为: 349,幸运值达到360必中一颗[荣耀水晶]。
第 350 次抽奖未中奖,幸运值+1,幸运值为: 350,幸运值达到360必中一颗[荣耀水晶]。
第 351 次抽奖未中奖,幸运值+1,幸运值为: 351,幸运值达到360必中一颗[荣耀水晶]。
第 352 次抽奖未中奖,幸运值+1,幸运值为: 352,幸运值达到360必中一颗[荣耀水晶]。
第 353 次抽奖未中奖,幸运值+1,幸运值为: 353,幸运值达到360必中一颗[荣耀水晶]。
第 354 次抽奖未中奖,幸运值+1,幸运值为: 354,幸运值达到360必中一颗[荣耀水晶]。
第 355 次抽奖未中奖,幸运值+1,幸运值为: 355,幸运值达到360必中一颗[荣耀水晶]。
第 356 次抽奖未中奖,幸运值+1,幸运值为: 356,幸运值达到360必中一颗[荣耀水晶]。
第 357 次抽奖未中奖,幸运值+1,幸运值为: 357,幸运值达到360必中一颗[荣耀水晶]。
第 358 次抽奖未中奖,幸运值+1,幸运值为: 358,幸运值达到360必中一颗[荣耀水晶]。
第 359 次抽奖未中奖,幸运值+1,幸运值为: 359,幸运值达到360必中一颗[荣耀水晶]。
恭喜屏幕前这位大佬第 360 次抽中一颗[荣耀水晶]
第 361 次抽奖未中奖,幸运值+1,幸运值为: 1,幸运值达到360必中一颗[荣耀水晶]。
第 362 次抽奖未中奖,幸运值+1,幸运值为: 2,幸运值达到360必中一颗[荣耀水晶]。
第 363 次抽奖未中奖,幸运值+1,幸运值为: 3,幸运值达到360必中一颗[荣耀水晶]。
第 364 次抽奖未中奖,幸运值+1,幸运值为: 4,幸运值达到360必中一颗[荣耀水晶]。
第 365 次抽奖未中奖,幸运值+1,幸运值为: 5,幸运值达到360必中一颗[荣耀水晶]。


PRD的优点

平衡性PRD通过调整概率,使得随机事件更加平衡。例如,在掉落系统中,PRD确保物品不会长时间不掉落,也不会短时间内频繁掉落。

易于控制:开发者可以通过调节初始概率或递增函数的参数,来控制事件的发生频率和分布特性。

提升用户体验PRD可以防止用户在面对纯粹的随机系统时感到挫败,尤其是游戏中的奖励机制,通过PRD可以避免极端运气差的情况。

当然了,算法并非一成不变的,具体实现还得基于我们在开发业务中的具体需求来决定是否对原算法进行扩展、优化、变种。

比如下面这些扩展建议:

  1. 递增机制:可以根据具体需求将递增值设计为动态调整,而不仅仅是固定值。
  2. 外部配置:如果PRD用于实际的游戏开发中,概率和递增值通常从外部配置表中读取,而不是硬编码在程序中。

小结

如果你不从事游戏开发相关领域工作,那么这篇文章可以帮你了解身边游戏抽奖的中奖机制和原理,在面对华丽的游戏虚拟道具抽奖时,请务必保持理性消费(有钱人忽略,因为本质就是来圈你们这些所谓有钱人的RMB滴!)代码面前,不要对自己的运气抱有过高的自信!

如果你是一个即将或者是正在从事游戏开发工作,那么学无止境,共勉!

这是一个连载的专题,欢迎持续关注哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/141411.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

计算机毕业设计 二手闲置交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

什么是快充协议,最常见的快充协议有哪些

什么是快充协议 随着手机快充的出现大家都知道快充技术但很多人确不知道快充协议&#xff0c;在快充技术里快充协议是必不可少的&#xff0c;那么今天我们就来探讨一下什么是快充协议&#xff1f; 快充协议是一种通过提高充电效率来缩短设备充电时间的电池充电技术。它通过在充…

主播和礼品检测系统源码分享

主播和礼品检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

约瑟夫环和一元多项式修正版

这里先附上上一篇博文的链接大家可以对比着看&#xff0c;错误已经改正https://blog.csdn.net/2302_78946488/article/details/141751514?spm1001.2014.3001.5501 约瑟夫环 以下是详细代码 //约瑟夫环 #include<stdio.h> #include<stdlib.h> //建立链表结点 str…

【Unity】 HTFramework框架(五十六)MarkdownText:支持运行时解析并显示Markdown文本

更新日期&#xff1a;2024年9月15日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 MarkdownText支持的Markdown语法标题强调文本表格嵌入图像超链接 使用MarkdownText设置项运行时属性解析使用ID模式嵌入图像 MarkdownText MarkdownText…

句子成分——每日一划(八)

目录 一、原句 二、第一部分 三、第二部分 一、原句 In class society everyone lives as a member of a particular class, and every kind of thinking, without exception, is stamped with the brand of a class. 来源&#xff1a;二、阶级和阶级斗争 二、第一部分 In…

QT添加图标标题和打包项目

QT项目打包 项目的标题和图标标题项目图标exe图标 可执行文件——生成exeexe运行报错“找不到qt6gui.dll”等 相关库文件——生成zip安装包打包程序——生成exe安装包 项目的标题和图标 项目打包要好看点&#xff0c;得有个好点的标题和图标&#xff0c;这次打包的项目是我上一…

图论篇--代码随想录算法训练营第五十八天打卡|拓扑排序,dijkstra(朴素版),dijkstra(堆优化版)精讲

拓扑排序 题目链接&#xff1a;117. 软件构建 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依赖于文件 B&#xff0…

【移动端】菜单的自动展开与收回

前言 为了满足手机上菜单栏随用户移动&#xff0c;菜单的自动展示与隐藏&#xff0c;特此记录 基本原理 实现逻辑 window.addEventListener(‘scroll’, debouncedScrollHandler) – 监听文档视图滚动事件 document.querySelector(‘.header’) – 选择器匹配元素 创建show和h…

中断门+陷阱门

中断门&#xff1a; 中断描述符在IDT表里面 kd> dq idtr 80b95400 83e48e000008bfc0 83e48e000008c150 80b95410 0000850000580000 83e4ee000008c5c0 80b95420 83e4ee000008c748 83e48e000008c8a8 80b95430 83e48e000008ca1c 83e48e000008d018 80b95440 000085000050…

Tuxera NTFS for Mac 2023绿色版

​ 在数字化时代&#xff0c;数据的存储和传输变得至关重要。Mac用户经常需要在Windows NTFS格式的移动硬盘上进行读写操作&#xff0c;然而&#xff0c;由于MacOS系统默认不支持NTFS的写操作&#xff0c;这就需要我们寻找一款高效的读写软件。Tuxera NTFS for Mac 2023便是其中…

Redis入门2

在java中操作Redis Redis的Java客户端 Redis 的 Java 客户端很多&#xff0c;常用的几种: Jedis Lettuce Spring Data Redis Spring Data Redis 是 Spring 的一部分&#xff0c;对 Redis 底层开发包进行了高度封装。 在 Spring 项目中&#xff0c;可以使用Spring Data R…

DTU远程控制:空巢老人的智慧灌溉方案

我是老刘&#xff0c;大家经常这样唤我。在浙江省台州市下面的一个小乡村里&#xff0c;我经营着一家工厂。 说起台州&#xff0c;是个好地方&#xff0c;这里有一座天台山&#xff0c;就是“一座天台山&#xff0c;半步全唐诗”的那座山&#xff0c;山里有一个大瀑布&#xf…

计算机毕业设计 乡村生活垃圾管理系统的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

STM32(十四):USART串口数据包

HEX数据包 0xFF包头&#xff0c;0xFE包尾。 如果数据和包头包尾重复&#xff0c;可能会引起误判。 解决办法&#xff1a; 1. 限制载荷数据的范围 2. 如果无法避免载荷数据和包头包尾重复&#xff0c;就使用尽量使用固定长度数据包。 包头 ‘\r\n 包尾 在载荷数据中间可以出现…

用nginx-rtmp-win32-master及ffmpeg模拟rtmp视频流

效果 使用nginx-rtmp-win32-master搭建RTMP服务 双击exe就可以了。切记整个目录不能有中文 README.md ,启用后本地的RTM路径: rtmp://192.168.1.186/live/xxx ffmpeg将地本地视频推RMTP F:\rtsp\ffmpeg-7.0.2-essentials_build\bin>ffmpeg -re -i F:\rtsp\123.mp4 -c c…

分贝转换 1 mVpp = 9.03dBmV

分贝转换 1 mVpp 9.03dBmV 函数发生器调节如下参数在频谱仪器上能看到9.03dBmv的电压值函数发生器产生 30mVpp 频谱仪会显示多少dBmV 函数发生器调节如下参数 输出频率&#xff1a;10 MHz 波形类型&#xff1a;正弦波 阻抗&#xff1a;50 Ω 幅度&#xff1a;1 mVpp …

CTF-杂项隐藏在数据包中的秘密lol

题目 隐藏在数据包中的秘密 解题 首先分析一下题目&#xff0c;题目给出的是一个流量包&#xff0c;大致浏览一遍是HTTP上网请求流量&#xff0c;直接过滤出http流量包 可以看到&#xff0c;第一个包是用户通过访问网页&#xff0c;然后post提交上传一个文件&#xff0c;下一…

黑马程序员Java笔记整理(day01)

1.windowsR进入运行&#xff0c;输入cmd 2.环境变量 3.编写java第一步 4.使用idea 5.注释 6.字面量 7.变量 8.二进制 9.数据类型 10.关键词与标识符

echarts中tooptips提示框超出了怎么解决

我们在制作echarts表格时&#xff0c;有时候会遇到提示框内容较多&#xff0c;会让提示框超出&#xff0c;展示不全数据&#xff0c;如下&#xff1a; 这种情况下需要在tooltips下增加一些属性&#xff1a; 1.confine: true&#xff1a;这个配置的作用是让提示框&#xff08;t…