因为单纯的随机确实会影响到竞技性,所以dota2引入的是伪随机机制,在大量的技能中,比如说混沌的混乱之箭、剑圣的剑舞、冰女的冰霜领域之类的技能,都利用了伪随机机制。
而纯随机,或者标准正态分布并不会因为之前的结果影响此次技能的效果,因为他们的每次计算是互相独立的。
所以,从魔兽争霸3继承来的PRD(Pseudo Random Distribution)机制就被引入啦,具体的实现原理是这样的,每次的运行,都使用一个不断增加的概率来进行计算,如果这个事件一直触发不成功,那么概率就不断上升,直到事件发生为止。
要完成这个算法,要解决的问题就是,对于一个发生概率为p的事件,在我们第N次调用的时候,我们使用的概率是P(N) = c * N,P(1)显然要是一个小于p的数值,所以要解决的就是c这个数值,如何让整体的概率尽量接近于p。
这里要引入的是马尔可夫链公式,马尔可夫链的定义在这里可以看到。
简单来说,马尔可夫链就是描述了一种此次事件会受到之前N个状态的影响。具体的公式可以去百度百科看到。
回到dota2,比如我们对于一个触发概率为5%的暴击,那么第一次出现暴击的概率是c,第二次是2c,如果一直不发生,直到第N次,出现了(c*N)大于1了,那么这次暴击就必然发生了,而在中间的每一次,如果暴击发生了,那么我们就把随机概率重置为c。
因此,总体期望的计算公式就是

P = 1*c + 2*c(1-c) + 3*c(1-c)(1-2c)+....

其中P = 1/p,N=1/c(第N次必然发生),那么我们可以用2分法在(0,1)之间不断估算c,直到这个公式成立就行了。
具体的算法实现:

local function p_from_c(c)
-- 模拟N次随机,计算是否会在N次随机之后必然发生
local po, pb = 0, 0
local sumN = 0
local maxTries = math.ceil(1/c) -- P = 1*c + 2*c(1-c) + 3*c(1-c)(1-2c)+....
for n = 1, maxTries do
po = math.min(1, c*n) * (1-pb)
pb = pb + po
sumN = sumN + n * po
end return (1 / sumN)
end function c_from_p(p)
local cu = p
local cl = 0.0
local cm
local p1, p2 = 0, 1
while true do
cm = (cu + cl) / 2
p1 = p_from_c(cm)
if math.abs(p1 - p2) <= 0.000000001 then -- 如果发生的概率足够小,那么认为已经找到了对应的c
break
end if p1>p then cu = cm else cl = cm end
p2 = p1
end
return cm
end

具体的使用上,我们需要在技能里面用个变量来储存连续失败的次数,之后随机的时候再使用伪随机数来计算发生的概率。

function my_ability:OnSpellStart()
if self.nFails == nil then self.nFails = 1 end
local c = c_from_p(0.20)
local success = RollPercentage(c*100*self.nFails)
if success then
-- 执行具体的操作
self.nFails = 1
else
self.nFails = self.nFails + 1
end
end

这个算法可能出现的问题:

  1. 在大概率事件的时候,不建议使用这个算法,因为如果一个70%的事件以57%的概率进行第一次计算的话,会出现很大的误差,基本上就是第一次57%,第二次100%。
  2. 如果事件出现的数量很少的话,比如说10%的事件整个游戏过程只会出现个三四次的话,那么就纯随机就好了。

当然,最适合的算法就是各种抽奖算法啦,能够稍微保护一下非酋的体验。
之前炉石不是有个更新说,新手的30包必定出橙嘛,就暴露了一个事实,无良暴雪一开始的开包就是纯随机的,有了这个更新才变成的伪随机,难怪我一直玩的是炉石稀有。

作者:XavierCHN
链接:https://www.jianshu.com/p/f9a1646a8f19
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

【转】 DOTA2中的伪随机及其lua实现的更多相关文章

  1. 众妙之门玄之又玄,游戏系统中的伪随机(Pseudo-Randomization)和真随机(True-Randomization)算法实现Python3

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_212 有人说,如果一个人相信运气,那么他一定参透了人生.想象一下,如果你在某款moba游戏中,在装备平平,队友天坑的情况下,却刀刀 ...

  2. 游戏开发中伪随机正态分布JavaScript

    在游戏开发中经常遇到随机奖励的情况,一般会采取先生成数组,再一个一个取的方式发随机奖励. 下面是js测试正态分布代码: <!DOCTYPE html> <html lang=&quo ...

  3. 高端黑链SEO—恶意JS脚本注入访问伪随机域名

    摘要:我们的服务器又出入侵事故了.有客户的 html 网页底部被插入了一段 js 脚本,导致访客打开网页时被杀毒软件警告网站上有恶意代码.在黑链 SEO 中这是常见的手法,但奇特的地方就在于我们这次捕 ...

  4. java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...

  5. 深入解析PHP中的(伪)多线程与多进程

    本篇文章是对PHP中的(伪)多线程与多进程进行了详细的分析介绍,需要的朋友参考下 (伪)多线程:借助外力利用WEB服务器本身的多线程来处理,从WEB服务器多次调用我们需要实现多线程的程序.QUOTE: ...

  6. CSS和CSS3中的伪元素和伪类(总结)

    好多人伪类和伪元素分清楚,其实就是一句话,“伪类的效果可以通过添加一个实际的类来达到,而伪元素的效果则需要通过添加一个实际的元素才能达到”. CSS中伪类包括: :first-child :lang ...

  7. 浅析SQL Server数据库中的伪列以及伪列的含义

    SQL Server中的伪列 下午看QQ群有人在讨论(非聚集)索引的存储,说,对于聚集索引表,非聚集索引存储的是索引键值+聚集索引键值:对于非聚集索引表,索引存储的是索引键值+RowId,这应该是一个 ...

  8. js中的伪数组

    一, 伪数组 1. 具有length属性 2. 按索引方式存储数据 3. 不具有数组的方法, 比如push(),pop()等 二, 生成伪数组的方法 在js中生成伪数组的方法比较多 1. functi ...

  9. 如何在Python中从零开始实现随机森林

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 决策树可能会受到高度变异的影响,使得结果对所使用的特定测试数据而言变得脆弱. 根据您的测试数据样本构建多个模型(称为套袋)可以减少这种差异,但是 ...

随机推荐

  1. android 网络广播 类似QQ动态检查网络

    private ConnectivityManager mConnectivityManager; private NetworkInfo netInfo; 在onCreate 注册广播 Intent ...

  2. Jmeter(三十八)Jmeter Question 之 ‘批量执行SQL语句’

    知识使我们变得玩世不恭,智慧使我们变得冷酷无情,我们思考的太多,感知太少,除了机器,我们更需要人性,除了智慧,我们需要仁慈和善良. ------出自查理卓别林的演讲 前面有提到Jmeter使用JDBC ...

  3. 数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下

    数据迁移_把RAC环境备份的数据,恢复到另一台单机Oracle本地文件系统下 作者:Eric 微信:loveoracle11g 1.创建pfile文件 # su - ora11g # cd $ORAC ...

  4. Linux下安装python3及相关包

    Python3: sudo apt-get install python3 终端中输入python则进入python2,输入python3则进入python3 安装python2的相关包: sudo ...

  5. U3D学习10——关节和射线检测

    1.弹簧  2.铰链  3.固定关节  4.角色关节  5.自定义关节  6.raycast和raycasthit 射线有位移参数,可以设定只触发某一层的. 7.射线检测用于高速和精确 update是 ...

  6. WebBrowser JS回调delphi的方法 (简单通用)

    上一部分讲了Delphi根据方法名调用方法,这一部分还有用到,接着上一章: [主要原理] 通过TEmbeddedWB控件的OnShowMessage事件捕获弹窗来实现,弹窗时定义方法名和参数,在捕获方 ...

  7. mysql的DATE_FORMAT参数格式

    mysql有个字段是DATETIME类型,要实现可以按月统计,该怎么写sql语句?select month(f1) from tt group by month(f1)or select DATE_F ...

  8. web端文字转语音的几种方案

    最近在开发一个微信排队取号的的系统,其中对于服务员端(管理端) 需要有呼叫功能,即点按钮 就播出"xxx号顾客请就座"的声音. 经过在网上一番搜索研究,web端实现指定文字的语音播 ...

  9. hadoop分布式集群的搭建

    电脑如果是8G内存或者以下建议搭建3节点集群,如果是搭建5节点集群就要增加内存条了.当然实际开发中不会用虚拟机做,一些小公司刚刚起步的时候会采用云服务,因为开始数据量不大. 但随着数据量的增大才会考虑 ...

  10. KVM总结-KVM性能优化之网络性能优化

    前面已经介绍了KVM CPU优化(http://blog.csdn.net/dylloveyou/article/details/71169463).内存优化(http://blog.csdn.net ...