ピクミンブルームでデコピクミンをコンプリートするまでにかかる苗取得回数の分布を求めるためのシミュレーションプログラムを作りました。
レアレストランなどの不均一な確率のデコや、複数デコピクミンをゲットするまでの回数を求めるのにも対応済みです。ご自由にお使いください。
コンプリートまでの苗取得回数計算プログラム
不均一な確率分布に対応したものをまず書きます。
※ただし、プログラムのrandom前後の書き方からか、平均は1前後少なく出るようです。均一な確率の場合は後者のプログラムもおすすめ
プログラム
言語はPython。コピペしてご自由にお使いください。
import numpy as np
import collections
import matplotlib.pyplot as plt
import random
pdist = [1/7]*7 #ピクミン入手確率の偏り
want = [2]*7 #欲しいピクミンの種類と数
lim=80 #苗の入手回数の上限値
NN=N=100000 #試行回数
Type=len(pdist)
hantei = [0]*Type
Pik=[0]*Type
for m in range(0,Type):
Pik[m] = -want[m]
cumpdist=[0]*(Type+1)
count=0
sum=cump=0
c=[0]*(lim+1)
for i in range (0,Type):
cump += pdist[i]
cumpdist[i] = cump
while N>0:
for j in range(1,lim+1):
for k in range(0,Type):
if cumpdist[k-1] <= random.random() < cumpdist[k]:
Pik[k] += 1
count=count+1
if min(Pik) >= 0:
sum=sum+count
if count <= lim:
c[count] += 1
if N < 101:
print(count,"回、", [Pik[x]+want[x] for x in range(0,Type)])
break
for m in range(0,Type):
Pik[m] = -want[m]
count=0
N=N-1
print()
print("●",Type,"種類")
print("平均",sum/NN,"回")
Xaxis=list(range(0,lim+1))
plt.xticks(np.arange(0, lim+1, step=10)) #stepは適宜変更
plt.grid(linestyle="--")
plt.bar(Xaxis,[x/NN for x in c])
plt.show()
y=[x/NN for x in c]
z=[0]*(lim+1)
psum=0
for i in range(0,lim+1):
psum += y[i]
z[i] = psum
plt.plot(Xaxis, z)
plt.xticks(np.arange(0, lim+1, step=10)) #stepは適宜変更
plt.yticks(np.arange(0, 1.1, step=0.1))
plt.grid(linestyle="--")
plt.show()
パラメータについて
pdist = [1/7]*7 #ピクミン入手確率の偏り
:これは7種デコですべて1/7の場合。4種デコなら[1/4, 1/4, 1/4, 1/4] 、レアレストランなら [(1-p)/7,(1-p)/7,(1-p)/7,1/7,1/7,1/7,1/7,p/7,p/7,p/7] (この場合、pdistの前の行にp=0.15などと書く)とすればOKwant = [2]*7 #欲しいピクミンの種類と数
:これは7種デコをすべて2匹欲しい場合。
[2, 2, 2, 1, 1, 1, 1] なら赤黄青2匹、紫白岩羽1匹欲しいという意味になるlim=80 #苗の入手回数の上限値
:これを超える数の苗入手およびグラフ描画は行われないNN=N=100000 #試行回数
:データサンプル数。何人が上の条件で実験するかを示す値。大きいほどデータの精度が高いが、実行時間が長い。少ないとデータの精度が良くないが、実行時間は短い。1万~100万くらいが目安
出力結果
- コンプリートした時の所持デコの偏り例100個 + データサンプル数での平均
(長いので下の例では10個のみ表示。プログラムのNを弄れば個数変更可能) - 回数ごとの確率分布のグラフ
- 「何回以内にコンプできたか」を示す累積分布グラフ
が下のように出力されます。今回は「7種デコを全2種類ゲットするまでの回数の分布」です。
※プログラムのrandom前後の書き方からか、平均は1前後少なく出るようです。
クーポン出現確率が一様な場合のプログラム
※本プログラムは、外部Qiita記事クーポンコレクター問題:どうぶつの森で73種類の化石コンプリートには何日かかる?を参考に、パラメータ等を変更して作成しております。
最初のプログラムと違い、苗取得平均回数が正確です。ただしレアレストランなどの、不均一な確率分布には対応しておりません。
プログラム
import numpy as np
import collections
import matplotlib.pyplot as plt
import random
def get_days(k):
fossil_list = [0]*k #最初のクーポン所持数
days = 0
while min(fossil_list) < 2: #クーポンが全部x個以上になったら完了
num_fossil_per_day = 1
for i in range(num_fossil_per_day):
fossil_list[random.randint(0, k - 1)] += 1
days += 1
return days
# かかった日数をnum回取得して分布を取得する。numが大きいほど分布は正確になる
def days_plot(k=73, num=10000):
days = [get_days(k) for i in range(num)]
c = collections.Counter(days)
key = list(c.keys())
value = list(c.values())
left = np.array(key)
height = np.array(value) / sampling_num
plt.title('number of samples: {}'.format(num))
plt.xlabel('number of days for complete')
plt.ylabel('probability')
plt.bar(left, height)
plt.show()
print("平均:", sum(left*height))
# クーポンの種類数
k = 7
# データサンプル数
sampling_num = 100000
# 横軸が日数、縦軸が N日目に初めてコンプリートする確率分布
days_plot(k, sampling_num)
パラメータ
k = 7 # クーポンの種類数
fossil_list = [0] * 7 #最初のクーポン所持数
:最初に持っているクーポンの数と種類。[0]が数、*7が種類にあたる。例えば14種類なら[0] * 14
と書き換えwhile min(fossil_list) < 1: #全クーポンがすべてx個以上に達したら条件達成
:クーポンを何個手に入れることを目標としているか。例えば全種類2個以上欲しいなら、
while min(fossil_list) < 2
と書き換えsampling_num = 100000 # データサンプル数
:何回分のデータを取るか。1万~100万くらいがちょうどいい。上げるとデータの精度が良くなるが、計算時間がかかる。下げると計算は早いが精度が下がり、グラフが滑らかでなくなる
その他の記法について
例えば同時に
fossil_list = [-3,-2,-1,0,0,0,0]
while min(fossil_list) < 0:
と書き換えると、7種のクーポンABCDEFGのうち、Aを3個、Bを2個、Cを1個ゲットするまでの回数を求められる。fossil_list
の内部の数は欲しい数にマイナスをつけたものであること。
出力結果
上の書き方の場合、「7種デコを全2種類ゲットするまでの回数の分布」が、
- ある回数でゲットできる確率の分布を表すグラフ
- データサンプル数の平均
で下のように出力されます。データサンプル数の平均は最初の偏った確率のクーポンコレクターと違い、正確なはずです。sampling_num
を大きくするほど精度が良くなります。
前者のプログラムよりも少し平均が多いですね。値としてはこちらの方が正確です。
参考
・コンピューターシミュレーション(外部Qiita):
クーポンコレクター問題:どうぶつの森で73種類の化石コンプリートには何日かかる?
ピクミンブルーム デココンプ回数の分布表と偏りについて【クーポンコレクター問題】
クーポンコレクター問題の理論的な解やグラフ、分布関数などを出力するプログラム
不均一な確率分布のクーポンコンプに必要な平均回数計算プログラム【クーポンコレクター問題】
コメント