ガチャの確率と期待値をプログラミングで求める
概要
ガチャの確率と期待値をプログラミングで求める 主な機能としては
排出率x%でy回まわしたとき1体以上でる確率を求める
そのときの期待値を求める
0~y回までの結果をグラフに表示
アルゴリズム
1体以上でる確率は、y回まわして0体(一回もでない)の確率を1から引けば良いので
もう少し拡張すると
n体以上でる確率は、y回まわしてn-1体までの確率の合計を1から引けば良い
イメージでいうと
0 ・・・ n-1 | n ・・・・ y n-1体まででる確率 + n体以上でる確率(ここを求めたい) =合計1
排出率x%でy回まわしたとき,ちょうどi回でる確率は
なので0~n-1体まででる確率の合計は
なのでn体以上でる確率は
ちなみに0~y体でる確率の合計はすべての可能性なので1になる
また各期待値は、各確率にその時出る回数iをかければ良い。つまり
これをi(0→y) まで足したものが排出率x%でy回まわしたときの期待値
実はこれうまく出来て式を整理すると
x*yになる(二項分布コイン投げから分かる二項分布。正規分布やポアソン分布との関係性と近似について | アタリマエ!
すごい
感覚的にもあってるよね
例えば確率10%で10回したら0.1*1=1体はでそうだよね~って感じ
というわけで期待値の計算は簡単
まとめ
排出率x%でy回まわしたときの排出確率を求めるプログラムを作成
主な機能
- 排出率x%でy回まわしたときz体以上でる確率を求める
- そのときの期待値を求める
- 0~y回までの結果をグラフに表示
今後追加したい機能
* コストの追加(これはガチャを回す回数に消費石、石の値段をかけるだけなので簡単
コードと結果
試しに排出確率0.5%、200回まわしたとき(200連)、1体以上でる確率をグラフで出してみる
200連しても狙ったキャラが排出されるのは65%以下・・・
期待値は0.5x200 = 1なのでちょうど200連すれば1体はでるでしょうという感じ
200連っていうと、オセロニアだと消費石だいたい800個くらい
1個あたり約50円とすると800x0=40000円
4万使ってようやく目的のキャラくるかな~という結果
0.5は高いほうで0.33,0.19とかもざらにある
やっぱ1点狙いが如何に闇で爆死しやすいか、非常にわかりやすい
逆にいえば、排出確率が3~10%になれば、結構でるのだ
3~10%というとA駒だったり、複数のターゲットがあれば実現できる
何が言いたいかというと
ソシャゲのガチャを批判してるのではなく、
ガチャを引くならちゃんと確率を考えて引けば効率いいよ、という話
参考 書いたコード
# -*- coding: utf-8 -*- import math import numpy as np import matplotlib.pyplot as plt import matplotlib import time def c_count(n, r):#nCrを求める return math.factorial(n) // (math.factorial(r)*math.factorial(n - r)) def over_prob(x,y,z): #x% y-1回まわしたとき、z体以上当あたるを確率を求める = 1-sum(0~(z-1)のprob) prob = [] if y < z:#y<z is impossible return 0 else: for i in range(z):#i駒当たる確率 tmp = c_count(y,i) * (x**i) * ((1-x)**(y-i)) prob.append(tmp) return 1- sum(prob) def each_expect(x, y):#x% 0~y-1回まわしたときの各期待値を求める 期待値は二項分布より x*y return (np.arange(y))*x#0~yまでの配列を作成 -> xをかける def over_predict(x, y, z):#x% 0~y-1回まわしたときの 1:z体以上でる確率 2:期待値を格納する all_prob = []#z駒以上排出の確率 for i in range(y): tmp = over_prob(x,i,z) all_prob.append(round(tmp*100,4)) all_expect = each_expect(x, y) return all_prob,all_expect #setting a = 0.5#確率% b = 100# ~連続引いた場合 c = 1#何体以上でる排出率か d = 50/11 #一回まわすのにひつような石 石/回す回数 #main process start = time.time() all_prob,all_expect = over_predict(a/100, b+1, c)#b+1なのは0~b-1->0~bにするため process_time = time.time() - start #result as text print (all_prob, all_expect) print (str(process_time)+'s') print(matplotlib.matplotlib_fname()) #result as graph x = np.arange(0, b+1, 1) y1 = np.array(all_prob) y2 = np.array(all_expect) fs = 15 #fontsize ##graph:1 prob plt.subplot(1,2,1) plt.xlabel('ガチャをまわす回数',fontsize = fs) plt.ylabel('少なくとも'+str(c)+'体 出る確率 (%)',fontsize = fs) plt.plot(x, y1, label=("排出率"+str(a)+"%の場合")) plt.legend() plt.xticks( np.arange(0, b+1, b/10) ) plt.yticks( np.arange(0, 101, 10) ) plt.grid(True) ##graph:2 expect plt.subplot(1,2,2) plt.xlabel('ガチャをまわす回数',fontsize = fs) plt.ylabel('期待値 (コマ数)',fontsize = fs) plt.plot(x, y2, label=("排出率"+str(a)+"%の場合")) plt.legend() plt.xticks( np.arange(0, b+1, b/10) ) plt.grid(True) ##draw graph plt.show()