パワポケシリーズ 乱数探索プログラムの実装例(入門編)

前回までのブログでは、パワポケ乱数を観測するためのプログラムPokeRNGを実装した。しかし、それだけでは「ゲーム内で所望の事象を起こすような初期起動時間と乱数消費数は、どのようにして探索すればいいのか」ということがまだよくわからない。

 

この記事では、前記事でパワポケ10裏で強い補正の主砲をゲットするための初期起動時間と乱数消費数をどのようにして短時間で探し当てたか、ということを稚拙な実装プログラムと共に解説する。

前記事はこちら↓

iid01.hatenablog.com

 

パワポケ10裏の主砲は、乱数24個を消費して生成されるが、その乱数の値が大きければ大きいほど強いものができやすい、というのが検証と実験によってわかっている。

また、主砲のすばやさに関しては補正値の幅が小さい上にあまり重要ではない(122ミリ砲除く)と考えたため、「最初の18個の乱数の和が大きければ大きいほど、攻撃力、命中、弾数の多い良い主砲になるだろう」と考え、18個の乱数の和がある一定以上の値になるような部分乱数列を探索するプログラムを組んでみた。

 

実装プログラムは以下のようになる。稚拙だけど、最初ということで許してください。

 

f:id:iid01:20190223202719p:plain

理想乱数列探索プログラムの例

 

PokeRNGといっしょの部分も多々あるが、違う部分は、

・要素数18のリスト"list"の定義し、そのリストに18個分の部分乱数列を格納

・その18個の部分乱数列の和を目的関数値とし、その値が「足きり」"lim"以上となるような部分乱数列であるかどうかの判定・・・(★)

・上記を、分m、秒sに関してのfor文で繰り返し判定していく

・(★)を満たすものが見つかったら、break文で終了し、目的関数値とリストを出力

 

list.insert、list.popの部分であるように、リストは、乱数を生成するたびに新しくその値を格納し、一番古いものを捨てていく。(キューとスタックで言ったら、キュー。スーパーの行列と同じ、First in, first out)

最後のbreak文とかが稚拙すぎて出力後にエラーが出るけど、プログラムは正常に動く上に結果もまあ目的は達成できるのでとりあえずこれでいい()

 

 

このプログラム、Nとlimの値を正しく設定しないととんでもない計算時間とメモリを食ってしまうので要注意。

Nは、1つの時間、分、秒のセットの中でいくつの乱数値を生成して調べたいかを表す。300~3000くらい、できれば1000あたりが適当な値だろうと思う。18個の乱数が必要なので300以下だと効率は良くないし、3000以上だといい乱数列が見つかっても乱数調整に時間がかかる。

 

limは、目的関数値=18個の乱数の和の「足きり」。目的関数値の値がlimより大きければ終了。12~13.5くらいでないと結構時間かかるはず。それ以下だとすぐ終わるけど、それを使って作る主砲の性能は物足りないかもしれない。

逆に14を超えてくると、なかなか見つからなくて実行時間が急激に増える。ただし、それを超える目的関数値の乱数列では、見事な性能の主砲が出来上がる(はず)。

 

 

時間hについては、24通りなのもあり、計算時間の増大が怖いのでfor文にはせずに、好きなように指定する。

 

h=10(10時台を探索)、N=1000(1つの時間、分、秒あたり1000個分探索)、lim=14.4(18個の0~1の一様乱数列の値の平均が0.8。結構キツイ足きり。)で実行したときの結果はこちら。

 

f:id:iid01:20190223210140p:plain

パワポケ理想乱数探索プログラム 出力結果


実行時間はよく覚えてないけど、数分ほど。(3分くらい?)

一番左の100531っていうのは、時間、分、秒のこと、つまり、10:05:31。(h=0のときは00は省略なので注意)

その次が、10:05:31のときの乱数消費回数。

「終わりやあああああああああああああああ」の後が、所望の和が大きい値の部分乱数列。順番は新しい方から古い方、つまり下から上にさかのぼるような表示。

 

今回は743番目から760番目の乱数が目当ての乱数列。真っ青。

 

★付きの数字が、目的関数値。今回は18個の乱数列の和が約14.5。見事に真っ青。これは偏差値換算でいうと95にあたる優秀さ。上位何パーセントかは正規分布表とかで調べてください

 

最後にbreak文関連のエラー出てるけど、関係ないので見なくてよい。

 

あとはこの結果(時間、分、秒)をPokeRNGとかに入れて詳しく調べて、実際のパワポケで試してみればいい性能の主砲が手に入る。

 

 

上の例で10:05:31の743番目から766番目の乱数で88ミリ砲を拾うと、100-98-7-23になる。

 

命中が高くて他も高水準で、もしかしたらこの前の102-96-8-23より(人によっては)使えるかも・・・

 

余談だけど、737番目から760番目でやると98-96-9-23になります。

こちらはすばやさが高い感じ。

 

 

まとめとして、今回は18個の乱数列をリストに順々に格納していき、その和を目的関数値として足切り判定を自動的に行ってそれをクリアするときの乱数列の結果、情報を出力するプログラムを使ってパワポケ10裏で強い主砲を見つけました。前記事の主砲もこのプログラムで見つけたものです。

 

リストの判定方法を変えることで、(例えば所望のこの事象が起きる条件は1番目が0~0.02で2番目は0.7~1.0で、・・・みたいな条件をプログラムに記述して)ゲーム内のいろいろな事象を狙って起こせるような乱数列を効率的に探索、なんてことができたらいいなと思います。(内部の乱数条件とイベントへの影響を調べるのが一番めんどい。誰かデバッグとかで解析して())

 

その時に、今のままのリストでいいのか(リストの長さを変えたいときは"list"の0の数を変える)、配列(多次元配列)のほうが良いのではないか、ということも考えてはいるけど、とりあえずこんな感じで。

 

 

ではまた。