ぱちんこシミュレータを作りたい

本プログラム群は下記にて公開しています。

**PyPachinko**
[https://github.com/Amanohara/PyPachinko](https://github.com/Amanohara/PyPachinko)

# TL;DR
①概要 
・ぱちんこの抽せんプログラムを作成して例えば1万回転行った時の出玉収支を求めたい 

②目標
・好きな機種や気になる機種のスペックや任意のベースを設定して、甘いのか辛いのか等を見てみたい。
・「こういうスペック(確変ループやV-STとかラウンド振り分け)だったらよかったのに。。」と言うのを実際に再現してみたい。
　（試験に適合するのか等も含めて）

③課題
・スペックの種類が数多あってフォーマットを統一できない

# はじめに

**「○○は甘いらしい」「○○は辛い！ゴミ！」**という意見をよくネットで見ます。

本当か？と思い、実際に打ちに行って後悔することがかなりありました。




この後悔を糧に、任意のぱちんこ機種をプログラムで再現してシミュレーションしてみたい！と思ったのがきっかけです。

# 手法

今は下記のように考えています。

1. スペックを大別して、①確変ループ機 ②V-ST機 ③1種2種混合機 ④転落機 に分類してそれぞれ汎用的なプログラムを作成する
1. これらの汎用プログラムに、再現してみたい機種の情報（大当たり分母、時短回数、振り分け等）が記載された詳細プログラムをアタッチさせる
1. **（未完成）**1万回回して、出玉の収支具合を出力させる

## 例
たとえば、最初に再現したかったCRF戦姫絶唱シンフォギアは、1種2種混合機です。
まず、1種2種混合機の汎用プログラムを以下のように書いてみました。

```python
import random
import pandas as pd
import sys
from machine import symphogear as machine

'''
1種2種混合機
'''

def main(*args):
    normal, koukaku, tokuzu1, tokuzu2 = machine.information()
    # 試行回数
    challenge = int(args[1])
    # 確認
    print("低確率：1/" + str(normal))
    print("高確率：1/" + str(koukaku))
    # 乱数設定
    heso, denchu = random_select(normal, koukaku)
    # ラムクリア
    kaiten, kaiten_sum, mode = ram_clear()
    # 大当たり表の枠作成
    result = create_flame()
    # ここから抽せん開始。。
    for i in range(0, challenge):
        # 高確率か低確率か最終決戦中かを判定する
        if mode == "normal":
            kekka = chusen_normal(heso)
        elif mode == "koukaku":
            kekka = chusen_koukaku(heso, denchu, kaiten, tokuzu2)
        else:
            # 最終決戦(搭載機による)
            kekka = chusen_fine(denchu, kaiten, tokuzu1)
        # 0ははずれ。何もせずに回転数を足す
        # 1は特図1での大当たり。電サポをtokuzu1回す
        # 2は特図2での大当たり。電サポをtokuzu2回す
        # 9は左打ちに戻す
        if kekka == 0:
            # はずれ
            kaiten = kaiten + 1
            kaiten_sum = kaiten_sum + 1
        elif kekka == 1:
            # 特図１での大当たり。振り分け判定。
            furiwake = machine.furiwake_heso()
            # 回転数を記録後、リセット
            record = pd.Series([kaiten, furiwake, kaiten_sum], index=result.columns)
            result = result.append(record, ignore_index=True)
            kaiten = 0
            kaiten_sum = kaiten_sum + 1
            '''
            時短突入抽せん
            0はシンフォギアスペック(突破型）
            1は時短突入率で判定かつ当せん
            2は時短突入率で判定かつ通常
            ''' 
            migiuchi = machine.migiuchi_judge(furiwake)
            if migiuchi == 0:
                # 最終決戦突入。ただし振り分けで1％を引くと高確率直行
                if furiwake != "全回転":
                    mode = "fine"
                else:
                    mode = "koukaku"
            elif migiuchi == 1:
                # 時短突入
                mode = "koukaku"
            else:
                # 通常
                mode="normal"
        elif kekka == 2:
            # 特図2大当たり。振り分け判定。
            furiwake = machine.furiwake_denchu()
            # 回転数を記録後、リセット
            record = pd.Series([kaiten, furiwake, kaiten_sum], index=result.columns)
            result = result.append(record, ignore_index=True)
            kaiten = 0
            kaiten_sum = kaiten_sum + 1
            # 次回も高確率
            mode = "koukaku"
        else:
            # kekka==9を想定。不承不承ながら左打ち
            mode = "normal"
    result.to_csv("result.csv", index=None)


def ram_clear():
    # ラムクリア
    kaiten = 0
    kaiten_sum = 0
    mode = "normal"
    return kaiten, kaiten_sum, mode


def random_select(normal, koukaku):
    # 乱数設定を行う。大当たり確率は65536個中のX個で決定している。
    heso_ran = 1 / normal * 65536
    heso_ran = int(heso_ran)
    denchu_ran = 1 / koukaku * 65536
    denchu_ran = int(denchu_ran)
    # 乱数生成
    a = list(range(0, 65536))
    heso_atari = random.sample(a, heso_ran)
    denchu_atari = random.sample(a, denchu_ran)
    return heso_atari, denchu_atari


def create_flame():
    # Pandasフレームの作成
    cols = ['回転数', '大当たり', '総回転数']
    df = pd.DataFrame(index=[], columns=cols)
    return df


def chusen_normal(tokuzu1):
    # 特図１での抽せん
    lottery = random.randint(0, 65536)
    if lottery in tokuzu1:
        # 大当たり
        result = 1
    else:
        # はずれ
        result = 0
    return result


def chusen_koukaku(tokuzu1_atari, tokuzu2_atari, kaiten, limit):
    # 特図2での抽せん
    if kaiten <= limit:
        lottery = random.randint(0, 65536)
        if lottery in tokuzu2_atari or lottery in tokuzu1_atari:
            # 大当たり
            result = 2
        else:
            # はずれ
            result = 0
    else:
        # 左打ちに戻す信号を送る
        result = 9
    return result


def chusen_fine(tokuzu2_atari, kaiten, limit):
    # 最終決戦中の扱い
    if kaiten <= limit:
        lottery = random.randint(0, 65536)
        if lottery in tokuzu2_atari:
            # 大当たり
            result = 2
        else:
            # はずれ
            result = 0
    else:
        # 左打ちに戻す信号を送る
        result = 9
    return result


if __name__ == '__main__':
    args = sys.argv
    if len(args) < 1:
        print("Error.\n<Usage>\npython3 1+2mix.py 試行回数")
    else:
        main(*args)
```

ここの`from machine import symphogear as machine`は詳細スペックの呼び出しです。
下記の通りに設定しています。

```python
import random

'''
1種2種混合機
CRF戦姫絶唱シンフォギア
'''

def main():
    pass

def information():
    # 特図1での大当たり確率[1/n]
    normal = 199.8
    # 特図2での小当たり確率[1/n]
    koukaku = 7.4
    # 特図1当せん時の電サポ回数[回]
    tokuzu1 = 5
    # 特図2当せん時の電サポ回数[回]
    tokuzu2 = 11
    return normal, koukaku, tokuzu1, tokuzu2


def furiwake_heso():
    # シンフォギアの特図１の振り分けは99%が通常。1%は右打ち直行
    a = random.randint(0, 100)
    if a != 50:
        heso = "4R"
    else:
        heso = "全回転"
    return heso


def furiwake_denchu():
    # ここはラウンド振り分け。
    # シンフォギアは4Rが50%,8Rが7%,12Rが3%,15Rが40%
    a = random.randint(0, 100)
    if a < 50:
        denchu = "4R（確変）"
    elif a >= 50 and a < 57:
        denchu = "7R（確変）"
    elif a >= 57 and a < 60:
        denchu = "12R（確変）"
    else:
        denchu = "15R（確変）"
    return denchu

def migiuchi_judge(heso):
    # 確変突入率のジャッジ
    # シンフォギアは100%右打ち
    judge = 0
    return judge

if __name__ == '__main__':
    main()
```

現在は回転数とラウンド振り分けのみをまとめた出力した表を結果として出しています。


# 今後やりたいことや課題

## 電サポ回数の振り分け
これはどうにかすればできると思います。今は通常を引いた場合は時短なしにしているので修正したいです。

## 出玉収支を求めたい（≒ベースを設定したい）
出玉収支を求めるには、賞球情報とベースが分かれば計算できます。あとは一般入賞口への入り具合等ですね。
（ベースは125玉20回転ならば、1回転当たり6.25玉必要と求められます。）

## 遊タイム（B時短）を再現したい
これが面倒くさい。。
たとえば、1種2種混合機のB時短は特図２での小当たり確率（と大当たり確率）を抽せんします。
それ以外にもB時短からの当せんは特典が付いたり等、特殊なパターンが多すぎてパターンを統一できない（＝汎用プログラムに再現できない）でいます。。

## 特殊スペックの再現が難しい
たとえばPF機動戦士ガンダムUCとかの3000FEVERは255回転落小当たりを引くまで時短が続きます。
これを再現するのも難しいです。汎用+詳細体制だと、ここら辺が厳しくなります。
餃子の王将3を再現する方が楽です。


#さいごに
+ まだまだ前途多難ですが、分母内に当たる確率を数えると63%付近に収束するのが面白いです。
+ アドバイス等あればご教授ください！是非活用させていただきます！
+ 好きな機種はスロットなら主役は銭形、ぱちんこなら乙女フェスティバルです。後者の続編を早く見たい。。