导航菜单
首页 >  牛客网app都是游戏策划的真题吗知乎  > 在游戏中的随机过程中经常会加入伪随机的设计。请阐述(或举例)

在游戏中的随机过程中经常会加入伪随机的设计。请阐述(或举例)

写这篇随笔的动机,在于最近看了不少对于游戏中概率事件的提问

在这些相关讨论里,总是能频繁看到“真随机”和“伪随机”这两个词汇。

其中最常见的句子则莫过于宝典一般的——“程序里没有真随机”。

这句话本身当然是没有问题的。 但是大多数时候,用这句话去回复别人的疑问就有点风马牛不相及了。

导致这种情况的原因就在于,在不同的范畴,“真随机”和“伪随机”实际上是有着不同的定义。 对概率提出疑问的游戏玩家问的基本上都是应用层面的随机问题 而回复者提到的却是程序原理上的真伪随机。 这样一来一回非但不能解释清楚游戏里的随机问题,反而会让看的人越来越迷茫。

所以,要想讲清楚这件事情,就必须把程序原理上的真伪随机和应用领域的真伪随机都详细说明一番。

程序原理上的真伪随机

对计算机有点了解的朋友都知道,在程序里,0就是0,1就是1,程序中是不存在可能为0也可能为1的数据的。 所以,程序也就不能自己生成“随机”的东西。

在程序原理上,真随机的定义是指,通过外置的观测设备,观测某个真正随机的事物的状态。 在需要产生随机数的时候,记录该事物的状态值,再以此值经过一定的算法,得到一个真正的随机数。 (也有部分人认为宇宙中不存在真正随机的事物,所以宇宙中也没有真随机……这个争论太玄学,咱们就不搀和了。)

所以,采用真随机对于程序来说,成本极高效率极低,在制作游戏的时候,没有人会蛋疼的买设备去做真随机。

而相对于真随机的伪随机,就是指在系统内部抓取一个程序员自身无法预料准确值的值,把该值作为种子,放进随机数生成器,由此得到一连串随机数的方法。

这句话听起来很拗口,实际上过程非常简单。在此我举一个最简单例子来说明: 随机数生成器的核心部分是一个函数,函数就可以写成f(x)的形式 这个x,就是一个随机种子 x的确定标准就是要无法预测,比如说可以选取系统开始运行之后的时间(单位毫秒) 然后把x放进f() 根据函数的特效,x的值确定,f(x)的值就唯一且确定 这个f(x)就是该随机数生成器生成的第一个随机数,我们记作R_1 (注:R1只是一个胚体,在实际调用的时候,还会用一个不可逆的处理方法使其变成我们需要的随机数——比如50到300之间的随机数,这个过程在此就略过不写了) 然后如果还需要第二个随机数,就把R_1放进f(),得到第二个随机数R_2 = f(R_1) 然后如果还需要第三个随机数,就把R_2放进f(),得到第三个随机数R_3 = f(R_2) 以此类推

R_1 = f(x) R_2 = f(R_1) R_3 = f(R_2) … R_n = f(R_ n-1)

由此可以看出,一旦某个随机数生成器的种子确定,他之后所产生的每一个随机数就都确定了 随机数生成器就好比一副空白扑克,放入种子的过程就好比给每一张扑克都写上一个数字 然后等着程序在需要的时候去一张张抽取调用

进而可以得到一个推论:如果两个随机数生成器的种子是一样的,那么他们这两副扑克的牌序也就都是一样的了。

在同一时间创建三个随机数生成器,让他们的种子一致 然后让他们轮流生成4个100以内的随机整数 可以看到,这三个随机数生成器在每一次生成的值都是一样的

这个推论在游戏中最常见的运用场景就是replay回放 比如war3的录像回放,一个几十分钟的录像,大小只有几十K 这个录像文件中存放的实际上只有每一个玩家的有效操作,以及每一个随机数生成器的种子值 然后根据这些内容,创建一场游戏,模拟重现整场战斗

录像文件是不会去记录每一个野怪的掉落,剑圣的每一刀是否暴击,牛头人是否能打出粉碎等等信息的,否则容量就会大大超标。这些随机的内容全部都是通过set种子值来重现。

看到这里可能就会有不少玩家觉得很没劲 如果每一次随机的结果在游戏开始时就已经确定了,那随机还有什么意义

这,就是一个很哲学的问题了。

如果有一副空白扑克,上帝在每一张的上面都已经随便写上了一个数字。 如果你无法查看也无法修改这些数字,那么对于需要一张张摸牌的你来说,这些数字究竟算随机的还是确定的?

每个人的看法或许都不一样。 但是,无论你的看法如何,至少在表现出来的效果上,这副牌就是随机的。

同理对于程序中的种子随机: 如果你无法查看也无法修改随机种子,那么程序用伪随机方法所产生的随机数在表现出来的效果上就等同于真随机。

用伪随机进行大规模的模拟,其统计结果也会与数学计算出来的期望相符。

如果你暴击率35%,每次攻击时程序产生一个1到10000之间的数,处于1到3500之间时就暴击 连续攻击一万次,你暴击的次数就会在3500附近。 至于第一万零一次会不会暴击?仍然是35%的几率暴,65%的几率不暴。

模拟攻击一万次,暴击时计数+1 暴击的次数 应用层面的真伪随机

在应用层面上,真随机就是指每一次几率判断都是独立的。 比如说一个游戏角色的暴击率是20%,那么在真随机的机制下,他的每一次攻击都会是20%的几率暴击。 前一刀暴击了,下一刀是20%暴率,前一刀没爆,下一刀也仍然是20%暴率。

伪随机就是指同一类的概率事件,彼此之间存在关联性。 比如说一个游戏角色的暴击率是20%,那么在伪随机的机制下,这个角色每一次攻击的暴击率都是动态变化的。 前一刀暴击了,后一刀的爆率就会降低;前一刀没爆,后一刀的爆率就会提升。但是,当这个玩家进行足够多次攻击之后,统计上的暴击率还是会等于20%。

可以说,真随机是一种自然的随机机制,用代码来实现也非常容易,只需要用一个随机数与一个常量进行比较,根据大于小于等于分别触发不同的结果就行了。

而伪随机则是人为创造出来的一种机制,他需要程序员写下

相关推荐: