【星の翼】結局50%募集と100%募集どっちがいいの
この記事を見に来ている人はある程度予備知識を備えていると思うので,単刀直入に本題から入りますが,
「結局50%募集と100%募集どっちを回せばいいの??」
という問を考察していきます.
結論を先出し
結論は以下の通りです
どうしても絶対損したくないって人以外は,50%募集を引こう
排出率が上昇してからは単発の方がチケットの節約になるのでは
募集(ガチャ)の仕様
星の翼の募集は,特定の回数から徐々にキャラの排出率が上昇します.
50%募集では1/2の確率でピックアップキャラ以外の伝説キャラが排出され,二回目に引く伝説キャラはピックアップで確定する仕様です.
$$
\begin{array}{lcc}
& 50\%募集 & 100\%募集\\ \hline
基本の伝説キャラ排出率 (\%) & 0.8 & 0.1 \\
排出率が上昇し始める募集回数 & 40 & 70 \\
伝説キャラが確定で排出される回数(天井) & 70 & 90\\
最終的な排出率 (\%) & 2.4 & 1.3 \\
\end{array}
$$
50%募集は,高確率で伝説キャラや史詩キャラを入手できるが,最大で140回募集しないとピックアップキャラを引けない.
100%募集はピックアップキャラを90回以内に必ず引ける.
というトレードオフ関係があります.
ピックアップキャラを引くまでに必要な募集回数の計算
以上の仕様を踏まえ,ピックアップキャラを引くまでに必要な募集回数の確率を計算していきます.なお排出率がどのように変化するか,運営は公開していないため今回の検討では一次関数として増加すると仮定します.
50%募集 VS. 100%募集
n回目の募集までにピックアップキャラを引く確率を示します.
なお,50%募集はガチャエミュレータ,100%募集は確率計算から求めました.
(50%募集のすりぬけを考慮した確率計算がアホみたいに面倒だったため)
50%募集では一万回伝説キャラが排出されるまでシミュレーションを回しました.
青と赤の四角は天井を表すので,グラフ上は100%未満ですが実際には100%の確率でピックアップキャラを引きます.70回目の不連続な確率の上昇は,70回目が50%募集の一回目の天井だからですね.
考察
さて一目瞭然ですが,すりぬけを考慮しても50%募集の方がピックアップキャラを引ける確率が高いです.70回目までに50%超の確率でピックアップキャラが引けます.
ただし,100%募集では必ず90回以内にピックアップキャラを引けます.
50%募集で90回目までにピックアップキャラが排出される確率は60%強(2/3程度)といったところで,これを高いと見るか低いと見るかは意見が分かれそうですね.
忘れてはいけない点として,50%募集では他にも伝説キャラやその他史詩キャラが排出される確率が非常に高いです.
完凸推奨の低コ(アイーダ,十八号など)も抽選枠に含まれるので,キャラの選択肢を増やせると考えると50%ガチャはかなりお得ですね.
この手のゲームでは操作してみて始めてキャラが手に馴染むようなことも往々にしてあるので,まだキャラがそろっていない始めたての人ほど,50%募集で効率よく沢山のキャラを入手して色んなキャラで遊べるようにした方が星の翼を満喫できるのではないでしょうか.
既にある程度所持キャラが充実している人でも,キャラがダブったときに併せて排出される星髄は800個集めると,任意のキャラと交換できるので全く損ということは無いです.
プレイスタイルや課金方針など各々の好みで選んでよいと思います.
ピックアップキャラの排出率が段々増加するということは...
確率計算とは全く関係ないですが,星の翼の募集では
10連募集で割引がありません.
(裏で10連のときに確率の調整が入っている可能性は捨てきれないですが)特定の募集回数以降伝説キャラの排出率が上昇します.
よって排出率の上昇が始まってからは単発で引いた方が,チケットの節約ができるのではないかと考えられます.
例えば40回目以降排出率が上昇する50%募集で,53回目に伝説キャラが排出されると仮定します.
単発の場合,53回目に伝説キャラが排出され募集を終了できますが,10連を繰り返していた場合,51回~60回を一度に募集するため7回分チケットを無駄にします.(あくまで仮定に則った推察でしかないが...)
まとめ
100%募集では90回以内に必ずピックアップ伝説キャラが手に入るが,
50%募集でも2/3くらいの確率で90回以内にピックアップ伝説キャラが手に入る.ピックアップ以外の伝説キャラや史詩キャラが入手できる可能性が高いので,始めたての人ほど50%募集がオススメ
伝説キャラの排出率が上昇し始めたら,単発で引いたほうがチケットの節約になる.
以上!よきほしつばライフを!!
蛇足:細かいことが気になる人向けの内容
細かいことまで気になるよ~という人向けに補足を書いておきます.
n回目の募集までにピックアップキャラを引く確率って何やねん
厳密には,50%募集 シミュレーションでは「ピックアップ伝説キャラを全部でN回排出されたときn回目に排出された回数が占める割合」,100%募集 確率計算では「n回目までに少なくとも1回ピックアップキャラが排出される確率」を示す.
確率計算
$p$の確率で伝説キャラが排出されるとき,$k$回目の試行で伝説キャラを引かない確率は$1-p_k$である.ここで$p_k$は$k$回目の試行での排出率を表す.よって$n$回目の募集までに少なくとも一体の伝説キャラが排出される確率は
$$
P_n=(1-\prod_{k=1}^n (1-p_k)),
$$
である.
ガチャエミュレータのソースコード
import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np
rng = np.random.default_rng()
class LotterySimulator:
def __init__(self, p0, p1, N0, N1):
"""
くじシミュレータの初期化
p0: 初期確率
p1: N1回目での確率
N0: 確率上昇開始回数
N1: 確率上昇終了回数(この回では必ず当たり)
"""
self.p0 = p0
self.p1 = p1
self.N0 = N0
self.N1 = N1
self.current_trial = 0
self.total_trials = 0
self.isFirstLegend = True
def get_probability(self, n):
"""n回目の確率を計算"""
if n < self.N0:
return self.p0
elif n < self.N1:
# N0からN1の間で線形に増加
slope = (self.p1 - self.p0) / (self.N1 - self.N0)
return self.p0 + slope * (n - self.N0)
else:
return 1.0 # N1回目は確実に当たり
def draw(self):
"""くじを1回引く
Returns:
tuple (bool): (ピックアップキャラでない伝説が排出された、ピックアップキャラが排出された)
"""
self.current_trial += 1
self.total_trials += 1
prob = self.get_probability(self.current_trial)
legend = rng.random() < prob
if legend and self.isFirstLegend:
pickup_legend = rng.random() < 0.5
if pickup_legend:
# ピックアップキャラが当たった場合は初期化
self.isFirstLegend = True
self.current_trial = 0
self.total_trials = 0
return legend, True
else:
# ピックアップキャラが外れた場合は、次回以降の確率をリセット
self.isFirstLegend = False
self.current_trial = 0
return legend, False
elif legend and not self.isFirstLegend:
# 二回目は必ずピックアップキャラ
self.current_trial = 0
self.total_trials = 0
self.isFirstLegend = True
return legend, True
return legend, False
if __name__ == "__main__":
# パラメータ設定
p0 = 0.008 # 初期確率 0.8%
p1 = 0.024 # 最終確率 2.4%
N0 = 40 # 40回目から確率上昇開始
N1 = 70 # 70回目で確実に当たり
# シミュレータ初期化
simulator = LotterySimulator(p0, p1, N0, N1)
# シミュレーション
total_trials = 140
pickup_trials = []
legend_trials = []
while len(pickup_trials) < 10000:
for i in range(total_trials+1):
legend, pickup_legend = simulator.draw()
##
## デバッグ用
# print(f'legend: {legend}, pickup_legend: {pickup_legend}')
# print(f'isFirstLegend: {simulator.isFirstLegend}')
# print(f'current_trial: {simulator.current_trial}, total_trials: {simulator.total_trials}')
# print(f'p: {simulator.get_probability(simulator.current_trial)}')
##
##
if legend:
legend_trials.append(i)
if pickup_legend:
pickup_trials.append(i)
break
else:
print('Something went wrong.')
print(f'@{i}th trials')
exit(1)
np.save('pickup_trials.npy', np.array( pickup_trials ))
np.save('legend_trials.npy', np.array( legend_trials ))
# ヒストグラム表示
fig, ax = plt.subplots()
ax.hist(pickup_trials, bins=30, label='ピックアップ伝説')
ax.hist(legend_trials, bins=30, alpha=0.5, label='伝説')
ax.legend()
ax.set_xlim(0, 140)
ax.set_xlabel('募集回数')
ax.set_ylabel('伝説キャラを排出した回数')
plt.show()