なんだこれ
いわゆるガチャテーブル、『 重み付き乱択 』をes6で実装してみました。
特定のバナー画像だけ他のバナー画像よりも少し多めに表示させたり、簡易的に負荷分散をさせたり、、と使う場面は多そうです。
1. 実装
// ダーツ投げる
const throwDarts = awards => {
const hit = rand(1, dartboard(awards));
return dartboard(awards, hit);
}
// ダーツ盤
const dartboard = (awards, hit) => {
let area = 0;
for (let key in awards) {
area += awards[key];
if (hit && (area >= hit)) return key;
};
return area;
}
// 乱数(min ~ max)
const rand = (min, max) => {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// 賞品テーブル
const awards = {
'たわし': 7,
'温泉旅行': 2,
'パジェロ': 1
}
// 実行
console.log(throwDarts(awards)); // たわし
メインとなる関数は dartboard()
ですが、たったこれだけです。
おわかりいただけたでしょうか。
『関口宏の東京フレンドパークII』の最後にやっていた、回転するダーツ盤にダーツを打ち込むイメージです。
2. 解説
throwDarts()
const hit = rand(1, dartboard(awards));
ここでの dartboard(awards)
は 賞品テーブル awards
の 合計値(10) を返します。
乱数 hit
はダーツの 着弾地点(1~10) を示します。
dartboard()
let area = 0;
for (let key in awards) {
area += awards[key];
if (hit && (area >= hit)) return key;
};
area
はダーツ盤における 賞品の面積 です。
各賞品の面積を for
ループで加えていき、 hit
が area
の範囲内ならば賞品名を返します。
当然、面積が広い賞品ほど刺さりやすく、逆に狭い賞品には刺さりにくくなります。
例えると簡単ですね。
ロジックは分かったので精度を検証してみましょう。
3. 検証
100万回投げた
const awards = {
'たわし': 50,
'画力': 8,
'筋力': 8,
'集中力': 8,
'健康': 8,
'優しい性格': 8,
'5000兆円': 8,
'パジェロ': 2
}
const results = {
'たわし': 0,
'画力': 0,
'体力': 0,
'集中力': 0,
'健康': 0,
'優しい性格': 0,
'5000兆円': 0,
'パジェロ': 0
}
for (let i=0; i<1000000; i++) {
results[throwDarts(awards)]++;
}
console.log(results);
結果
Object {
5000兆円: 79486,
たわし: 500800,
パジェロ: 20037,
健康: 79943,
優しい性格: 79549,
画力: 80002,
体力: 79774,
集中力: 80409
}
よさそう
よさそうです