随机

手游通常的模式是打关,掉东西。东西里面有稀有的,有普通的。这就造成了一种手游血统论,很多玩家觉得自己不出东西是由于自己其实出生在非洲。作为玩家,当然希望自己是欧洲人,稀有的道具经常掉落。但是作为游戏制作方,到底什么样的抽卡体验,会对玩家最好,对游戏运营也最好呢?其实并没有答案。从结果论来说,最火的游戏的策略是最好的。但我无从得知历史上那些火的游戏都是如何做掉落随机的。我只能说从我自己玩游戏的角度出发,我不希望我自己太非,我也不希望我的朋友或者各种不认识的人太欧。我们中国古思想早就说过了,不患寡而患不均。

对于超级稀有的掉落,比如1%,遵循均匀分布(uniform distribution),期望是100次出一次,实际上,比如每个人抽1000次,得到的概率分布图会是一个正态分布。我随便写了一段代码模拟了这个过程。

normal distribution

可以看到,100万人里,只有58%的人获得了8-12次奖励。而剩下的42%的人,要么获得的次数多了,要么少了。可想而知那35个获得0个的人是什么心情,可能他们不会继续玩游戏了。再比如6次以下的12%的人,当他们听说他们的欧洲人朋友获得了13次以上(20%的人),他们可能也不会继续玩了。并且20%的13次以上的这群人,他们会比其他人要么少花很多时间,要么少氪金。

要是所有人都能获得8-12次奖励,那该多好呢?这样欧洲人和非洲人的血统差也不会过大,没有人会被伤害,所有人都获得了幸福。

我们可以使概率变得不那么随机。暴雪做过一个伪随机算法,后来冰蛙在dota2里也使用了这个算法。 算法详情。 使用这个算法,我们需要记录已经多少次没掉落某物,然后动态地修改几率。推广到多物掉落也是一样的。记录列表中每个物品有多少次没有被掉落,如果A掉落,则BCDE…的次数+1。实现了dota2的prd算法以后,我们来看所有玩家的掉落分布图。

normal distribution

可以看到,这次的正态分布更加靠近中心的10次了,但是仍然有5.84%的非洲人和7.57%的欧洲人。如果对这个结果满意,就可以完事了。但是我本人仍然对这个结果不满意,我不想看到有人能拿到13个及以上,我非常讨厌欧洲人。这怎么办呢?

我们思考一个问题。prd中,每次玩家抽取到此物以后,将次数重置到0。以1%为例,c=0.00015604019165039, 1/c=6408, 最倒霉的玩家在6408次一定会抽到, 然后重置到0。如果我们把次数-100会怎么样呢?100是0.01的倒数,实际期望100次抽到1次。当玩家运气够好时,在100次以内抽到了,记录的次数会减到负数,此时到记录回正前他都抽不到此物。同理运气不好的玩家,抽到以后,-100之后的记录次数也从正数开始,相当于他的厄运给自己之后累计了好运。由于期望是100,所以最后抽到的概率仍然为1%。当然我是通过代码验证过了。用这种算法100万人抽1000次得到的概率分布如下:

normal distribution

好运已经完全被扼杀了!坏运气稍少了!显然这不满足我们对游戏概率分布的需求。但是开展到这里其实已经有了最终的方案了。我们可以设置一个负无穷到正无穷上都取得到0-1的概率函数,而不是prd这样的只在0-n上有值的函数。然后每次随机到目标后,将记录的次数-n。这样就能构造出一个平衡好运和厄运的随机了。

另外,中国目前手游里比较流行的保底,掉落池等方法,也都是为优化掉落设计的,比较简单,分布也很明显,就不多说了。

math.randomseed(os.time())

local times1 = 1000000
local times2 = 1000

local percent = 0.01

local result = {}
for i = 1,times1 do
    local t = 0
    for j=1,times2 do
        local p = math.random(math.maxinteger) / math.maxinteger
        if p < percent then
            t=t+1
        end
    end
    result[t] = (result[t] or 0) + 1
end
Written on October 22, 2018