随机机制的探索(RandomPicker中文文档)

RandomPicker?? 最初的灵感来来自音乐随机播放: 权重++ 切歌模式

最近在研究游戏机制,发现随机在游戏领域有着广阔的空间。随机和博弈往往联系在一起,而博弈的英文即‘game’,非常有趣的一个词。

暴击机制与翻牌随机

在这里,推荐一篇非常不错的文章: 随机机制在游戏中的应用与控制

里面提到的暴击机制非常吸引我。因为真随机确实有个弊端,无法保证运气不好的情况下多少次能触发。 翻牌随机呢能够保证一轮当中必定触发一次,但是如果用在游戏领域它有一个非常要命的缺陷——存在真空期。何为真空期?我对其这么定义:

概率大于0的事件在某些情况下100%不触发,这些时期即为真空期。

举个例子,有5张牌,其中只有一张是中奖。那么,若第一次就翻到了中奖,也就意味着后面4次100%不会中奖。这是很要命的,赌徒都带有侥幸心理,即便只有1%的机会也愿意放手一博。但是,没有哪个赌徒蠢到会去博0%的机会。因此,真空期是应该避免的。

上面提到的暴击机制解决了这个问题

累计爆率,累计爆率设计思路和实现方法为:爆率的计算使用如下模式:每次攻击如果不暴击则下一次的暴率增加,直到产生暴击以后累积的爆率复原。 例:单次基础暴击为12%,如果第一次没暴击则第二次暴击为24%。如果第二次仍然没暴击则第三次暴击为36%。第三次出现暴击,累计被清空。第四次的暴击率还原为12%。(很显然,如果一直不暴击,那么暴击一定会累计到100%以上产生必然的暴击)。

当然,这个暴击率递增有点夸张了,但是它提供了一个思路与一种实现可能:

1.通过重置随机率来避免真空期;2.这个综合概率是可以算出来的。

概率推算

因此,翻牌随机也只需要加一个简单的重置即可:翻到中奖牌后,重新洗牌。存在的问题就是:概率如何计算?假设我想保证20%的中奖率,该有多少张牌?

用归纳法来递推一下: 1张牌,几率1; 两张牌,1/2的几率第1次中,1-1/2的几率第2次中(1/2),综合=1/2+(1/2)/2=3/4; 3张牌,1/3的几率第1次中,(1-1/3) * (1/2)的几率第2次中(1/3),1 -1/3-1/3的几率第3次中(1/3),综合=1/3+(1/3)/2+(1/3)/3=11/18; 看不出什么,那么继续递推—— 4张牌,1/4的几率第1次中,(1-1/4) * (1/3)的几率第2次中(1/4),(1-1/4-1/4) * (1/2)的几率第3次中(1/4),1-1/4-1/4-1/4的几率第4次中(1/4),综合=1/4+1/8+1/12+1/16=25/48; ... 好了,现在比较明显了 n张牌,1/n第1次中,1/n第2次中,1/n第三次中...1/n第n次中。综合=1/n + 1/(n * 2) + 1/(n * 3) + ... + 1/(n * n) = (1/n) * (1+1/2+1/3+...+1/n)

!!!真tm美妙的数学,目前还没有公式能表示 1+1/2+1/3+...+1/n ,看来只能写个脚本算出前54张的对应概率了。 Python代码如下:

def poker(n):
    rate = 0
    for x in range(1,n+1):
        rate = rate + 1/x
    return (1/n) * rate

for x in range(1,55):
    print("%d: %.2f" % (x, poker(x)*100) + "%")

公式:(1/n) * (1+1/2+1/3+...+1/n) n=1...54时 1: 100.00% 2: 75.00% 3: 61.11% 4: 52.08% 5: 45.67% 6: 40.83% 7: 37.04% 8: 33.97% 9: 31.43% 10: 29.29% 11: 27.45% 12: 25.86% 13: 24.46% 14: 23.23% 15: 22.12% 16: 21.13% 17: 20.23% 18: 19.42% 19: 18.67% 20: 17.99% 21: 17.36% 22: 16.78% 23: 16.24% 24: 15.73% 25: 15.26% 26: 14.82% 27: 14.41% 28: 14.03% 29: 13.66% 30: 13.32% 31: 12.99% 32: 12.68% 33: 12.39% 34: 12.11% 35: 11.85% 36: 11.60% 37: 11.36% 38: 11.13% 39: 10.91% 40: 10.70% 41: 10.49% 42: 10.30% 43: 10.12% 44: 9.94% 45: 9.77% 46: 9.60% 47: 9.44% 48: 9.29% 49: 9.14% 50: 9.00% 51: 8.86% 52: 8.73% 53: 8.60% 54: 8.47%

因此,可以得出,若希望中奖率为20%(在翻牌重置模式下),则需要17或者18张牌。

概率校验

一切似乎很美妙,轻而易举推出了公式与概率表。 然而,用Java代码进行了一万次抽取校验,发现得出的概率与概率表相差甚远。

    private void pokerTest(int num) {
        List<Integer> list = new ArrayList<>();
        for (int x = 0; x < num; x++)
            list.add(x);
        Collections.shuffle(list);

        Random random = new Random();
        int luckyCount = 0;
        for (int i = 0; i < 10_000; i++) {
            int index = random.nextInt(list.size());
            int lucky = list.remove(index);
            if (lucky == num/2) { //取中间值作为中奖数
                luckyCount++;
                //抽中后重新洗牌
                list.clear();
                for (int x = 0; x < num; x++)
                    list.add(x);
                Collections.shuffle(list);
            }
        }
        System.out.println(" " + (luckyCount/10_000f));
    }

执行pokerTest(17),得到0.11左右的数,与表中的20.23%差得有点多。 一步步校验, 执行pokerTest(1),得到1.0,没问题; 执行pokerTest(2),得到0.67,问题来了。

为什么两张牌的时候,概率会是0.67 ???

公式校准

回顾一下,两张牌的概率我是这么算的:

错误的算法: 两张牌,1/2的几率第1次中,1-1/2的几率第2次中(1/2),综合=1/2+(1/2)/2=3/4;

考虑到了每次抽中的概率,考虑到了要除以抽中时所用的次数,但是!忽略了次数占比。两张牌,一次中的次数占比是1/(1+2),两次的次数占比是2/(1+2),因此,两张牌应该这么算:

两张牌,1/2的几率第1次中,1-1/2的几率第2次中(1/2),综合=(1/2) * (1/(1+2))+((1/2)/2) * (2/(1+2))=2/3;

正确的公式应是:

n张牌,1/n第1次中,1/n第2次中,1/n第三次中...1/n第n次中。综合=(2/(n * (n+1)) * 1/n + (2 * 2/(n * (n+1)) * 1/(n * 2) + ... + (n * 2/(n * (n+1)) * 1/(n * n) = (2/(n * (n+1)) * (1+1+1+...+1) = 2/(n + 1)

结果如此简单:2/(n+1)。代入测试代码,发现基本没有偏差。

正确Python代码:

def poker(n):
    return 2/(n+1)

for x in range(1,55):
    print("%d: %.2f" % (x, poker(x)*100) + "%")

P=2/(n+1) 1: 100.00% 2: 66.67% 3: 50.00% 4: 40.00% 5: 33.33% 6: 28.57% 7: 25.00% 8: 22.22% 9: 20.00% 10: 18.18% 11: 16.67% 12: 15.38% 13: 14.29% 14: 13.33% 15: 12.50% 16: 11.76% 17: 11.11% 18: 10.53% 19: 10.00% 20: 9.52% 21: 9.09% 22: 8.70% 23: 8.33% 24: 8.00% 25: 7.69% 26: 7.41% 27: 7.14% 28: 6.90% 29: 6.67% 30: 6.45% 31: 6.25% 32: 6.06% 33: 5.88% 34: 5.71% 35: 5.56% 36: 5.41% 37: 5.26% 38: 5.13% 39: 5.00% 40: 4.88% 41: 4.76% 42: 4.65% 43: 4.55% 44: 4.44% 45: 4.35% 46: 4.26% 47: 4.17% 48: 4.08% 49: 4.00% 50: 3.92% 51: 3.85% 52: 3.77% 53: 3.70% 54: 3.64%

因此,在翻牌重置模式下,若希望中奖率为20%,需要9张牌;若希望中奖率为5%,需要39张牌。

翻牌重置的最终代码参见

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏about云

使用Spark MLlib给豆瓣用户推荐电影

问题导读: 1.常用的推荐算法有哪些? 2.推荐系统是什么样的流程? 3.从这个推荐系统我们能学到什么? 推荐算法就是利用用户的一些行为,通过一些数学算法,推测...

8217
来自专栏ATYUN订阅号

赫尔辛基大学AI基础教程:搜索和解决问题(2.1节)

想象一下你在一个外国的城市,在某个地方(比如一家酒店),想用公共交通工具去另一个地方(比如一家不错的餐馆)。你是做什么?如果你会像许多人一样,掏出智能手机,输入...

1486
来自专栏灯塔大数据

探秘 | Python 求职 Top10 城市,来看看是否有你所在的城市

导读:从智联招聘爬取相关信息后,我们关心的是如何对内容进行分析,获取用用的信息。本次以上篇文章“5分钟掌握智联招聘网站爬取并保存到MongoDB数据库”中爬取的...

3243
来自专栏PaddlePaddle

【AI核心技术】课程十九:神经图灵机—寻址

UAI与PaddlePaddle联合推出的【AI核心技术掌握】系列课程持续更新中!

911
来自专栏机器之心

教程 | 如何优雅而高效地使用Matplotlib实现数据可视化

2945
来自专栏PPV课数据科学社区

电商评论情感分析

? 随着网上购物的流行,各大电商竞争激烈,为了提高客户服务质量,除了打价格战外,了解客户的需求点,倾听客户的心声也越来越重要,其中重要的方式 就是对消费者的文...

9437
来自专栏AI研习社

一次 PyTorch 的踩坑经历,以及如何避免梯度成为NaN

本文首发于知乎答主小磊在「PyTorch有哪些坑/bug?」下的回答,AI 研习社获原作者授权转载。 分享一下我最近的踩坑经历吧。 这几天在实现一个语义分割的 ...

1.6K6
来自专栏生信技能树

如何通过Google来使用ggplot2可视化

今天是大年初二,这篇文章我只想传达一点: 没有什么菜鸟级别的生物信息学数据处理是不能通过Google得到解决方案的,如果有,请换个关键词继续Google! 第一...

3298
来自专栏CDA数据分析师

案例 | R语言数据挖掘实战:电商评论情感分析

随着网上购物的流行,各大电商竞争激烈,为了提高客户服务质量,除了打价格战外,了解客户的需求点,倾听客户的心声也越来越重要,其中重要的方式 就是对消费者的文本评论...

67110
来自专栏大数据挖掘DT机器学习

Python 自然语言处理(NLP)工具库汇总

最近正在用nltk 对中文网络商品评论进行褒贬情感分类,计算评论的信息熵(entropy)、互信息(point mutual information)和困惑值(...

51412

扫码关注云+社区

领取腾讯云代金券