ゲームのガチャ等では偏りランダムは欠かせないものとなっています。
私の場合以下のようなやり方で行っています。
Aの確率は
80%
Bの確率は19.5%
Cの確率は0.5%
の場合
➀ 各データの確率を分数のように通分し全て整数にします
B,Cが少数の確率がなのですべて10倍します。
Aは800
,Bは195
,Cは5
となります。
➁ ➀で求めた各データの値を分数のように約分します
この場合、各データの➀の値はすべて5の倍数なので、すべて5で割ります。
Aは160
,Bは39
,Cは1
となります。
➂ ➁で求めた各データの値分を配列に代入します
Aは160
なので配列にAを160
個代入。Bは39
個代入。Cは1
個代入。
配列の中身は['A', 'A', 'A', 'A', ... 'A', 'B', 'B', 'B', 'B', ... 'B', 'C']
のようになります。
➃ 偏りランダムを行います
配列[Math.floor(Math.random() * 配列.length)]
で取得します。
js
1// *** 偏り *** // 2let table = { 3 "A": 80.0, 4 "B": 19.5, 5 "C": 0.5 6}; 7 8// *** 手順➀ *** // 9while (true) { 10 let ok = true; 11 for (let key in table) { 12 if (!Number.isInteger(table[key])) { 13 ok = false; 14 break; 15 } 16 } 17 if (ok) { 18 break; 19 } 20 for (let key in table) { 21 table[key] *= 10; 22 } 23} 24 25// *** 手順➁ *** // 26function GCD(array) { 27 function call(a, b) { 28 return (b ? call(b, a % b) : a); 29 } 30 let ans = array[0]; 31 for (let i = 1; i < array.length; i++) { 32 ans = call(ans, array[i]); 33 } 34 return ans; 35} 36let div = GCD(Object.values(table)); 37for (let key in table) { 38 table[key] /= div; 39} 40 41// *** 手順➂ *** // 42let output = new Array(); 43for (let key in table) { 44 let amount = table[key]; 45 for (let i = 0; i < amount; i++) { 46 output.push(key); 47 } 48} 49 50// *** テスト *** // 51let items = {}; 52for (let i = 0; i < 1000; i++) { 53 54 // *** 手順➃ *** // 55 let key = output[Math.floor(Math.random() * output.length)]; 56 57 // *** カウント *** // 58 if (!items.hasOwnProperty(key)) { 59 items[key] = 0; 60 } 61 items[key]++; 62 63} 64console.log(items);
※ ここのページを参考にいろいろと改良しました。
問題点
このやり方では超低確率での偏りランダムを行う際、➂の手順で大量のデータを入れる必要があります。
環境によってはメモリ不足などのパフォーマンスに影響を及ぼします。
その為、著しく低い確率の偏りランダムを行うのは不向きです。
ループを使わずにパフォーマンスも安定している偏りランダムを行う方法についてご教授ください。
よろしくお願いします。
回答3件
あなたの回答
tips
プレビュー