随机机制的探索(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张牌。

翻牌重置的最终代码参见

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容