veloren/common/src/lottery.rs

63 lines
1.6 KiB
Rust
Raw Normal View History

2020-12-12 22:14:24 +00:00
use crate::assets;
2020-07-03 13:49:17 +00:00
use rand::prelude::*;
use serde::{de::DeserializeOwned, Deserialize};
2020-07-03 13:49:17 +00:00
#[derive(Clone, Debug, PartialEq, Deserialize)]
2020-07-03 13:49:17 +00:00
pub struct Lottery<T> {
items: Vec<(f32, T)>,
2020-07-03 13:49:17 +00:00
total: f32,
}
2020-12-12 22:14:24 +00:00
impl<T: DeserializeOwned + Send + Sync + 'static> assets::Asset for Lottery<T> {
type Loader = assets::LoadFrom<Vec<(f32, T)>, assets::RonLoader>;
2020-12-13 01:09:57 +00:00
const EXTENSION: &'static str = "ron";
2020-07-03 13:49:17 +00:00
}
2020-12-12 22:14:24 +00:00
impl<T> From<Vec<(f32, T)>> for Lottery<T> {
fn from(mut items: Vec<(f32, T)>) -> Lottery<T> {
2020-07-03 13:49:17 +00:00
let mut total = 0.0;
2020-12-12 22:14:24 +00:00
for (rate, _) in &mut items {
total += *rate;
*rate = total - *rate;
}
2020-07-03 13:49:17 +00:00
Self { items, total }
}
2020-12-12 22:14:24 +00:00
}
2020-07-03 13:49:17 +00:00
2020-12-12 22:14:24 +00:00
impl<T> Lottery<T> {
pub fn choose_seeded(&self, seed: u32) -> &T {
let x = ((seed % 65536) as f32 / 65536.0) * self.total;
&self.items[self
.items
.binary_search_by(|(y, _)| y.partial_cmp(&x).unwrap())
.unwrap_or_else(|i| i.saturating_sub(1))]
.1
2020-07-03 13:49:17 +00:00
}
2020-08-12 14:10:12 +00:00
pub fn choose(&self) -> &T { self.choose_seeded(thread_rng().gen()) }
pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.iter() }
}
#[cfg(test)]
mod tests {
use super::*;
2020-12-12 22:14:24 +00:00
use crate::{assets::AssetExt, comp::Item};
#[test]
fn test_loot_table() {
let test = Lottery::<String>::load_expect("common.loot_tables.loot_table");
2020-12-12 22:14:24 +00:00
for (_, item_asset_specifier) in test.read().iter() {
assert!(
Item::new_from_asset(item_asset_specifier).is_ok(),
"Invalid loot table item '{}'",
item_asset_specifier
);
}
}
}