乱数について考えてみる
2013.02.23
この記事は最終更新日から1年以上が経過しています。
乱数について考えてみました。そもそも乱数とはなにか?
乱数とは、サイコロの出目のように規則性がなく予測不能な数値のこと。
と、書かれているところが多いかと思います。
Javascriptのなど言語ではMath.random();で乱数を生成することができます。
Math.random();で生成出来る数値は、0〜1以下の数値となります。(詳しくは0と1の間の数値となります。)
生成している記事は以下を参考に宜しくお願い致します。
JavaScript ランダム関数 Math.random() まとめ + css3
0〜1以下の数値を生成とありますが、勿論範囲の指定などを行えば、範囲内の乱数値を生成することが出来ます。
11〜20の値を生成する場合。
var nMax = 20; var nMin = 11; var ransu = Math.floor(Math.random()*(nMax-nMin+1))+nMin;
結果
13
また、少数点を取得する際は、桁数掛けた数値を設定値とし、乱数を生成した後、桁数割ることによって少数点の乱数数値を生成することが出来ます。
var nMax = 125; var nMin = 95; var ransu = Math.floor(Math.random()*(nMax-nMin+1))+nMin; ransu = ransu/100;
結果
1.21
このようにコンピューターのプログラム言語を用いて生成した乱数に関しては計算によって乱数が生成されるため、完全な乱数を生成することが出来ません。このような手法で生成された乱数のことを擬似乱数といいます。
このような擬似乱数は確定的な計算によって求められている数列の為、計算方法と初期値がわかれば全く同じ数値列を再現することができます。
乱数テーブル
それでは確率について考えてみます。
擬似乱数を使い、1〜160の値の乱数を生成します。
そのうち、1を当たりとし1/160の確率で当たるという計算式を作成してみます。
その検証を8000回行った時、果たして1/160の確率で当たるのかどうか。
ピンときた方、そうです。スロットなのでの確率だったりします。
1/160の確率の台を一日8000回回すのを想定しています。
scriptは以下の様な感じで。
var ransu; var nMax = 160; var nMin = 1; var nTest = 8000; var count = 0; for(var i =0;i < nTest;i++){ ransu = Math.floor(Math.random()*(nMax-nMin+1))+nMin; if(ransu == 1){ count ++; console.log("当たり"); } } console.log(Math.floor(nTest/count));
検証の結果以下の様になりました。
非常にバラつきが発生致しました。
1/150の確率や1/130の確率で多く当たる分に関しては「ラッキー!」となりますが、1/200の確率になると、「クッソー」となりますね。w
このようなバラつきがなく160回目には大体1回は当たって欲しいのが人情だったりもします。
また、このような大きなバラつきが生じるとゲームバランスを崩れてしまうおそれがあります。
この様なことを回避する為、ゲームなどで使われているのが乱数テーブルとなります。
乱数テーブル(乱数表)とは以下のように、ランダムに数字を並べた表をイメージして頂ければと。
乱数表
重複しない数字を埋めることによって、任意の確率を得ることができます。
エクセルでの作成方法
RAND関数を使うことによって、ランダムの値を生成することが出来ます。
=RAND()
セルA1〜A5までこのRAND関数でランダムの値を生成しましょう。
その数値の順位をつけることによって、重複のない数値を生成します。
順位をつける為にRANK関数を使用し、Bのセルにその順位を表示させます。
=RANK(A1,$A$1:$A$5,)
B1のセルに入力しB2〜はコピーでA2〜A5の値を参照出来るようにすると順位が表示し、重複のない数値を生成することが出来ます。
ポインター
再び乱数テーブルの話に。
先ほど用意した、乱数テーブルをみると、バラバラに数値が配置されているかと思います。
この中で抽選することによってはずれのない任意の確率をつくることが出来ます。
ハズレの無いようにするには、例えば、3-1の193の値を引いたとすると、次は3-1以外の場所に移動させる。
次に移動させる場所が3-4の212の値だとすると、3-1と3-4以外の場所に移動させる。といった具合にすれば当たりとしている数値をいずれ引くことが出来ます。
このように現在の値の位置のポインターをずらすことによって、重複のない抽選方法を作成することが出来ます。
JavaScriptで乱数テーブルを作成
それでは、JavaScriptで乱数テーブルを作成していこうと思います。
良質な記事がございましたのでこちらを参考に。
レトロRPGを作る-乱数を実装する
こちらのscriptを参考にさせて頂くと、
Random.table = [ 7, 182, 240, 31, 85, 91, 55, 227, 174, 79, 178, 94, 153, 246, 119, 203, 96, 143, 67, 62, 167, 76, 45, 136, 199, 104, 215, 209, 194, 242, 193, 221, 170, 147, 22, 247, 38, 4, 54, 161, 70, 78, 86, 190, 108, 110, 128, 213, 181, 142, 164, 158, 231, 202, 206, 33, 255, 15, 212, 140, 230, 211, 152, 71, 244, 13, 21, 237, 196, 228, 53, 120, 186, 218, 39, 97, 171, 185, 195, 125, 133, 252, 149, 107, 48, 173, 134, 0, 141, 205, 126, 159, 229, 239, 219, 89, 235, 5, 20, 201, 36, 44, 160, 60, 68, 105, 64, 113, 100, 58, 116, 124, 132, 19, 148, 156, 150, 172, 180, 188, 3, 222, 84, 220, 197, 216, 12, 183, 37, 11, 1, 28, 35, 43, 51, 59, 151, 27, 98, 47, 176, 224, 115, 204, 2, 74, 254, 155, 163, 109, 25, 56, 117, 189, 102, 135, 63, 175, 243, 251, 131, 10, 18, 26, 34, 83, 144, 207, 122, 139, 82, 90, 73, 106, 114, 40, 88, 138, 191, 14, 6, 162, 253, 250, 65, 101, 210, 77, 226, 92, 29, 69, 30, 9, 17, 179, 95, 41, 121, 57, 46, 42, 81, 217, 93, 166, 234, 49, 129, 137, 16, 103, 245, 169, 66, 130, 112, 157, 146, 87, 225, 61, 241, 249, 238, 8, 145, 24, 32, 177, 165, 187, 198, 72, 80, 154, 214, 127, 123, 233, 118, 223, 50, 111, 52, 168, 208, 184, 99, 200, 192, 236, 75, 232, 23, 248 ];
このようにオブジェクトのメンバーに乱数を格納
ポインタ移動
Random.pos = Math.floor(Random.pos + Math.random() * 255) % 256;
さらに、範囲を決めて判定を行いないたいときは、Random.judge({l: 0, g: 64}のように記述。
Random.judge(range) { var v = Random.table[Random.pos]; Random.pos = Math.floor(Random.pos + Math.random() * 255) % 256; return range.l <= v && v < range.g; } if(Random.judge({l: 0, g: 64})) { //アイテムドロップ }
それをまとめると、
Random.getValue = function (range) { var v = Random.table[Random.pos]; Random.pos = Math.floor(Random.pos + Math.random() * 255) % 256; if (range == null) { return v; } for (var i = 0; i < range.length; i++) { if (range[i].l <= v && v < range[i].g) { return i; } } return i - 1; } var Items = ["A","B","C","D"]; var pos = Random.getValue([ {l:0, g: 128}, {l:128, g: 201}, {l:201, g: 251}, {l:251, g: 256}]); //Items[pos]がドロップしたアイテム。
のようにすれば、乱数テーブルに配置した数字から抽選し、4種類あるアイテムを範囲を決めることによって選択することができますよ。と記事に書かれています。
いやぁ。素敵。
では、これを使って可視化したページを作成してみました。
乱数テーブルがどのように動いているか、何のアイテムをGET出来ているかが確認できます。(数字の重複処理は含まれていません。)