[作者:雯雯子] 一、纯随机的体验 在卡牌游戏中,抽卡是一个很重要的环节。对于卡池中价值较高概率较低的物品,比如设计抽出概率为5%,抽出期望次数为20次,但是实际玩家在抽的时候,大部分玩家都能在少数几次内抽出,也有一部分玩家很多次都没出,使得体验上的差异较大。如果可以使玩家抽出次数的分布符合正态分布,即绝大部分玩家都是在20次左右抽出指定道具,似乎更符合体验的需求。 首先来看一下,设定道具A抽出的概率为5%,在纯随机下,抽出次数的分布如图: 可以看出,有5%的玩家一次就能抽出道具A,10次以内抽出的玩家达到了40%,然而50次没有抽出的玩家也有7.7%。这很显然对于单个玩家来说,无论是很快抽出导致后续付费下滑,还是多次不出对抽卡不满,都并不是我们希望看到的情况。 那么,有什么办法可以尝试使玩家抽出次数的分布符合正态分布呢?这里我大概尝试了两种办法,一个是借鉴dota中暴击等概率计算的PRD算法,一个是用序列填充法。 二、PRD算法 PRD算法,是指假设暴击的概率为20%,那么以基础概率c为基础,如果没有触发暴击,下一次暴击的概率就增长为2c、3c、4c以此类推,直到触发暴击,则恢复基础概率c。这种算法可以很大程度的使得暴击次数接近期望值,并大大减少连续暴击或多次进攻无暴击的情况,使得暴击体验符合玩家的预期。 那么这里,我设定道具A的抽出概率为5%,模拟计算得PRD的基础概率c为0.38%,只考虑单个物品的抽出情况,抽出道具A的次数分布如图: 可以看出,现在玩家抽出次数的分布近似于正态分布,有70%的玩家在10-30次的时候抽出道具A,5次以内抽出和40次都没有出的玩家都只有5%。这样的分布使得绝大部分的玩家体验都在一个正常的范围,我觉得是可行的。 但是,对于抽卡来说,一个池子里的道具肯定不止一种,那么在多个道具的情况下如何处理呢? 设定池子中有5个道具,道具A、B、C抽出的概率为5%、10%、15%,道具D、E抽出概率为30%、40%,并且需要道具A、B、C的抽出次数分布均符合正态分布。模拟计算得到道具A、B、C的PRD基础概率分别为0.38%、1.47%、3.2%,单次抽卡代码如下: 不要吐槽代码,随便跑跑没有做优化 其中,b记录了每个道具距离上次抽出后已经抽了多少次,step为每个道具的基础概率,pro为本次抽卡中,各个道具对应的概率区间,runOne返回单次抽卡结果。 抽卡100万次,5个道具各自的抽出次数分布如图: 5个道具的实际抽出概率和期望如下: 可以看出,五个道具的实际出货概率和设计一致,A、B、C各自的抽出次数分布是大致符合正态分布的,而D、E没有进行PRD算法处理,抽出的曲线和纯随机的曲线一致。 所以,在一个抽卡池中设定一定数量的特殊道具并使特殊道具的抽出次数符合正态分布,我觉得PRD算法是可行的。当然也可以通过改进PRD算法(比如乘法换成次方)来调整使得每个道具的抽出次数正态分布曲线更集中。在实际运用中,应该需要配置n个道具的基础概率,配置其余非特殊道具的普通概率,并在每一次玩家抽卡后记录这n个道具距离上次抽出的抽卡次数。 但是,PRD算法总归会让最后一个“保底”道具的抽出次数无法符合正态分布。那么有没有办法可以让池子中所有的道具抽出次数都大致符合正态分布呢?
三、用正态分布进行序列填充 一个玩家进行多次抽卡,抽出的结果可以看作一个道具的序列,简单列举如下: [A,B,A,C,D,B,E,D……] 而单个道具的抽出次数,其实可以看作序列中,每一个道具到上一个相同道具的距离。如果这个距离都是符合正态分布的,那么对于这样一个抽出序列,道具的抽出次数应该是符合正态分布的。 那么我们先考虑道具A,设定抽出概率为5%,抽出次数期望为20次,随机生成道具A的抽出次数序列使之符合正态分布如图: 然后,将这些抽出次数,按照顺序插入玩家的抽卡序列中,由于次数符合正态分布,那么在抽卡序列中,抽出次数也会符合正态分布: 别吐槽图,数据量就500个太少 对于单个物品如此计算,而如果池子中有多个物品应该怎么处理呢?还是上面的池子,A、B、C、D、E五个道具分别对应的抽卡概率为5%、10%、15%、30%、40%。那么根据5个道具的抽出次数期望,各生成一个符合正态分布的次数序列,然后按次数大小顺序依次加入抽卡序列中。那么这个抽卡序列应该是所有道具都大致符合正态分布的。 这里需要注意的点是,生成的次数是距离上一次被抽出的次数,所以在每次抽出后,下一个次数应该加上上一个次数,以距离抽卡起点的次数进行比较大小。 简单举例: 生成3个道具的次数序列,然后按照大小取抽出序列,第一个为A,那么A的第二个值应该加上1变成3,再和B、C进行比较,第二个依然是A,A的第三个值加上3变成8再进行比较,依次进行最后可得到抽卡序列: 简单举例部分不懂的可问我 由于每次比较只需要一个值,我们初始只随机一个值,然后在每次抽出后再进行下一次随机即可。代码如下: 同样不要吐槽代码QAQ Count为抽卡总次数,props为道具数量,arr记录每个道具随机的符合正态分布的抽卡次数,dis记录每个道具距离上一次被抽出的抽卡次数,result记录道具i在第j次被抽出来的结果数。 5个道具的实际抽出概率和期望如下: 抽卡500万次,5个道具各自的抽出次数分布如图: 哇哦!我们可以发现5个道具的抽出次数都是大致符合正态分布的,概率和期望也是完全符合设计的。所以用序列填充法是可以完全做到抽卡池中的道具抽出次数都符合正态分布。 当然,序列填充也有一定的问题,在实际运用中,除了配置每个道具各自的概率,也需要记录玩家每一次抽卡后,池子中每一个道具的抽卡次数随机数,并且对于不同的玩家,需要不同的随机种子,不然有可能所有玩家的体验都是一模一样的。
四、简单总结 抽卡是卡牌游戏的核心体验,通过改进抽卡概率的算法,优化单个玩家的抽卡体验,使之符合正态分布,PRD算法和序列填充法都是可行的。如果条件允许,从玩家的体验出发优化概率算法,我觉得是有意义的。
五、参考资料
|