この記事では、パワポケシリーズの乱数列で合計値ができるだけ大きくなるような部分列を「実用上は」十分な速度で探索することを可能とするPythonプログラムを公開し、その解説を行います。
なお、本記事のプログラムは、パワポケ10裏の武器粘り、パワポケ11裏、12裏の合成システムでMPの強い武器、装備を作成するのに非常に役に立ちます。(それらは別途記事にしようと思います。)
この記事執筆にあたり、下記を参考にいたしました。
また、本記事の成果は下の記事にも利用しております。
【最新版】パワポケ10 バトルディッガー編で総合的に強い武器を出す乱数シードとやり方
プログラム
言語はPythonです。コピペしてご自由にお使いください。
青色の解説部分は、適宜適切なパラメータに変えて実行してください。
#1:X_0がMP判定、X_nからX_(nn-1)の和がlim以上の乱数列を探索するプログラム A = 0x5d588b656c078965 C = 0x0000000000269ec3 M = 2 ** 64 b=0 bb=0 #2:n,nnを指定 n=4 nn=28 #3:X_nを表すための定数を求める for i in range(0,n): b += A**i % M An=A**n% M Cn=(C*b)% M #4:X_nnを表すための定数を求める for i in range(0,nn): bb += A**i % M Ann=A**nn% M Cnn=(C*bb)% M #5:乱数探索部分。時間h、足切りlim、探索数N、MP判定の#14を設定するべし for h in range(14,24): #6:何時から何時を探索するか for m in range(0,60): for s in range(-1, 59): lim = 19 #7:足切り設定。(nn-n)の7-8割くらいの値がいい N = 100000 #8:1つの乱数初期シードでの乱数発生数、探索数 X_n = 0 X_nn = 0 X = h * (2 ** 16) + m * (2 ** 8) + s + 1 #9:(nn-n)個の乱数値の和をvalueとする value = 0 for i in range(0, N): X_n = (An * X + Cn) % M #10:X_nの値 X_nn = (Ann * X + Cnn) % M #11:X_nnの値 value += (X_nn - X_n) / M #12:乱数が1つ生成されるたびに、valueの値が変動する if i < nn-n: value += X_n/M X = (X * A + C) % M #13:X_0がMPかどうかを判定、さらにX_nからX_(nn-1)の和が足切りlim以上か判定 if value > lim and X/M < 1: #14:11裏なら0.005,12裏なら0.02、それ以外なら1 print(10000 * h + 100 * m + s, i+1, X/M) print("★", value) break
出力結果とその解説
上のプログラムの実行結果です。実行時間が長いので、途中で停止ボタン(■)で打ち切りました。
赤い矢印は、
「14:01:39起動の初期乱数シードから12096番目の乱数値は0.7115654985314595(←#14で調節可能)であり、それを\(X_0\)として\(X_4\)から\(X_{27}\)までの24個の乱数の合計値(←#1, #2のとおり)が19.267637801960564(←#12のvalueの値)である」
ことを示します。
・・・何のことかよくわからないので、【改良版】パワポケの内部乱数観測器をPythonで実装してみたの14:01:39起動時の結果に照らし合わせたものを見てみましょう。
12096番目の乱数が\(X_0\)にあたり、その値は0.7115654985314595です。
この値は11裏、12裏でMP武器、装備を粘りたい場合に使います。詳細は後述。
今回のプログラムではn=4, nn=28と設定しましたので、\(X_4\)から\(X_{27}\)までの24個(= nn-n)の乱数値の合計(図のオレンジの範囲の和)がvalueで、19.267637801960564として返されています。
#1のとおり、和として出力されるのは\(X_n\)から\(X_{nn-1}\)までの部分です。nとnnは#2で決めます。
図で、\(X_{nn} = X_{28}\)は和には入っていないことに注意してください。
なお、この乱数列は【最新版】パワポケ10 バトルディッガー編で総合的に強い武器を出す乱数シードとやり方という記事のものと同一です。
このようにしてゲーム内部で理想的な乱数列を効率よくPythonで探索し(本記事)、実際のゲームで理想の事象を起こす(リンク先のような強い武器を引き当てる)ことが可能になります。
青色部分のパラメータ調整について
#2
は、何番目から何番目の乱数の合計値を考えるのかを決めるのに使います。#1のとおり、和として出力される値は\(X_n\)から\(X_{nn-1}\)までの和であり、個数は(nn-n)個になることに注意してください。
#7は、#2で決めた(nn-n)個分の乱数の合計値の足切りを表します。n=4, nn=28なら24個分で、この場合16 < lim < 20くらいがちょうどいいと思います。大体(nn-n)の6.5-8割がちょうどいいです。
#6は探索するゲーム内の起動時間、 #8は1つの乱数シードあたりの乱数発生数を表します。これらのパラメータの範囲の広さ、大きさによってO(n)で実行時間が変わります。(ただし、#8のNについてはlimの値が十分大きいとき。)うまく調節してください。
目安ではhが0-24、Nが1000のときに最大133秒くらいかかります。
#6のrange(14, 24)では、Pythonでは14,15,16, … , 23と実行され、24は実行されないことに注意しましょう。
#8はだいたい500~200000くらいがいいと思います。
#14は、パワポケのゲーム内で何をしたいかで決めればいいです。\(X_{0}\)は11裏、12裏の合成システムでMP判定かどうかを調べるもので、11裏、12裏でMP武器、装備が欲しい場合はそれぞれのMP確率0.005, 0.02としてください。10裏の武器粘りは無関係なので1でOKです。
プログラム自体の解説について
赤色のコメントアウト部分
で、ポイントとなる部分を解説します。
#3, #4について、線形合同法において初期乱数シードが\(X_{0} = x\)で生成規則となる漸化式が\(X_{n+1} = A X_n + C\ (mod\ M)\)の場合、一般項は次の通りになります。
\(X_{n} = A^n x + C\displaystyle\sum_{i=0}^{n-1} A^i \ (mod\ M)\)
線形合同法では、1つ次の乱数のみならずn個次の乱数でもA, Cの値をうまく上の通りの変えてあげれば実装できてしまうのです。
#3, #4はそれを数式で実装し、#10, #11でうまく生成規則のA, Cの部分を置き換えることでn個(とnn個)次の乱数をうまく一発で、一本の数式で求めているのです。
高校数学なら数列、大学数学なら群論やマルコフ連鎖の知識がここで役に立っています。
パワポケは、数学です。
というより、ゲームは数学です。
#12の部分は、とあるように、従来記事(パワポケシリーズ 乱数探索プログラムの実装例(入門編))からの変更点です。これにより、実行速度のアップに成功しています。
従来はサイズ18(今回の場合は24とる必要あり)のリストを確保し、1つ乱数を生成するたびにpush, popを繰り返してその都度合計を求める、ということをしていたので探索速度が今より何十倍も遅かったのです。
本記事のプログラムも特別速い、というわけではないかもしれませんが、実用上では十分、というレベルまでは到達しております。途中で落ちることもありません。
他の部分については、おおむねコメントのとおりです。
まとめ
・パワポケシリーズにおける、実用上十分高速な理想の乱数列探索プログラムを公開し、解説いたしました
・このプログラムは、10裏の武器粘り、11裏と12裏のMP武器、装備粘りにおいて絶大な威力を発揮します。10裏についてはすでに公開済みです(【最新版】パワポケ10 バトルディッガー編で総合的に強い武器を出す乱数シードとやり方)
・パワポケは、数学です
コメント