3 #include "term/z-rand.h"
14 * 確率テーブルを作成し、確率に従った抽選を行うクラス
16 * @tparam IdType 確率テーブルに登録するIDの型
18 template <typename IdType>
19 class ProbabilityTable {
26 ProbabilityTable() = default;
33 return item_list_.clear();
37 * @brief 確率テーブルに項目を登録する
39 * 確率テーブルに項目のIDと選択確率のセットを登録する。
41 * 追加した項目の確率(引数prob) / すべての項目のprobの合計
43 * probが0もしくは負数の場合はなにも登録しない。
48 void entry_item(IdType id, int prob)
51 // 二分探索を行うため、probは累積値を格納する
52 auto cumulative_prob = item_list_.empty() ? 0 : std::get<1>(item_list_.back());
53 item_list_.emplace_back(id, cumulative_prob + prob);
58 * @brief 現在の確率テーブルのすべての項目の選択確率の合計を取得する
60 * 確率テーブルに登録されているすべての項目の確率(登録時の引数prob)の合計を取得する。
62 * @return int 現在の確率テーブルのすべての項目の選択確率の合計
64 int total_prob() const
66 if (item_list_.empty())
69 return std::get<1>(item_list_.back());
73 * @brief 確率テーブルに登録されている項目の数を取得する
75 * 確率テーブルに登録されている項目の数を取得する。
76 * 登録されている項目のIDに被りがある場合は別の項目として加算した数となる。
78 * @return size_t 確率テーブルに登録されている項目の数
80 size_t item_count() const
82 return item_list_.size();
86 * @brief 確率テーブルの項目が空かどうかを調べる
88 * @return bool 確率テーブルに項目が一つも登録されておらず空であれば true
89 * 項目が一つ以上登録されており空でなければ false
93 return item_list_.empty();
97 * @brief 確率テーブルから項目をランダムに1つ選択する
99 * 確率テーブルに登録されているすべての項目から、確率に従って項目を1つ選択する
100 * それぞれの項目が選択される確率は、確率設定probに対して
101 * 該当項目のprob / すべての項目のprobの合計
103 * 抽選は独立試行で行われ、選択された項目がテーブルから取り除かれる事はない。
104 * 確率テーブルになにも登録されていない場合、std::runtime_error例外を送出する。
106 * @return int 選択された項目のID
108 IdType pick_one_at_random() const
111 throw std::runtime_error("There is no entry in the probability table.");
114 // probの合計の範囲からランダムでkeyを取得し、二分探索で選択する項目を決定する
115 const int key = randint0(total_prob());
116 auto it = std::partition_point(item_list_.begin(), item_list_.end(), [key](const auto &i) { return std::get<1>(i) <= key; });
118 return std::get<0>(*it);
122 * @brief 確率テーブルから複数回抽選する
124 * 確率テーブルから引数 n で指定した回数抽選し、抽選の結果選択された項目のIDを
126 * 抽選は独立試行で行われ、選択された項目がテーブルから取り除かれる事はない。
128 * @tparam OutputIter 出力イテレータの型
129 * @param first 結果を書き込む出力イテレータ
130 * @param table 抽選を行う確率テーブル
133 template <typename OutputIter>
134 static void lottery(OutputIter first, const ProbabilityTable &table, size_t n)
136 std::generate_n(first, n, [&table] { return table.pick_one_at_random(); });
140 /** 項目のIDと確率のセットを格納する配列 */
141 std::vector<std::tuple<IdType, int>> item_list_;