JavaScript
アルゴリズム
es6
たわし
パジェロ

要素ごとにランダムに抽出される確率(重み付け)を設定する

なんだこれ

いわゆるガチャテーブル、『重み付き乱択』をes6で実装してみました。
任意のバナー画像だけ他の画像よりも少し多めに表示させたり、簡易的に負荷分散処理をさせたり、と 使う場面は多そうです。

1. 実装

const throwDarts = awards => {
  const hit = rand(1, dartboard(awards));
  return dartboard(awards, hit);
}

const dartboard = (awards, hit) => {
  let area = 0;
  for (let k in awards) {
    area += awards[k];
    if (hit && (area >= hit)) return k;
  };
  return area;
}

const rand = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

const awards = {
  'たわし': 7,
  '温泉旅行': 2,
  'パジェロ': 1
}

// 実行
console.log(throwDarts(awards)); // たわし

メインとなる関数は dartboard() ですが、たったこれだけです。
おわかりいただけたでしょうか。

『関口宏の東京フレンドパークII』の最後にやっていた、回転するダーツ盤にダーツを打ち込むイメージです。
849be8af-a664-4452-9615-d7455ca77ce9.jpg

2. 解説

throwDarts()
let hit = rand(1, dartboard(awards));

ここでは dartboard()awards合計値(10)を返します。
乱数 hit はダーツの着弾地点(1~10)を示します。

dartboard()
  let area = 0;
  for (let k in awards) {
    area += awards[k];
    if (hit && (area >= hit)) return k;
  };

area はダーツ盤における賞品の面積です。
面積を for で足していき、 hitarea の範囲内ならば賞品名を返します。

goods_tawashi.png
例えると簡単ですね。
ロジックは分かったので精度を検証してみましょう。

3. 検証

100万回投げた

const awards = {
  'たわし': 50,
  '画力': 7,
  '彼女': 7,
  '転職先': 7,
  'やる気': 7,
  'コミュ力': 7,
  '5000兆円': 7,
  '優しい性格': 7,
  'パジェロ': 1
}

const results = {
  'たわし': 0,
  '画力': 0,
  '彼女': 0,
  '転職先': 0,
  'やる気': 0,
  'コミュ力': 0,
  '5000兆円': 0,
  '優しい性格': 0,
  'パジェロ': 0
}

for (i=0; i<1000000; i++) {
  results[throwDarts(awards)]++;
}

console.log(results);

結果

Object {
  5000兆円: 70375,
  たわし: 500001,
  やる気: 69448,
  コミュ力: 69690,
  パジェロ: 9984,
  優しい性格: 69720,
  彼女: 69973,
  画力: 70742,
  転職先: 70067
}

よさそう

よさそうです

4. 参考