裏CHUNSOFT > ROMイメージ改造・解析 > 乱数生成
乱数生成
コンピュータにおける乱数について
実はコンピュータが発生させる乱数は、本当の意味でランダムなのではなく、一定の初期値(これを乱数の種と呼びます)と決められたアルゴリズムに従って一見ランダムに見える数列を生成しているに過ぎないのです(このようにして発生させた乱数のことを擬似乱数と言います)。 コンピュータは決められた計算をすることはできても、ランダムな数字を発生させることはできないのです。
コンピュータでは、乱数は擬似乱数しか発生させることができないのですから、風来のシレンは勿論全てのゲームにおける乱数は擬似乱数です。 ただ不思議のダンジョンシリーズは、必要に応じて擬似乱数を発生させているのが特徴で、擬似乱数の実感がしやすいゲームだと言えます。 他のゲームでは、1フレーム毎に擬似乱数を発生していたりするのでなかなか実感ができません。
そのフロアにおけるシレンの行動を記録しておけば、後は乱数の種から正しくフロア生成や再開・回想ができたり、他の不思議のダンジョンシリーズで救助する場合に倒れた人と同じ地形を進むことになったり、Windows版風来のシレンのゴミ壺ダンジョンで何度プレイしても同じダンジョンになったりすることから、擬似乱数というものが実感できます。 また、保存しておいたセーブデータから再開し、そこから同じ行動をすることを繰り返すと何度やっても同じ結果になります。
乱数生成アルゴリズム
(擬似)乱数生成ルーチンは03F65Fh以降にあります。 以下はその逆アセンブルリストです。
数値は全て16進数です。 $XXはメモリ(変数)を表します。 乱数生成に影響しない命令にはコメントを付けていません。 1つ1つ解説するまでもない命令は、複数の命令をまとめて1つのコメントで解説しています。
03F65F 08 PHP ; 03F660 C2 20 REP #$20 ; 03F662 A5 B7 LDA $B7 ; "A" = 100 * $B8 + $B7 03F664 0A ASL * 5 ; "A" *= 20 (を10000で割った余り) 03F669 45 B8 EOR $B8 ; "A" = "A" xor 100 * $B9 + $B8 03F66B 0A ASL ; "A" *= 2 (を10000で割った余り) 03F66C E2 20 SEP #$20 ; 03F66E A5 B8 LDA $B8 ; 03F670 85 B9 STA $B9 ; $B9 = $B8 03F672 A5 B7 LDA $B7 ; 03F674 85 B8 STA $B8 ; $B8 = $B7 03F676 A5 B6 LDA $B6 ; 03F678 85 B7 STA $B7 ; $B7 = $B6 03F67A EB XBA ; 03F67B 85 B6 STA $B6 ; $B6 = "A" / 100 (余りは切り捨て) 03F67D 85 00 STA $00 ; $00 = "A" / 100 (余りは切り捨て) (これが新しい乱数になり、乱数生成ルーチンを呼び出した側で受け取られる) 03F67F 64 01 STZ $01 ; 03F681 28 PLP ; 03F682 6B RTL ;
$B6,$B7,$B8,$B9には今まで生成された乱数が入っています(例:05,DD,E8,F7)。
簡単に言うと、$B7のbit2〜$B8のbit1と、$B8のbit7〜$B9のbit6の排他的論理和が新しい乱数です。 後は、$B7〜$B9に$B6〜$B8の値を、$B6に新しい乱数を代入して終了です。
乱数は偏るか
不思議のダンジョンシリーズでは、よく「偏る乱数」が言われます。 そしてそれは、偏りやすい乱数生成アルゴリズムを使っているからだと言われることがあります。 少なくともSFC版風来のシレンでは、乱数生成アルゴリズムは上の通りですが、このようなアルゴリズムによって生成された数列が偏りやすい性質を持つのかは、私には分かりません(詳しい方がいましたら教えて下さい)。 そこで、ここでは統計で「偏る乱数」説を検証してみます。
JavaScriptを使って、同じアルゴリズムで乱数を16777216回発生させてみました($B6〜$B9の初期値は上の例のものを用いました)。 以下は0〜255の各値が出た回数です。
65424,65593,65649,65342,65422,65800,65473,65695,65402,65507,65717,65914,65332,65892,65493,65227, 65473,65759,65834,65637,65425,65533,65198,65165,65621,65786,65647,65445,65503,65906,65974,65379, 65556,65437,66012,65772,65402,65272,65664,65591,65411,65373,65333,65559,65967,65637,65172,65460, 65154,66120,65438,65406,64894,65559,65593,65948,65556,65381,65380,65333,65843,65582,65412,65488, 65550,65238,65509,65677,65347,65248,65311,65627,65645,65431,65757,65780,65811,65486,65480,65162, 65443,65369,65395,65388,65638,66025,65910,65218,65768,65626,65684,65730,65602,65972,65617,65337, 65925,65415,65619,65342,65417,65221,65791,65353,65553,65441,65269,65392,65444,65096,65662,65880, 65468,65403,65677,65525,65471,65610,65291,65600,65508,65614,65286,65813,65393,65505,65520,65980, 65659,65241,65306,65726,65703,65818,65429,65851,65513,65597,65357,65427,65225,65523,65141,65584, 65165,66010,65415,65456,65706,65765,65341,65126,65318,65620,65418,65283,65083,65543,65637,65321, 65695,65335,65500,65764,65507,65456,65235,65225,65380,65424,65731,65316,65588,65533,65992,65647, 65334,65801,65763,65704,65910,65560,65495,65693,65639,65932,65640,65952,65892,65182,65250,65486, 65696,65409,65859,65134,65772,65635,65729,65421,65440,65462,65340,65364,65553,66058,65053,65440, 65603,65068,65347,65808,65732,65696,65326,65552,65334,65650,65601,65839,65608,65135,65425,65872, 65216,65362,65410,65376,65691,66041,65409,65416,65493,65351,65686,65194,65858,65442,65391,65200, 65578,65543,65558,65684,65223,65795,65663,65377,65414,65630,65752,65357,65794,65723,65718,65905
最も少なく出た値が52の64894、最も多く出た値が34の66012でした。 しかし、65536と比べて何れも±1%未満です。 少なくとも長い目で見れば偏りは殆ど存在しないと言えます。
それでは短期的にはどのくらい偏るのでしょうか。 アークドラゴンの場合、発生させた乱数が0〜31の場合に炎を吐きます(つまり1/8の確率です)。 そこでもう1度乱数を16777216回発生させて、今度は0〜31の値が連続した回数を調べてみました。
連続 | 回数 |
---|---|
1 | 1606698 |
2 | 201095 |
3 | 24901 |
4 | 3106 |
5 | 363 |
6 | 49 |
7 | 5 |
8 | 1 |
大体(n連続):(n+1連続以上)=7:1の、望ましい回数になっています。 そんなに連続で0〜31が出やすいアルゴリズムとは言えないでしょう。 短期的には連続で炎を吐くことがあっても、他のどこかで長いターンの間炎を吐かない時がある筈なのです(実際は、乱数は1ターンの内でもランダムな処理が必要になったモンスターの数だけ生成されるので、連続してドラゴン系の炎の判定に使われることは少ないですが)。
ということで、個人的には偏る乱数は存在せず、単に確率の高いことよりも低いことの方が印象に残りやすいだけだと思います。
2009年2月25日更新
裏CHUNSOFT > ROMイメージ改造・解析 > 乱数生成