アニマロッタ: 全ジャックポットチャンスの確率を求める


確率を求めよう

アニマロッタには現在4種類のJPCがあり、苦手意識得意意識をそれぞれ持っているかもしれません。実際どれくらいの確率なのかを計算します。ある程度アニマロッタを知っている方向けの記事なので、細かい説明はしないのでご了承ください。

計算の方法ですが、プログラミング言語 python を使ったシミュレーションで確率を求めています。記事の後半には具体的にどうシミュレーションを設計したかも解説したいと思います。

カラコロッタの各JPCの確率はこちら

スターダストJPC

概要

スターダストJPCは70球以内に1~25番のポケットを全て埋めるシンプルなJPCです。シミュレーションではクリスタルJPC(球数増加アイテム)や倍率付きスターダストは考慮していません。

倍率付きスターダストは、JPCの場合のみ効力を発揮します。つまり、ワンダーチャンスのはずれ配当は等倍で、JPCからはJPとはずれ配当に倍率がつきます。

JPCが外れた場合ははずれ配当がもらえます。JPが獲れた場合ははずれ配当は無効でJP値が配当になります。

確率と期待値

スターダストJPCの当選率は
19.60%

思ったより低いと思います。スターダストJPCは安定した当選率を持っている印象ですが、確かに振り返ってみるとこれくらいの確率でしょう。

スターダストJPCの期待値は
562.01枚

JP値が1000枚のとき

JPCに上がってしまえばJP値の半分以上が期待できます。

  • JP当選時の平均値は1000枚

  • JP非当選時の平均値は455.26枚

という内訳になっています。JPCが外れても4割から5割のリターンは見込めます。

ムーンライトJPC

概要

アニマ5にワンダフルジャックポットとして追加されたJPCです。アニマ6にムーンライトと改名されました。
5の倍数のデジタルポケットにヒットさせるJPCです。最初のラウンドは5球で挑戦、成功したら次のラウンドに進みます。ラウンドが進むごとに球数と有効ポケットが一つずつ減ります。ラウンド2クリアでJP扱いです。

確率と期待値

ムーンライトJPCの当選率は
33.86%

印象通り、当選率はスターダストよりもかなり高いです。JPCまで行ったら確実に獲りたいJPCになっています。

ムーンライトJPCの期待値は
948.04枚

JP値の下限が1000枚のとき

パーフェクトまで行けば18倍JP(理論値は28.5倍JP)まであるため、期待値もつられてとても高いです。期待値がほぼJP値なので期待が持てるJPCです。

  • JP当選時の平均値は2163.29枚

  • JP非当選時の平均値は325.82枚

以上の内訳を見ると、JPが外れた時の配当がスターダストと比べて低くなっています。その分JPを獲得することができたらかなり期待が持てます。ハイリスクハイリターンと思いきやそもそもJP当選率が高いのでやはりプレイヤーにとっては嬉しいJPCです。

各ラウンドの成功率

ムーンライトJPCに関してはシミュレーションをしなくても式を立てて計算することでも求められます。ムーンライトJPCでラウンド挑戦が失敗する場合は発射されたボール全てがはずれポケットに入賞する場合のみです。ラウンド成功についてはそれ以外の場合、ということになります(つまり一球以上あたりポケットに入賞すること)。

ラウンドを突破する確率はラウンドが失敗する確率を求めてそれを全体の確率から引けば求まります。
例えば、ラウンド1は5球抽選であたりポケットが5つあります。各球につきはずれポケットに入賞する確率は$${20\over25}$$なので、$${\frac{20}{25}^5}$$が失敗する確率です。成功する確率は$${1-\frac{20}{25}^5}$$です。

  • 32.77%でラウンド1終了

  • 33.47%でラウンド2終了

  • 23.01%でラウンド3終了(JP獲得)

  • 9.1%でラウンド4終了(約3倍JP以上)

  • 1.59%でラウンド5終了(約8倍JP以上)

  • 0.066%でパーフェクト(約18倍JP以上)

  • 0.000000000009%で理論値JP(28.5倍JP)

JPが跳ね上がるラウンド4以降に進める確率が約10%ということです。理論値JPは100兆分の9の確率で当たります。

サンシャインJPC

概要

アニマ6から追加されたJPCです。ムーンライトと若干似ているルールで、40球を発射して5の倍数のデジタルポケットに4回以上入賞するとJP獲得です。4回入賞は単一のポケットでカウントされるので、5つのデジタルポケットに満遍なく3回入賞などするとJPは非当選となります。

確率と期待値

サンシャインJPCの当選率は
37.1%

ごめんなさい、一つ言わせてください。

嘘つけええええぇぇぇぇぇ!!!

という感じでホントですか?と疑っていますがシミュレーションの設定は問題ない(はず)なので4割弱の確率でJPが獲得できます。

サンシャインJPCの期待値は
576.41枚

JP値の下限が1000枚のとき

なお、内訳としては:

  • JP当選時の平均値は1197.55枚

  • JP非当選時の平均値は210枚

となっているので、JPが獲れなかったときの配当がかなり渋いです。JPが獲れた際、はずれ配当が無効になります。また、5回以上デジタルポケットに入賞したら入賞のたびにJPの10%が加算されます。4回以上入賞されたデジタルポケットが複数個あれば、その個数倍のJPになります(最大5倍)。
5回以上の入賞はあれど2倍JPはかなり難しく、3倍JP以上はかなりの豪運です。JP当選時の平均が1.2倍JPなので、ほぼ等倍でしか獲れないと思った方がいいでしょう。

はずれ配当があまり期待できなくて倍率もつきにくい以上、リンクボーナスなどJPが獲得できることのメリットがあると嬉しいJPCという考えでしょうか。

ドリームJPC

概要

アニマ7から追加されたJPCです。2球発射し、入った2つ数字とその間にある数字が全て点灯し、25個全てのポケットが光ればJP獲得です。抽選機が円になっているので、1番と10番に入賞した場合、{1, 2, 3, …, 8, 9, 10} が光るパターンと  {10, 11, 12, …, 24, 25, 1} と光るパターンがあります。光る数字が少ない方が採用されます。

確率と期待値

ドリームJPCの当選率は
28.57%

妥当な確率だと思います。スターダストJPCが一番確率が低いのはとても意外です。

ドリームJPCの期待値は
639.14枚

JP値が1000枚のとき
  • JP当選時の平均値は1254.95枚

  • JP非当選時の平均値は392.84枚

良くも悪くもスターダストと近い数値で安定していると言えると思います。サンシャインと同じく倍率アップはあるがそこまで多いわけではないです。倍率アップは2球とも同じポケットに入ることで権利が得られます。確率は$${\frac{1}{25}^{2}}$$で$${1\over125}$$ですが、25通りあるので$${1\over25}$$です。

コンプリートJPC

概要

アニマ7から追加された特殊なJPC。スターダスト、ムーンライト、サンシャイン、ドリームの4つのJPを期限内に全て獲得し、さらに期限内にコンプリートワンダーチャンスを突破することで挑戦できるJPC。

スターダストの要領で80球抽選し、最後に1球だけ抽選する。ラスト1球がはいいたポケットが、最初の80球の抽選で5回以上入賞されたポケット(赤ポケット)ならJP獲得です。配当はコンプリートワンダーチャンスの配当(集めたりんご分)プラスJP4種で獲得した配当です(複数回獲得の場合は最も高いJP枚数)。はずれた場合はワンダーチャンス分のはずれ配当だけになります。つまり、4種JPの配当はコンプリートJP獲得時のボーナスということです。

確率

コンプリートJPCの当選率は
21.54%

スターダストよりも若干当たりやすいという感じでしょうか。不思議なJPCで、通常スターダストとは逆でなるべく被ってほしく、十分被ったら(赤ポケットができたら)そのポケットに被らず他のポケットにバラけてほしい、となんとも忙しいです。

期待値ですが、コンプリートボーナスの配当によりますし、JPCが外れた場合は突破したワンダー分だけのため、実質的にコンプリートボーナスを獲得するか0かというJPCです。
そのため、基本的な立ち回りはなるべく高額で早く4種のJPを獲得した後、コンプリートボーナス狙いでコンプリートJPCへ上がるまでローベットをすることになると思います。

シミュレーションの設計

各JPCのシミュレーションを設計するにあたって、次の前提を立てています。

  • 1~25番のポケットにボールが入賞する確率は同様に確からしい($${1\over25}$$)

  • 上記により、ボール同士の衝突は考慮しない

  • 上記により、有効ポケットの配置は考慮するが結果に影響はない

  • 上記により、ボール発射のタイミングは考慮しない

  • 上記により、盤面の回転速度は考慮しない

ボールの抽選はpythonの整数をランダムで生成するrandint関数を用いて、1〜25(または0~24)を球数分生成します(番号はそれぞれポケットに対応)。どのポケットに何回入賞したかを記録する必要がある場合は生成した乱数を添字として使用し、各要素に入賞回数を記録しています。

試行回数は100万回です。

スターダストのシミュレーション

スターダストJPCは25個のポケットに全て入賞したかどうかを確認することと、外れた場合の配当が各ポケットの入賞回数によるため、配列を用意しました。70回(70球)整数を生成し、それを配列の添字として中の要素を+= 1して入賞回数を管理しています。

本来25個のポケットが全て埋まった時点で(70球撃ち切っていなくても)JP獲得となりますが、1球抽選ごとに確認をすると処理時間がかなり伸びてしまうため、70球撃ち切った後にポケットの埋まり具合をチェックしています。

配列の要素が全て1以上なら全てのポケットが埋まっているということになり、JP配当を総獲得枚数に加算し次の試行へ進みます。
そうではない場合ははずれ配当を計算する必要があるため、各要素の入賞回数を確認してそれに対応する配当を総獲得枚数に加算します。

  • ブルー(1hit): 配当なし

  • グリーン(2hit): 0.4%

  • イエロー(3hit): 1.2%

  • ピンク(4hit): 2.6%

  • レッド(5hit以上): 4.6%

パーセントはJP値の割合です。なお、配当は最終的な入賞回数ではなく、入賞するごとに配当が加算されます。上記の表は最終的な配当です。例えば、最終的にピンクだったポケットの配当は、0→0.4%→0.8%→1.4%と4回の入賞のたびにこれらの配当が加算されます。これの和が2.6%になります。プログラムでは抽選が終わった後にしか入賞回数を確認しないので、そのまま和で計算しています。

あるポケットがレッドになった後、以降は入賞するたびにレッドの配当が加算されるので(仮にオーバー入賞とします)、入賞回数が6回以上の場合は和の4.6%とレッドの配当(2%)をオーバー入賞した回数分加算しています。

他のJPCについても、コードを載せます。noteのコードブロックは見にくいのであまり気が進みませんが、各JPCのプログラムが十分に短いのでnoteのコードブロックで載せます。

#from random import randint
def stardust(trial, jp):
    success, fail, win = 0, 0, 0
    odds = [0, jp * 0.004, jp * 0.012, jp * 0.026, jp * 0.046, jp * 0.02] #normal
    
    for i in range(trial):
        hit = [0] * 25
        for i in range(70):
            hit[randint(0, 24)] += 1

        if all(hit):
            success += 1
            win += jp
        else:
            fail += 1
            for freq in hit:
                if freq > 5:
                    win += odds[4] + odds[-1] * (freq - 5)
                else:
                    win += odds[freq-1]
    return success, fail, win

はずれた時の配当ですが、スターダストJPは必ず等倍JPではずれ配当も無効になるため、総獲得枚数winからJP値とJP獲得回数を掛けた数値を引けばはずれた時のはずれ配当がわかります。

ムーンライトのシミュレーション

ムーンライトJPCはいわゆるはずれ配当がなく、JPを獲得したときにはずれ配当が無効になることはありません。従って、入賞回数を記録する必要がないのでそのための配列は用意しません。一方、入賞したらラウンドが進む有効ポケットがあります。また、その有効ポケットがどんどん減少するため、それを管理する配列を用意します。

どの番号が消えるか、ですがシミュレーションの前提に則るとランダムで問題ありませんが、実機に近い仕様で実装できるためそうしました。ラウンド1で最初に入賞したポケットを記録し、以降はその番号の2つ先の番号を消していきます。
どういうことかというと:

  • 有効ポケット = [5, 10, 15, 20, 25] #5の倍数のデジタルポケット

  • デジタルポケット = [5, 10, 15, 20, 25]

  • 添字 = ラウンド1で最初に有効ポケットに入賞したポケットの添字

    • 最初に10番に入賞したら配列[1]に10番があるので添字 = 1

  • 配列から10番を削除します

    • 有効ポケット = [5, 15, 20, 25]

    • デジタルポケット = [5, 10, 15, 20, 25]

  • 次のラウンドが成功したら、添字 += 2をします。デジタルポケット[添字]をします。その要素を有効ポケットから探して削除します。

    • 添字 += 2(添字=3)、デジタルポケット[3] = 20、20を有効ポケットから削除(有効ポケット = [5, 15, 25])

2個先のポケットを削除する理由について、ラウンドが進むごとにポケットがなるべく分散するように消えるためです。例えば、有効数字が3個に減った時、そのうち2個は隣り合っていて、残りの1個はその反対側にある配置になります。2個先のポケットを削除するようにするとこの配置をラウンド5まで維持できるため採用しました。

今回は配列を2つ用意しましたが、配列は一つにして要素を削除せずに-1(入賞し得ないポケット番号)にするなどすることもできます(今思いつきました)。

各ラウンドの抽選に関してはwhile文を使い、失敗したら集計する感じになります。配当に関しては入賞した時点で判定し獲得枚数に加算します。抽選が全て終了するまでJPを獲得しているかわからないため、仮枚数として保存し、JP獲得していた場合はJP獲得時の配当に、はずれていた場合ははずれた時の配当に加算して仮枚数をリセットします。こうするのはスターダストと違いはずれ配当が無効にならないことと抽選結果によってJP獲得時の枚数が変動するからです。

配当は以下の通りです:

  • はずれポケット: 4%(全ラウンド共通)

  • 有効ポケット(ラウンド1): 10%

  • 同ラウンド2: 50%

  • 同ラウンド3: 200%

  • 同ラウンド4: 500%

  • 同ラウンド5: 1000%

#from random import randint
def moonlight(trial, jp):
    success, fail, win, failwin = 0, 0, 0, 0
    odds = [jp*0.04, jp*0.1, jp*0.5, jp*2, jp*5, jp*10] #normal
    pockets = [5, 10, 15, 20, 25]
    endStage = [0, 0, 0, 0, 0, 0]
    for i in range(trial):
        challenge = True
        stage = 1
        ball = 5
        twin = 0
        rabbit = [5, 10, 15, 20, 25]
        rabbitIndex = -1
        while challenge:
            challenge = False
            for j in range(ball):
                hit = randint(1, 25)
                if hit in rabbit:
                    if rabbitIndex == -1:
                        rabbitIndex = pockets.index(hit)
                    challenge = True
                    twin += odds[stage]
                else:
                    twin += odds[0]
            
            if challenge:
                if stage == 5:
                    stage += 1
                    challenge = False
                else:
                    rabbit.remove(pockets[rabbitIndex % 5])
                    rabbitIndex += 2
                    stage += 1
                    ball -= 1
        
        if stage > 2:
            success += 1
            win += twin
        else:
            fail += 1
            failwin += twin
        endStage[stage-1] += 1
    return success, fail, win, failwin, endStage

サンシャインのシミュレーション

サンシャインはスターダスト同様配列を用意し入賞回数を管理します。スターダストと同じ要領で配列の要素を加算して入賞回数とします。最後の一球だけ同じ要素に+=2します(2hit)。

最初に5の倍数のポケットの入賞回数を見て、一つでも4回以上入賞があればJP獲得とします。また、5回以上入賞(オーバー入賞)または倍率JPがあるかを確認するためにそれぞれの入賞回数を調べます。4回以上入賞したポケットがあるたびにJP値を加算し、5回以上入賞は入賞ごとにJP値の10%を加算します。

上記が偽の場合は残りのポケットを見てはずれ配当を計算します。配当は以下の通りです。

  • ブルー: 0.6%

  • グリーン: 1%

  • レッド: 2%

  • オーバー入賞: 10%

JP獲得時ははずれ配当が無効なのでJP獲得時は上記の処理はしません。

#from random inport randint
def sunshine(trial, jp):
    success, fail, win, failwin = 0, 0, 0, 0
    odds = [jp*0.006, jp*0.01, jp*0.02, jp*0.1] #normal
    
    for i in range(trial):
        hits = [0] * 25
        for i in range(40):
            hit = randint(0, 24)
            hits[hit] += 1
            if i == 39:
                hits[hit] += 1
        
        if any((i >=4 for i in hits[4::5])):
            success += 1
            for freq in hits[4::5]:
                if freq >= 4:
                    win += jp + odds[-1]*(freq-4)
        else:
            fail += 1
            for i, freq in enumerate(hits):
                i = (i+1) % 5
                if i == 0:
                    continue
                elif i == 2:
                    failwin += odds[2]
                elif i == 3:
                    failwin += odds[1]
                else:
                    failwin += odds[0]

    return success, fail, win, failwin

ドリームのシミュレーション

ドリームも配列を用意しますが、ドリームはポケットを点灯させたいので、配列の要素は0か1(無点灯か点灯)で管理します。

問題は、2球抽選した時にどっち回りで数字を挟んで光らせるかです。もっと良い考え方があると思いますが、今回はゴリ押しパワーで2パターンの点灯数を比較して小さい方を採用する形にしました。

1球目: 10, 2球目19
[10, 11, 12, …, 19] は10, [19, 20, 21, …, 10]は17なので、前者を採用します。

配列の要素を1にします。
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
という具合です。

同じ数字にヒットした場合は球数を2つ増やし(実際は球数を減らさずループさせる)JP値もオッズアップさせます。

抽選終了時に配列の要素が全て1ならJP獲得、それ以外ならばはずれ配当を計算します。

配当は以下の通りです。

  • 10点灯まで: 1点灯ごとに1%

  • 11点灯から: 1点灯ごとに2%にアップ

  • 21点灯から: 1点灯ごとに5%にアップ

  • 23点灯から: 1点灯ごとに10%にアップ

14点灯なら、
1% + 1% + 1% + 1% + 1% + 1% + 1% + 1% + 1% + 1% + 2% + 2% + 2% + 2%
になります。

#from random import randint
def dream(trial, jp):
    success, fail, win, failwin = 0, 0, 0, 0
    for i in range(trial):
        pair = 6
        multi = 1
        light = [0] * 25
        while pair > 0:
            first, second = randint(0, 24), randint(0, 24)
            if first == second:
                light[first] = 1
                multi += 1
                continue
            elif second < first:
                first, second = second, first
            
            l1 = len(light[first:second+1])
            l2, l3 = len(light[second:]), len(light[:first+1])
            if l1 < l2 + l3:
                light[first:second+1] = [1] * l1
            else:
                light[second:] = [1] * l2
                light[:first+1] = [1] * l3
            pair -= 1
        
        if all(light):
            success += 1
            win += jp * multi
        else:
            fail += 1
            lighted = light.count(1)
            if lighted >= 23:
                failwin += jp * 0.4 + jp * 0.1 * (lighted - 22)
            elif lighted >= 21:
                failwin += jp * 0.3 + jp * 0.05 * (lighted - 20)
            elif lighted >= 11:
                failwin += jp * 0.1 + (jp * 0.02 * (lighted - 10))
            else:
                failwin += jp * 0.01 * lighted

    return success, fail, win, failwin

コンプリートのシミュレーション

スターダストと全く同じ要領で入賞回数を管理します。最後に1回だけ整数を生成し、そのポケットにすでに5回以上入賞されていればJP、そうでなければはずれです。

配当も計算していないので以下のように短いです。

#from random import randint
def complete(trial):
    success = 0
    for i in range(trial):
        hit = [0] * 25
        for j in range(80):
            hit[randint(0, 24)] += 1
        
        last = randint(0, 24)
        if hit[last] >= 5:
            success += 1
    return success


いいなと思ったら応援しよう!