4世代の乱数調整におけるseedの検索は、3世代におけるそれとは全く意味合いが異なってくる。3世代は初期seedが固定されており(少なくとも任意に設定する事は不可能)、初期seedから一定の消費数以下で個体検索を行う都合上、初期seedから順に検索していく方法で凡そ問題は無い(ただしBV保存等で消費数の実現性度外視で検索する場合はこの限りでは無い。0x0から任意のseedまでの消費数を高速で求める方法が存在する為、下記の4世代における方法と併用すれば、順に計算していくより速い)。しかし4世代は「初期seedを固定して消費数を任意に変動させて目標個体が存在するか探す」よりも「一定消費数以内で目標の個体が出る初期seedを探す」事が実用上重要になってくる。今回新たに4世代用乱数調整ツールを自力で組むにあたり、与えられた諸条件を満たす初期seedの効率的な探索方法について考察したので、備忘録を兼ねて記すことにした。

4世代固定シンボルの個体生成処理は以下の通りである。

◾️シンクロ無効個体
・LID決定
・HID決定
・HAB決定
・SCD決定

◾️シンクロ有効個体
(シンクロ判定なしの場合)
・仮性格決定
・LID決定
・HID決定(LID決定と合わせて、仮決定した性格に一致するPIDになるまで繰り返し)
・HAB決定
・SCD決定

(シンクロ判定ありの場合)
・シンクロ判定
(・仮性格決定…シンクロ判定に外れた場合)
(以下シンクロ判定なしと同様)

この内、該当するseedを探索する上で重要になってくるのは
HAB-SCDの個体値決定処理である。具体的には乱数値をR=seed>>16と置くと、H,S=R&0x1f
A,C=(R>>5)&0x1f
B,D=(R>>10)&0x1f
で個体値が決定される。個体値を与えられた時、HAB,SCDのそれぞれで乱数値16bitのうち15bit分の情報が与えられていることになる。また、個体値からHAB決定に使われるseedが求まれば、LIDとHIDの決定に使われるseedは逆算で簡単に求まる。シンクロ有効個体についても、性格の仮決定処理はあるものの、重要な部分はLID決定-SCD決定であると言える。
これを踏まえた上で、まずは与えられた個体値からLID決定に使われるseedを探索する処理について、考えられるものを挙げていこう。

◾️2^32通り全探索

全てのseedを調べる。1番単純な力業。指定された個体値の条件が広い時は案外効率悪くないのかもしれない(そんなことはない)。1回の検索にかかる時間は一律で、判定処理2^32(約42億)回分。長い。


◾️個体値から上位16bitを計算して下位16bitを全探索

個体値から16bitの乱数値の内15bit上位bitが求まる。残り1bitは0,1のそれぞれを指定してやる必要があるが、HAB決定のseedからLCG1回回して上位16bitがSCDと一致すれば良いので、個体値1つ当たり2^17回ループを回すだけで済む。指定された個体値の個数が2^17個を超えない限り上よりも効率的。


◾️上の条件を更に考察してみる

本題。効率的になったとは言え、毎回n *2^17回ループ回すのはまだ非効率的。検索に時間がかかるとストレスがマッハで非人道的なので、更なる高速化を図る。

HAB, SCDを生成するseedをそれぞれr[n]=HAB<<16 +y r[n+1]=SCD<<16 +zと置く。HABとSCDからyを求められないか? と言う方針。前に書いたこれの考え方(上位と下位を分けて式変形)とか使えそうな気がする。

f(HAB<<16 +y) = SCD<<16 +z

0x41c64e6d *(HAB<<16+y)+0x6073=SCD<<16+z

f(y)=SCD<<16 +z -0x41c64e6d*HAB<<16

ここで右辺の0x41c64e6d*HAB<<16

は0x4e6d *HAB<<16に等しいことに注意すると、

f(y) =(SCD-0x4e6d *HAB)<<16 +z

zの値は個体値に関係無くf(y)の下位16bitに等しいので、問題になるのは両辺の上位16bitということになる。つまり、yの満たすべき条件はf(y)>>16 = (SCD-0x4e6d *HAB)&0xFFFFであるということがわかる。各SCD-0x4e6d *HABの値に対応するyがわかっていれば、指定された個体値を生成するseedを簡単に得ることができるのだ。

ではこれをどう求めれば良いのかというと、上手い方法が思いつかなかった。


現在は65536項のListの配列を用意し、起動時に各i(0≦i≦65565)についてk=f(i)>>16を計算して、配列のk番目にiをAddする方法を取っている。指定された個体値に対してk=SCD-0x4e6d *HABを計算すれば、配列のk番目に格納されたListを取り出すだけで目的のseedが得られるようになっている(もちろん存在しない場合や、複数存在する場合もある)。

こんな感じ。

実際速い。


◾️締まらない

これで生成開始seedはわかったわけだが、シンクロ有効個体については性格決定処理を考慮する必要があるし、与えられた消費数以内にこのseedを実現できる初期seedで起動時間等の条件をクリアするものを探さなければならない。しかしそこまで話を進めると長くなるので、一旦ここで終わることにする。