Skip to content

Instantly share code, notes, and snippets.

@iwkjosec
Last active September 17, 2025 17:20
Show Gist options
  • Select an option

  • Save iwkjosec/a0c3a7768c84070ee9710b55a1d35186 to your computer and use it in GitHub Desktop.

Select an option

Save iwkjosec/a0c3a7768c84070ee9710b55a1d35186 to your computer and use it in GitHub Desktop.
勝利の女神:NIKKEの初心者用お手入れキットはR等級とSR等級どちらに使うべきか
def expected_trials_to_reach(p_list, cutoff):
"""
p_list : list of length 15 with p_0..p_14 (success probabilities)
cutoff : int, max number of trials per state before forced move to k+1
"""
n = 15 # states 0..14, plus absorbing state 15
def A_k(p):
q = 1 - p
if p == 0.0:
return float(cutoff)
s = 0.0
for t in range(1, cutoff + 1):
s += t * (q ** (t - 1)) * p
return s + cutoff * (q ** cutoff)
def s_k(p):
# success at least once within cutoff trials
return 1 - (1 - p) ** cutoff
E = []
for target in range(0, n + 1):
F = [0.0] * (n + 1)
for k in range(target - 1, -1, -1):
p = p_list[k]
Ak = A_k(p)
sk = s_k(p)
m = (k // 5) * 5 + 5
if m > n:
m = n
F[k] = Ak + sk * F[m] + (1.0 - sk) * F[k + 1]
E.append(F[0])
return E
# 例:p_k を適当に設定して実行
r = [0.176, 0.208, 0.240, 0.272, 0.400, 0.160, 0.192, 0.224, 0.272, 0.400, 0.144, 0.176, 0.224, 0.272, 0.400]
sr = [0.036, 0.059, 0.078, 0.113, 0.150, 0.022, 0.033, 0.049, 0.076, 0.125, 0.012, 0.022, 0.031, 0.047, 0.100]
r_values = expected_trials_to_reach(r, 5)
sr_values = expected_trials_to_reach(sr, 15)
print(f"{'i':>2} | {'r':>10} | {'sr':>10}")
print("-" * 27)
for i, (rv, srv) in enumerate(zip(r_values, sr_values)):
print(f"{i:2} | {rv:10.6f} | {srv:10.6f}")
def expected_stage_over_time(p_list, cutoff, max_k):
"""
p_list: list of length 15 with p_0..p_14 (success probabilities)
cutoff: max failures before forced move to i+1
max_k: compute expected stage from 0 to max_k trials
Returns: list of expected stages [E0, E1, ..., E_max_k]
"""
n = 15
assert len(p_list) == n
# 初期分布
prob = [ [0.0]*cutoff for _ in range(n) ] + [ [0.0] ] # last for i=15
prob[0][0] = 1.0
expected_stages = []
for step in range(max_k + 1):
# 現在の分布から期待到達段階を計算
exp_stage = 0.0
for i in range(n):
exp_stage += i * sum(prob[i])
exp_stage += n * prob[n][0]
expected_stages.append(exp_stage)
# 次の試行の分布に更新
new_prob = [ [0.0]*cutoff for _ in range(n) ] + [ [0.0] ]
for i in range(n):
for r in range(cutoff):
mass = prob[i][r]
if mass == 0.0:
continue
p = p_list[i]
# 成功時
m = (i//5)*5 + 5
if m > n: m = n
new_prob[m][0 if m < n else 0] += mass * p
# 失敗時
if r + 1 < cutoff:
new_prob[i][r+1] += mass * (1.0 - p)
else:
ni = i + 1
if ni > n: ni = n
new_prob[ni][0 if ni < n else 0] += mass * (1.0 - p)
# 吸収状態はそのまま
new_prob[n][0] += prob[n][0]
prob = new_prob
return expected_stages
r = [0.176, 0.208, 0.240, 0.272, 0.400, 0.160, 0.192, 0.224, 0.272, 0.400, 0.144, 0.176, 0.224, 0.272, 0.400]
sr = [0.036, 0.059, 0.078, 0.113, 0.150, 0.022, 0.033, 0.049, 0.076, 0.125, 0.012, 0.022, 0.031, 0.047, 0.100]
k = 20
E_over_time = expected_stage_over_time(r, 5, k)
E_over_time_s = expected_stage_over_time(sr, 15, k)
print(f"{'試行':>4} | {'r':>10} | {'sr':>10}")
print("-" * 28)
for step, (E_r, E_s) in enumerate(zip(E_over_time, E_over_time_s)):
print(f"{step:4d} | {E_r:10.4f} | {E_s:10.4f}")
i | r | sr
---------------------------
0 | 0.000000 | 0.000000
1 | 3.523461 | 11.750749
2 | 4.780650 | 17.602167
3 | 5.148821 | 19.694427
4 | 5.236604 | 20.200602
5 | 5.250755 | 20.269630
6 | 8.886930 | 33.165994
7 | 10.314961 | 41.750477
8 | 10.777021 | 46.428024
9 | 10.895555 | 48.290181
10 | 10.914662 | 48.721111
11 | 14.667522 | 62.524333
12 | 16.286863 | 73.284560
13 | 16.846943 | 80.542391
14 | 16.990622 | 84.619838
15 | 17.013783 | 86.057203
@iwkjosec
Copy link
Author

勝利の女神:NIKKEにおいて、SR等級コレクションを初心者用お手入れキットで5段階まで強化するよりR等級コレクションを初心者用お手入れキットで15段階まで強化してからSR等級に交換した方がお得というのは本当か。

コレクションの1段階強化に必要な経験値

等級 経験値
R 1000
SR 2000

お手入れキット毎の経験値

種別 経験値
初心者用 200
中級者用 500
上級者用 1000

大成功を外し続けた場合、1段階進むのに必要なお手入れ回数はR等級は初心者用5(=1000/200)回で、SR等級は初心者用15(=3000/200)回で進む。
15段階のR等級をSR等級に交換すると5段階になる。

段階$i$において$1$回の試行で当りが出る確率は$ p_i (i=0 \sim 14)$である。当たりが出たら次の$5$の倍数の段階に進み、外れが出たら現在の段階にとどまる。その段階に到達してから$k$回外れが出た場合は次の段階$i+1$に進む。
この試行を繰り返して段階$0$から$i$に到達するまでにかかる試行回数の期待値$E_i$$i=15$まで求めたい。

以上の問題を(頭を使いたくないので)ChatGPT(GPT-5 Thinking Mini)に投げるとcalc.pyを得る。頭を使いたくないので解法のチェックはしていない(カス)。

calc.pyを実行するとoutput.txtを得る。
output.txtを見ると
$\mathrm{E}[\mathrm{R}(15)]=17.01$
$\mathrm{E}[\mathrm{SR}(5)]=20.27$
と分かる。

初心者用お手入れキットだけを使う場合、初めからSR等級を持たせるよりR等級を15段階にしてからSR等級に交換した方が約3.3回お手入れ回数が少なく済む。ニケ1機当たり初心者用お手入れキット33個分の節約になる。
中/上級者用お手入れキットは貴重なので全部SR等級5段階以降に使おう。

おまけ:calc2.pyは試行回数毎の段階の期待値を計算するプログラム。当然output.txtの逆引きよりは小さい値になる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment