Pとある魔術の禁書目録(インデックス)のシミュレーション

お世話になっております、スログラミングです。

「遊タイム機のシミュレーションがしたい!」と思い始めて早3ヶ月が経ってしまいました。
(9月の「ぱちんこ 仮面ライダー 轟音」がきっかけ)

はまり属性の私にとって遊タイム(天井、天井時短)は非常にありがたい機能であるわけですが、実際どのくらい甘くなっているのかイメージしづらいところがありました。
具体的には、遊タイム有と無の場合のスランプグラフを描画して、どのくらい助かったのかを比較してみたいと思います。

今回タイトルにあるとおり、「Pとある魔術の禁書目録(インデックス)」のシミュレーションを作っていこうと考えていますが、インデックスを選んだ理由は1点!!
ST100%突入でスペックがシンプルだから!!
当初は突時もついている「P真・牙狼」のシミュレーションを予定していましたが、ちょっと複雑なので今回は断念。気が向いたら取り掛かってみます。

ということで早速行ってみましょう。
今回もPythonでのコーディングです。
※当然ですが念のため。素人の趣味なので実機とは異なる可能性が大いにある点ご承知おき下さい。

今回のアジェンダはこちら。

1. 遊タイムのコーディング

遊タイムはご存じのとおり、大当たり間で規定回数はまると時短に突入する機能です。
今回は、大きく2点の考慮を行いますので、それぞれ記載していきます。

1.1. ベースの違い

これは、イメージしやすいですね。
左打ちでヘソを狙うときと、右打ちで電チューを狙うときでは、1k(250玉)あたりの回転数が大幅に異なります。
今回のプログラム上では以下のような形で定義しています。
普段の遊技でイメージしやすいように、左打ちは1k(250玉)あたりの回転数、右打ちは玉がどのくらい残るかで設定しています。
    # 1k(250玉)あたりの回転数(左打ち)
    Border = 18
    # 1k(250玉)打って何発残るか(右打ち)。今回は10%減→90%残る仮定で計算
    Border_ST = 250 * 0.90

続いて、先ほどの設定値を元にループ処理(1回転毎の処理の繰り返し)を行っていきます。
一旦左打ち状態での使用玉数を減算してから、遊タイム中だった場合に玉数を再計算しています。
ぱっと思いついたプログラムの構成が下図の2パターンでした。
「当り判定+連荘処理」を2回書くのが嫌だったので、ちょっと回りくどいですが右側のやり方を採用しています。


また、ご存じの方がほとんどだと思いますが、遊タイムは大当たり間で1回しか入りません。
つまり、インデックスでは800回転はまると遊タイムに入りますが、その後さらに800回転はまって1600回転になったとしても遊タイムには突入しません。
ということで、遊タイムか否かの判定式は、上限を801回転から1214回転+残保4個分で設定しています。
    # 試行回数
    loop = 10000

    # 前回大当たりからの通常ゲーム数を入れる
    ゲーム数 = 1
    
    #ループ処理(loopで設定した回数だけシミュレーションを行う。)
    for i in range(loop):
    # 250発あたりの回転数から、1回転に必要な玉数を算出して減算
    Total = Total - (250 / Border)

    # 遊タイムの処理
    if 800 < ゲーム数 < 801 + 1214 + 4:
        # 801回転から1214回転+残保4個分は遊タイムになるので、右打ち中のボーダーで計算する。
        Total = Total + (250 / Border) - (250 / Border_ST)

    # 乱数の取得
    rand = random.randint(1,65536)

    # ここから当り判定+連荘処理を記載

1.2. 大当たり振り分けの違い

本機種は左打ちと右打ちで大当たり時ののラウンド振り分けが異なります。
つまり、通常時と遊タイム中で大当たり時のラウンド振り分けが異なるということですね。
具体的には、大当たりに当選した場合に、先ほどと同じく遊タイム中か否かを判定し、大当たり振り分けを変更しています。
最後にゲーム数をリセットしておくのも重要です。
リセットしておかないとはまってもいないのに遊タイムに突入してしまいます。
    # 当り判定+連荘処理
    if 左4RST範囲_下 <= rand <= 左4RST範囲_上:
        # 大当たりを引いた時の処理

        # 大当たりで獲得した玉数を加算(アタッカーに入れた玉数は減算する)
        # 遊タイム中か否かでラウンド数が異なるのでif分で条件分岐する
        # 遊タイム中のとき
        if 800 < ゲーム数 < 801 + 1214 + 4:
            # ラウンド振り分けを7:3にするために1~10の乱数を生成する
            rand3 = random.randint(1, 10)
            # 10Rの振り分けだったとき
            if 1 <= rand3 <= 7:
                Total = Total + 1500 - 10 * 10
            # 4Rの振り分けだったとき
            else:
                Total = Total + 400 - 4 * 10
        # 通常時(遊タイム以外)のとき
        else:
            Total = Total + 400 - 4 * 10
        
        # 大当たりしたのでゲーム数を0に戻す
        ゲーム数 = 0

        # ここからSTの処理

2. STのコーディング

ST機のシミュレーションを行うのも初めてのような気がしますので、一応どのようなプログラムを組んだのか説明しておきます。
STはSpecial Time機の略で、規定回数の間は高確率状態に制御されるような機能です。
ということでこんな感じで処理してみました。
While文を用いて規定回数到達までループを回しつつ、大当たり時はゲーム数をリセットしています。
    # STは154回転(残保込み)なので、154回転までループする
    while ゲーム数_ST <= 154:
        # 250発あたりの回転数から、1回転に必要な玉数を算出
        # 1回転ごとに使った玉数を減らしていく
        Total = Total - (250 / Border_ST)

        # 乱数の取得
        rand2 = random.randint(1,65536)
        # 10Rの振り分けだったとき
        if 右10RST範囲_下 <= rand2 <= 右10RST範囲_上:
            Total = Total + 1500 - 10 * 10
            ゲーム数_ST = 0
        # 4Rの振り分けだったとき
        elif 右4RST範囲_下 <= rand2 <= 右4RST範囲_上:
            Total = Total + 400 - 4 * 10
            ゲーム数_ST = 0
        # はずれのとき
        else:
            ゲーム数_ST = ゲーム数_ST + 1

3. 今回作成したコード

最終的には以下のようなコードを作成しました。
もし遊タイムがなかったらどのようなスランプグラフになるのか確認するために、遊タイム有無それぞれで差玉数を計測しています。
また、いつものようにグラフ表示を行っていますが、遊タイム期間だけグラフの背景の色を変更してわかりやすくしています。
    # coding: UTF-8
    # 乱数作成用
    import random
    # スランプグラフ描画用
    import matplotlib.pyplot as plt
    import pylab
    
    # 試行回数
    loop = 10000
    # 1k(250玉)あたりの回転数(左打ち)
    Border = 18
    # 1k(250玉)打って何発残るか(右打ち)。今回は10%減→90%残る仮定で計算
    Border_ST = 250 * 0.90
    
    # 大当たり確率の設定(左打ち)
    左4RST = 319.6 / 1.00
    
    # 乱数範囲の設定準備(左打ち)
    左4RST範囲 = round(65536 / 左4RST)
    
    # 乱数範囲の設定(左打ち)
    左4RST範囲_下 = 1
    左4RST範囲_上 = 左4RST範囲_下 + 左4RST範囲 - 1
    
    # 大当たり確率の設定(右打ち)
    右10RST = 99.9 / 0.70
    右4RST = 99.9 / 0.30
    
    # 乱数範囲の設定準備(右打ち)
    右10RST範囲 = round(65536 / 右10RST)
    右4RST範囲 = round(65536 / 右4RST)
    
    # 乱数範囲の設定(右打ち)
    右10RST範囲_下 = 1
    右10RST範囲_上 = 右10RST範囲_下 + 右10RST範囲 - 1
    右4RST範囲_下 = 右10RST範囲_上 + 1
    右4RST範囲_上 = 右4RST範囲_下 + 右4RST範囲 - 1
    
    # 結果用の箱やカウンタの準備
    Result_遊タイム有 = [] # グラフ描画用に1回転ごとの差玉を入れる(遊タイムがある場合)
    Result_遊タイム無 = [] # グラフ描画用に1回転ごとの差玉を入れる(遊タイムがない場合)
    Total_遊タイム有 = 0   # トータルの差玉を入れる(遊タイムがある場合)
    Total_遊タイム無 = 0   # トータルの差玉を入れる(遊タイムがない場合)
    ゲーム数 = 1    # 前回大当たりからの通常ゲーム数を入れる
    ゲーム数_トータル = 1    # ST中を含めた全てのゲーム数を入れる(グラフ用)
    遊タイム中 = []  # グラフで遊タイム中の背景色を変えるための配列(グラフ用)
    初当たり回数 = 0  # 初当たり回数のカウント(結果表示用)
    
    #ループ処理(loopで設定した回数だけシミュレーションを行う。)
    for i in range(loop):
        # 250発あたりの回転数から、1回転に必要な玉数を算出して減算
        # 1回転ごとに使った玉数を減らしていく(遊タイム有無で差は出ない)
        Total_遊タイム有 = Total_遊タイム有 - (250 / Border)
        Total_遊タイム無 = Total_遊タイム無 - (250 / Border)
    
        # 乱数の取得
        rand = random.randint(1,65536)
    
        # 遊タイムの処理
        if 800 < ゲーム数 < 801 + 1214 + 4:
            # 801回転から1214回転+残保4個分は遊タイムになるので、右打ち中のボーダーで計算する。
            Total_遊タイム有 = Total_遊タイム有 + (250 / Border) - (250 / Border_ST)
            # 遊タイム無の場合は、そのまま
            Total_遊タイム無 = Total_遊タイム無
    
            # 遊タイム期間の保存(グラフ用)
            if ゲーム数 == 801:
                遊タイム中.append(ゲーム数_トータル)
            if ゲーム数 == 800 + 1214 + 4:
                遊タイム中.append(ゲーム数_トータル)
    
        # 当り判定+連荘処理
        if 左4RST範囲_下 <= rand <= 左4RST範囲_上:
            # 大当たりを引いた時の処理
    
            # 大当たりで獲得した玉数を加算(アタッカーに入れた玉数は減算する)
            # 遊タイム中か否かでラウンド数が異なるのでif分で条件分岐する
            # 遊タイム中のとき
            if 800 < ゲーム数 < 801 + 1214 + 4:
                # ラウンド振り分けを7:3にするために1~10の乱数を生成する
                rand3 = random.randint(1, 10)
                # 10Rの振り分けだったとき
                if 1 <= rand3 <= 7:
                    Total_遊タイム有 = Total_遊タイム有 + 1500 - 10 * 10
                    # 遊タイム無の場合はヘソの4R振り分けになる
                    Total_遊タイム無 = Total_遊タイム無 + 400 - 4 * 10
                    # 当たった時のゲーム数を表示
                    print(ゲーム数, "遊10RST")
                    # 初当たり回数のカウント
                    初当たり回数 = 初当たり回数 + 1
                # 4Rの振り分けだったとき
                else:
                    Total_遊タイム有 = Total_遊タイム有 + 400 - 4 * 10
                    # 遊タイム無の場合はヘソの4R振り分けになる
                    Total_遊タイム無 = Total_遊タイム無 + 400 - 4 * 10
                    # 当たった時のゲーム数を表示
                    print(ゲーム数, "遊4RST")
                    # 初当たり回数のカウント
                    初当たり回数 = 初当たり回数 + 1
                # 遊タイム期間の保存(グラフ用)
                遊タイム中.append(ゲーム数_トータル)
    
            # 通常時(遊タイム以外)のとき
            else:
                Total_遊タイム有 = Total_遊タイム有 + 400 - 4 * 10
                # 遊タイム無の場合はヘソの4R振り分けになる
                Total_遊タイム無 = Total_遊タイム無 + 400 - 4 * 10
                # 当たった時のゲーム数を表示
                print(ゲーム数, "左4RST")
                # 初当たり回数のカウント
                初当たり回数 = 初当たり回数 + 1
            Result_遊タイム有.append(Total_遊タイム有)
            Result_遊タイム無.append(Total_遊タイム無)
    
            # 大当たりしたのでゲーム数を0に戻す
            ゲーム数 = 0
    
            # STの処理
            # ST中のゲーム数をカウント
            ゲーム数_ST = 1
    
            # STは154回転(残保込み)なので、154回転までループする
            while ゲーム数_ST <= 154:
                # 250発あたりの回転数から、1回転に必要な玉数を算出
                # 1回転ごとに使った玉数を減らしていく(遊タイム有無で差は出ない)
                Total_遊タイム有 = Total_遊タイム有 - (250 / Border_ST)
                Total_遊タイム無 = Total_遊タイム無 - (250 / Border_ST)
    
                # 乱数の取得
                rand2 = random.randint(1,65536)
                # 10Rの振り分けだったとき
                if 右10RST範囲_下 <= rand2 <= 右10RST範囲_上:
                    Total_遊タイム有 = Total_遊タイム有 + 1500 - 10 * 10
                    # 遊タイム有無で差は出ない
                    Total_遊タイム無 = Total_遊タイム無 + 1500 - 10 * 10
                    print("-", ゲーム数_ST, "10R")
                    ゲーム数_ST = 0
                # 4Rの振り分けだったとき
                elif 右4RST範囲_下 <= rand2 <= 右4RST範囲_上:
                    Total_遊タイム有 = Total_遊タイム有 + 400 - 4 * 10
                    # 遊タイム有無で差は出ない
                    Total_遊タイム無 = Total_遊タイム無 + 400 - 4 * 10
                    print("-", ゲーム数_ST, "4R")
                    ゲーム数_ST = 0
                # はずれのとき
                else:
                    ゲーム数_ST = ゲーム数_ST + 1
    
                Result_遊タイム有.append(Total_遊タイム有)
                Result_遊タイム無.append(Total_遊タイム無)
                # ゲーム数をカウント(グラフ用)
                ゲーム数_トータル = ゲーム数_トータル + 1
    
        else:
            # はずれたときの処理
            # 玉数をそのまま配列に格納
            Result_遊タイム有.append(Total_遊タイム有)
            Result_遊タイム無.append(Total_遊タイム無)
    
        # 前回大当たりからのゲーム数をカウント
        ゲーム数 = ゲーム数 + 1
    
        # ゲーム数をカウント(グラフ用)
        ゲーム数_トータル = ゲーム数_トータル + 1
    
    # 結果の表示
    pylab.plot(Result_遊タイム有, label = "遊タイム有")
    pylab.plot(Result_遊タイム無, label = "遊タイム無")
    pylab.legend(loc='upper left', prop={"family":"MS Gothic"})
    
    # 遊タイム中はグラフの背景の色を変える
    イテレータ = iter(遊タイム中)
    for start, end in zip(イテレータ, イテレータ):
        pylab.axvspan(start, end, color="magenta", alpha=0.3)
    
    print("初当たり確率:", round(loop / 初当たり回数, 0), "(初当たり:", 初当たり回数, "回)")
    print("遊タイム有:", round(Total_遊タイム有, 0), "(玉)")
    print("遊タイム無:", round(Total_遊タイム無, 0), "(玉)")
    print("遊タイム有無の差:", round(Total_遊タイム有, 0) - round(Total_遊タイム無, 0), "(玉)")
    
    pylab.show()
    plt.show()

4. 結果の確認

ここから作成したコードの結果を確認していきます。
とりあえず通常時を10000回転回したときの結果を2つほどピックアップしてみました。
いずれも初当たり確率1/312と確率分母よりちょっと引けてるレベルです。
グラフ上のピンクで囲まれた期間が遊タイム突入期間です。


当然ですが、遊タイムにいた期間が長いほど、遊タイム有無での出玉の差が大きくなっています。
10000回転というのは、1日2000回転程度回せるとするとざっくり5日くらいの回転量になりますが、場合によっては2万発も差が出てしまうんですね。
右側のグラフはブログ用にわざとインパクトのあるグラフを持っては来ましたが、現実に起こるかもしれないと考えると、遊タイムのおかげでかなり救済してもらえているのがわかります。


にほんブログ村 パチンコブログ パチンコ情報へ
にほんブログ村

コメント

このブログの人気の投稿

【WEBアプリ】Sキングハナハナ-30のベル確率予想&ベル確率逆算ツール&設定判別ツール

【WEBアプリ】ハナハナホウオウ天翔のベル確率を差枚数から逆算するツール

【WEBアプリ】ハナハナホウオウ天翔の設定判別ツール