Add a new lottery model.

Signed-off-by: Randy Barlow's avatarRandy Barlow <randy@electronsweatshop.com>
parent 70ae9449
......@@ -82,7 +82,8 @@ This project is available on [crates.io](https://crates.io/crates/rpick).
# Models
```rpick``` is capable of two different algorithms for picking choices: even and gaussian.
```rpick``` is capable of a few different algorithms for picking choices: even, gaussian, lottery,
and weighted.
## Even
......@@ -140,6 +141,35 @@ album:
```
## Lottery
The ```lottery``` distribution model is a dynamic version of the ```weighted``` model. Each of the
choices has a certain number of lottery tickets that influence how likely they are to be picked that
round. Once an item is picked, it loses all of its lottery tickets and every choice that wasn't
picked gains more lottery tickets. It accepts three keys:
* ```model```: This must be set to the string "lottery", in order to select this model.
* ```choices```: This must be a list of objects. Each object accepts three keys:
- ```name```: This is required, and is the name of the choice.
- ```tickets```: The current number of lottery tickets that this choice has. This is optional, an
integer, and defaults to 1.
- ```weight```: This is an integer expressing how many lottery tickets are given to this choice
when it is not chosen. You can use this to influence how often this item gets favored relative
to the other choices. It is optional, and defaults to 1.
Example:
```
activity:
model: lottery
choices:
- name: exercise
- name: read documentation
- name: watch tv
weight: 1000
```
## Weighted
The ```weighted``` distribution model is a more general version of the ```even``` model that allows
......
......@@ -50,12 +50,25 @@ enum ConfigCategory {
stddev_scaling_factor: f64,
choices: Vec<String>
},
Lottery {
choices: Vec<LotteryChoice>
},
Weighted {
choices: Vec<WeightedChoice>
}
}
#[derive(PartialEq, Serialize, Deserialize)]
struct LotteryChoice {
name: String,
#[serde(default = "_default_weight")]
tickets: u64,
#[serde(default = "_default_weight")]
weight: u64,
}
#[derive(PartialEq, Serialize, Deserialize)]
struct WeightedChoice {
name: String,
......@@ -76,6 +89,10 @@ fn main() {
_pick_gaussian(choices, *stddev_scaling_factor);
_write_config(config);
}
ConfigCategory::Lottery { choices } => {
_pick_lottery(choices);
_write_config(config);
}
ConfigCategory::Weighted { choices } => {
_pick_weighted(choices);
}
......@@ -157,6 +174,27 @@ fn _pick_gaussian(choices: &mut Vec<String>, stddev_scaling_factor: f64) {
}
/// Run the lottery model for the given choices.
fn _pick_lottery(choices: &mut Vec<LotteryChoice>) {
let weighted_choices = choices.iter().enumerate().map(
|x| ((x.0, &x.1.name), x.1.tickets)).collect::<Vec<_>>();
let index = loop {
let mut rng = rand::thread_rng();
let (index, choice) = weighted_choices.choose_weighted(&mut rng, |item| item.1).unwrap().0;
if _get_consent(&choice[..]) {
break index;
}
};
for choice in choices.iter_mut() {
choice.tickets += choice.weight;
}
choices[index].tickets = 0;
}
/// Run the weighted model for the given choices.
fn _pick_weighted(choices: &mut Vec<WeightedChoice>) {
let choices = choices.iter().map(|x| (&x.name, x.weight)).collect::<Vec<_>>();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment