見出し画像

真・ガチャ軍資金調査プログラム

皆さまこんにちは、いぬころんです。

前回、トレカのフルコンプ軍資金調査のプログラムを作りましたが、
スマホゲーム等のガチャではどうなのかがどうしても気になり、
また暇人モードを発動してプログラミングしてみました。

概要

一般的にスマホゲームのガチャでは
「期間限定キャラ」や「イベントで新登場のキャラ」が
そのガチャの当たり枠の中でもやや出現確率が高くなります。
例えば、いぬころんもプレイしている「プロセカ」では
最高レア度の「☆4」キャラ全体の出現確率は「3%」ですが、
☆4のキャラごとに見てみると、新登場のキャラのみ
他の☆4キャラに比べて確率が高く設定されています。

一般的にガチャを引くというのは
この新登場のキャラをゲットするために引くことになるでしょう。

そこで今回のプログラムは、確率が優遇されている
期間限定や新登場キャラを全てゲットする為に、
どれだけガチャればいいかを検証するものになっています。

ファイルダウンロード

仕様

事前に設定できる項目は以下のとおりです。
①ピックアップキャラの種類数
②各ピックアップキャラの名前
 ⇨各調査ごとの結果欄で被りがあるか確認できます。
③出現確率
 ⇨ピックアップキャラ・その他の当たりキャラ・ハズレ
 それぞれの出現回数がわかります。
 (※確率は「%」数で指定できます。自然数でも少数でもOKです。)
 (※少数の場合、小数点以下第4位以降を入力すると、
  小数点以下第3位までで四捨五入されます。【例】1.2345%▶1.235%)
④ガチャに必要な石の数や石の金額
 ⇨一回のガチャに必要な石の数、今持っている石の数
  ならびに石を購入するための必要金額を設定できます。
  今持っている石を使い切ったあとに必要であれば課金して
  ガチャを引いていくというシミュレーションになっています。
 (※石の金額に関しては一通りの設定しかできないので、
  一番お得な組み合わせで設定していただくことをおすすめします。
  【例】プロセカの場合「10000円で10500個」)
⑤シミュレーション回数
 ⇨指定した回数シミュレーションを行い、
  最終的にその平均データが表示されます。
  指定した回数が多いほど有用性のあるデータになると思いますが、
  当然その分結果の処理に時間がかかります。
 (※パソコンのスペックによると思いますが、
  10000回程度であれば1,2分程度で終わると思います。)

サンプル画面


情報入力画面
結果画面

ソースコード

今回は関数表記を使ってみました。
どの部分をパーツ化して関数に分けるのが良いかは判断次第ですが、
例えば、似た機能を作ると言う場合は
関数をコピーして中身を少し触るだけでも出来上がるので、
できるだけ細かく分けて作っておいたほうがいいのかなぁと感じます。

import random


# エラーメッセージの関数


def numerror():
    print("数字を入力してください。")

def minuserror():
    print("正の数を入力してください。")

def stoneminuserror():
    print("石の数は自然数を入力してください。")

def interror():
    print("整数を入力してください。")

def nullerror():
    print("入力されていません。")


def probaberror():
    print("出現確率の数値が異常です。")

def duplication():
    print("既に入力された名前です。\n"
          "入力し直してください。")


# 基本設定部分の入力に関する関数


def quant():
    while True:
        num = input("ピックアップキャラは何種類ですか?▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        quantity = int(num)
        break

    return quantity

def pickupname(listnum):
    while True:
        name = input(str(listnum) + "人目のピックアップキャラの\n"
                                    "名前を入力してください。▶")
        if name:
            return name
        else:
            nullerror()
            continue

def probab(reality):
    while True:
        num = input(str(reality) + "の出現確率を入力してください。(単位は%・小数第3位まで可)▶")
        if num:
            try:
                float(num)
            except ValueError:
                numerror()
                continue
        else:
            nullerror()
            continue
        probab = round(float(num), 3)
        if probab > 100:
            probaberror()
            continue
        if probab<=0:
            minuserror()
            continue
        break
    return probab

def jewelry():
    while True:
        num = input("単発1回のガチャに必要な石の数を入力してください。(整数のみ)▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        jewelry = int(num)
        if jewelry<=0:
            minuserror()
            continue
        break
    return jewelry

def defaultjewelry():
    while True:
        num = input("今持っている石の数を入力してください。(整数のみ)▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        defaultjewelry = int(num)
        if defaultjewelry<0:
            stoneminuserror()
            continue
        break
    return defaultjewelry

def jewelryprice():
    print("石の値段を入力してください。")
    while True:
        num = input("金額(数字だけ入れてください)▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        price = int(num)
        if price<=0:
            minuserror()
            continue
        break

    while True:
        num = input("個数(数字だけ入れてください)▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        quantity = int(num)
        if quantity<=0:
            minuserror()
            continue
        break
    return [price, quantity]

def kaisuusitei():
    while True:
        num = input("シミュレーション回数を指定してください。(整数のみ)▶")
        if num:
            try:
                int(num)
            except ValueError:
                interror()
                continue
        else:
            nullerror()
            continue
        specify = int(num)
        if specify<=0:
            minuserror()
            continue
        break
    return specify


# ガチャ機能

def gacha(pool):
    result = random.choice(pool)
    return result

# ==============================以上関数==============================
# ==============================以下本体==============================
print("いぬころんのガチャフルコンプシミュレーションへようこそ!")
#####基本情報入力#####
# ①ピックアップキャラは何種類かを指定する
while True:
    quantity = quant()
    if quantity <= 0:
        minuserror()
        continue
    break

# ②ピックアップキャラの名前を指定・リスト化
pickuplist = []
pickuplist_index = 0

while True:
    pickcharacter = pickupname(pickuplist_index + 1)
    if pickuplist.count(pickcharacter) > 0:
        duplication()
        continue
    pickuplist.append(pickcharacter)
    pickuplist_index = pickuplist_index + 1
    if pickuplist_index == quantity:
        break
print("ピックアップキャラは" + str(pickuplist) + "の" + str(quantity) + "種で設定されました。")

# ③各レアリティのキャラの出現確率を定義
realitylist = ["各ピックアップキャラ", "ピックアップキャラを含む最高レア全体", "最高レア以外"]
probabilitylist = []
index = 0
while True:
    if index == 0:
        while True:
            probability = probab(realitylist[index])
            if probability >= 100:
                probaberror()
                continue
            probabilitylist.append(round(probability, 3))
            break
    if index == 1:
        while True:
            probability = round(probab(realitylist[index]) - probabilitylist[0] * quantity, 3)
            if probability < 0:
                probaberror()
                continue
            probabilitylist.append(probability)
            break
    if index == 2:
        probability = round(100 - probabilitylist[0] * quantity - probabilitylist[1], 3)
        probabilitylist.append(probability)
    if index == 3:
        break
    index = index + 1

index = 0
provide = [probabilitylist[0], probabilitylist[1] + probabilitylist[0] * quantity, probabilitylist[2]]
while True:
    print(realitylist[index] + ":" + str(provide[index]) + "%")
    index = index + 1
    if index == len(provide):
        print("以上の出現確率に設定されました。")
        break

# ④ガチャに必要な石の数を定義
jewelry = jewelry()
print("単発1回のガチャに必要な石の数を" + str(jewelry) + "個に設定しました。")

# ⑤現在持っている石の数を確認
defaultjewelry = defaultjewelry()
print("今持っている石の数を" + str(defaultjewelry) + "個であることを確認しました。")

# ⑥石の値段を設定
jewelryprice = jewelryprice()
print("石の値段は、「" + str(jewelryprice[0]) + "円:" + str(jewelryprice[1]) + "個」で設定しました。")

#####シミュレーションツールの作成#####
# ⑦ガチャ用の抽選プールを作成
print("出現確率の情報をもとにガチャシミュレーション用のリストを作成しています。\n")
gachapool = []
# ピックアップキャラの在庫を抽選プールに投入
pickupstock = probabilitylist[0] * 1000
pickuplist_index = 0
while True:
    times = 0
    while True:
        gachapool.append(pickuplist[pickuplist_index])
        times = times + 1
        if times == pickupstock:
            break
    pickuplist_index = pickuplist_index + 1
    if pickuplist_index == len(pickuplist):
        break
# ピックアップキャラの以外の最高レア度のキャラ在庫を抽選プールに投入
hitstock = probabilitylist[1] * 1000
times = 0
while True:
    gachapool.append("HIT")
    times = times + 1
    if times == hitstock:
        break
# ハズレキャラ在庫を抽選プールに投入
loststock = probabilitylist[2] * 1000
times = 0
while True:
    gachapool.append("LOST")
    times = times + 1
    if times == loststock:
        break

# ⑧回数指定と開始宣言
print("ガチャシミュレーターの用意ができました。")
specify = kaisuusitei()
input("ピックアップキャラは名前\n"
      "ピックアップキャラ以外の最高レアのキャラは「HIT」\n"
      "最高レア以外のキャラは「LOST」で表示されます。\n"
      "「Enter」を押して開始します。")

#####シミュレーション開始#####

# ⑨シミュレーション開始

survey_times = 0
gacha_times_list = []
used_money_list = []

# 指定回数が終わるまで繰り返し
while True:
    remaininglist = []
    index = 0
    while True:
        remaininglist.append(pickuplist[index])
        index = index + 1
        if index == len(pickuplist):
            break
    gachatry = 0
    myjewelry = defaultjewelry
    usedjewelry = 0
    usedmoney = 0
    pickupget = []
    hitget = 0
    lostget = 0

    # ピックアップキャラを全てゲットするまでガチャを引く
    while True:
        if myjewelry < jewelry:
            print("%d円を使ってガチャ石を%d個購入します" % (jewelryprice[0], jewelryprice[1]))
            usedmoney = usedmoney + jewelryprice[0]
            myjewelry = myjewelry + jewelryprice[1]
        myjewelry = myjewelry - jewelry
        usedjewelry = usedjewelry + jewelry
        gachatry = gachatry + 1
        gacharesult = gacha(gachapool)
        print("%5d回目:%sでした。" % (gachatry, gacharesult))
        if pickuplist.count(gacharesult) == 1:
            pickupget.append(gacharesult)
            index = 0
            while True:
                if remaininglist[index] == gacharesult:
                    remaininglist[index] = "fin"
                    break
                index = index + 1
                if index == len(remaininglist):
                    break
            if remaininglist.count("fin") == len(remaininglist):
                break
            continue

        if gacharesult == "HIT":
            hitget = hitget + 1
            continue
        if gacharesult == "LOST":
            lostget = lostget + 1
            continue

    # ⑩結果発表
    print("ピックアップキャラを全てゲットしました!\n"
          "出現結果は以下のとおりです。")
    index = 0
    while True:
        print("%10s:%5d回" % (pickuplist[index], pickupget.count(pickuplist[index])))
        index = index + 1
        if index == len(pickuplist):
            break
    print("%10s:%5d回" % ("HIT", hitget))
    print("%10s:%5d回\n" % ("LOST", lostget))

    print("ガチャ石に関しては以下のとおりです。")
    print("%10s:%d個" % ("使用した石",usedjewelry))
    print("%10s:%d個" % ("購入した石",jewelryprice[1] * (usedmoney / jewelryprice[0])))
    print("%10s:%d円" % ("課金した金額",usedmoney))
    print("%10s:%d個" % ("残っている石",myjewelry))

    gacha_times_list.append(gachatry)
    used_money_list.append(usedmoney)
    survey_times = survey_times + 1
    if survey_times == specify:
        break
    continue

# ⑪情報まとめと通知

# ガチャ回数の平均
index = 0
gacha_all_times = 0
while True:
    gacha_all_times = gacha_all_times + gacha_times_list[index]
    index = index + 1
    if index == len(gacha_times_list):
        break
gacha_ave_times = round(float(gacha_all_times / len(gacha_times_list)), 1)

# 課金額の最大値、最小値、平均
money_max = max(used_money_list)
money_min = min(used_money_list)
index = 0
usedmoneyall = 0
while True:
    usedmoneyall = usedmoneyall + used_money_list[index]
    index = index + 1
    if index == len(used_money_list):
        break
usedmoneyave = round(usedmoneyall / len(used_money_list))

print("これで終了します。\n\n"
      "%s\n"
      "%10d回\n"
      "%s\n"
      "%10d回\n"
      "%s\n"
      "%10d円\n"
      "%s\n"
      "%10d円\n"
      "%s\n"
      "%10d円\n"
      "以上のようになりました。\n"
      "(※小数点以下は四捨五入しています。)\n"
      % ("調査回数",survey_times,"平均ガチャ数", gacha_ave_times,"平均課金額",
         usedmoneyave,"最大課金額", money_max,"最少課金額", money_min))

input("Enterを押して終了します。")

記事をご覧頂きまして、まことにありがとうございます。 「缶コーヒーの差し入れ」くらいの気持ちでサポートをしてくれされば とても励みになります。