伪随机和“伪随机”

源于某天晚上玩游戏时的临时起意。

在这里插入图片描述

如图所示,FF14中诗人的1号技能 强力射击 在发动时会有20%的几率触发 直线射击预备 效果,该状态会激活平时处于无法发动状态下的4号技能 直线射击,由此,该职业可以在战斗中造成更多的输出。

在实际的游戏体验中,经常会出现连续触发该技能追加效果或者连续触发不了的情况,也就是极端的欧非情况。如果按照我的游戏常识来看,为了保持游戏的公平性(竞技游戏)和体验度(抽卡游戏),游戏在设计如此类的随机机制时,会引入一个叫做 “伪随机” 的概念。这种机制不会让你特别欧,也不会让你特别非,举用上面的例子,就是你在一场战斗中(发动技能的次数不是很多,也就是说样本空间不够大的时候)触发该技能追加效果的最终概率,应该是非常接近20%的。

在FF14里,虽然没有经过统计,但我对这个20%概率的感觉,更像是一种 “真随机”,因为他和DOTA2中的 “伪随机” 机制的体验(在不够大的样本空间中,实际概率仍然接近期望概率)相差甚远。

由此就有了我当晚的问题:

FF14中的随机机制是 “伪随机” 吗?

要搞清楚这个问题,首先要搞清楚 “伪随机” 的机制原理。

在这里插入图片描述

我从DOTA2 Wiki上找到了关于伪随机机制的解释。如图所示,军团指挥官的三技能 勇气之霎 会让该英雄在遭受攻击时有25%的机率触发一次攻击中附加的吸血效果。经过Wiki的实测,在DOTA2的 “伪随机” 机制下,从第一次开始的效果触发概率如下:

第一次触发概率8.5%
第二次触发概率17%
第三次触发概率25.5%
··· ···
第N次成功触发
第N+1次触发概率 8.5%

也就是说,“伪随机” 机制下,该英雄第一次受到攻击的触发效果是很低的,随后会按照每次8.5%的概率累加。换言之,如果你前面几次都没有触发,那么越往后触发的概率越高。并且一旦成功触发之后,这个概率又会被重置为第一次的低概率。

则在连续N-1次没有触发的情况下,第N次触发概率的计算公式为:

P(N) = p1 + p * N

其中,p1为基础概率,p为每次累加的概率,N为累加次数。

经过Wiki的反复测试后,该技能最终的概率会停留在25%左右(wiki实测是24.9%)。由此可以看出,“伪随机” 机制可以一定程度上保证竞技游戏中的随机机制不会影响到游戏的公平性,所以Shadow的5锤晕3就是真正的天选之人了。因为如果按照传统概率的计算方式,Shadow的5晕锤3的概率约为7‰,而如果按照 “伪随机” 机制来计算的话,则概率约为6‰。但需要注意的是,因为Shadow的5晕锤3是连晕3下,所以只计算了后面4次攻击的触发概率,如果加上第一次暴击的概率,则会远远低于6‰。

所以,如果你在竞技游戏里面欧,那你就是真的欧啊!

但以上内容并不能解释我一开始关于FF14的问题,因为我没有大量的时间去测试FF14的技能概率分布是不是符合前面提到的 “伪随机” 公式(主要是懒),网络上也找不到相关的测试。因此,这个问题依然是一个悬而未决的问题。但有趣的是,我在查询 “伪随机” 机制的时候,发现了另一个同名异意的结论:

在计算机的世界中,所有的随机,都是伪随机。

这让我产生了浓厚的兴趣,于是我又有了新的问题:

计算机中的随机数是如何产生的?

编程时如果需要用到随机数,那么调用一下 rand() 函数就可以了。我会理所应当的认为,这个函数返回的就是一个真正的 “随机数”。但通过查阅资料我了解到,计算机世界中的 “随机” 远比我认为的要复杂。

于是我百度到了一段比较经典的随机数算法代码:

#include <stdlib.h>
static unsigned int RAND_SEED;
unsigned int random(void)
{
    RAND_SEED=(RAND_SEED*123+59)%65536;
    return(RAND_SEED);
}

void random_start(void)
{
    int temp[2];
    movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
    RAND_SEED=temp[0];
}

void main()
{
    unsigned int i,n;
    random_start();
    for(i=0;i<10;i++)
        printf("%u\t",random());
    printf("\n");
}

可以看出,random函数的返回值是通过对RAND_SEED的计算得出的,而RAND_SEED则是movedata函数将内存中0040:006C处的数据传给temp,再传给RAND_SEED。问题到这里就比较清晰了,只要搞清楚0040:006C处的数据是什么就可以了。

0040:006CH:TIMER_LOW DW
0040:006EH:TIMER_HIGH DW

百度给我的答案是,这两个地址处存放着计算机的一个计时器。简单的理解一下就是,TIMER_LOW根据计算机的运行时间累加,满了之后归零,同时让TIMER_HIGH加1。类似于微秒和秒的关系。

由于CPU对进程分配时间片的时间是不固定的,所以random函数获取这个地址处的数据的时间也就不是固定的。这样一来,获取到的数据自然就没有 “规律性” 可言,而计算出来的数据,在人来看来,就是一个看似没什么规律的 “随机数” 。

看到这里我终于恍然大悟,编程不就是依照一套固定的算法把输入变成想要的输出嘛,代码一旦经过编译就是固定不变的,而输入的数据同样也是按照固定方法提取出来的。

由此得出来的结论是:

计算机中的随机数是根据不同的输入种子经过一套特定的算法而计算出来的数值,只要知道算法和种子,那么 “随机数” 就变成了一种可以精准预测的数据。所以,计算机的世界里根本不存在真正的随机,这也是为什么前面游戏部分我的 “伪随机” 带双引号的原因。

虽然没能解决一开始的问题,不过却打开了一个新的话题。按照上面的结论,我只要知道触发的种子和算法,就可以预测 “随机” 结果了。但问题是,种子变多了咋办?经过了解,目前一般的随机算法,回归次数也就2的32次方,花花时间还是可以破解的(谁这么无聊)。但更有意思的是,有两个日本科学家(松本真, 西村拓士)在1997年就开发出了一个叫做Mersenne Twister的随机算法,直接把回归次数变成了2的19937次方(???)。

可以了解的是,只要你的随机种子够复杂,你的随机数就越接近真正的随机,密码学就是这一领域比较深入的学科了。那么我也可以猜测,V社的随机种子获取可能包括了你语音时候的声音信号(?),那么你喊 “爆爆爆” 的时候,没准真的可以增加爆率嗷(玄学)!

那么,如果做到真正的随机呢?知乎告诉我:遇事不决,量子力学。据说是元素的衰变是无法预测的balabala,这就到我的知识盲区了,所以这个问题到这里就结束了。

如有任何问题/疏漏/不严谨之处,欢迎指正/讨论。

参考:DOTA2 Wiki、百度百科

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值