use bracket_lib::random::RandomNumberGenerator; // FIXME: note to self, // passing around strings here is super inefficient, so this is // a good place to look for optimisation. Using a unique ID here // for every entry on the table and returning that instead of the // name would be helpful. That said, these tables see low enough // use that reducing readability and confusing things right now // seems like a waste of time. pub struct RandomEntry { name: String, weight: i32, } impl RandomEntry { pub fn new(name: S, weight: i32) -> RandomEntry { RandomEntry { name: name.to_string(), weight } } } #[derive(Default)] pub struct RandomTable { entries: Vec, total_weight: i32, } impl RandomTable { /// Creates a new, blank RandomTable pub fn new() -> RandomTable { return RandomTable { entries: Vec::new(), total_weight: 0 }; } /// Adds an entry to an existing RandomTable pub fn add(mut self, name: S, weight: i32) -> RandomTable { self.total_weight += weight; self.entries.push(RandomEntry::new(name.to_string(), weight)); return self; } /// Adds two RandomTables together pub fn add_table(mut self, table: RandomTable) -> RandomTable { // For every entry in the table being added, push to self. for entry in table.entries { self.entries.push(entry); } // Add the total weight of the added table to self. self.total_weight += table.total_weight; // Return return self; } /// Rolls on an existing RandomTable pub fn roll(&self, rng: &mut RandomNumberGenerator) -> String { // If the table has no weight, return nothing. if self.total_weight == 0 { return "None".to_string(); } // If the table has weight, roll a die, and iterate through // every index on the RandomTable. If the roll is below the // weight of the current index, return it - otherwise, reduce // the roll by the weight and test the next entry. let mut roll = rng.roll_dice(1, self.total_weight) - 1; let mut index: usize = 0; while roll >= 0 { if roll < self.entries[index].weight { return self.entries[index].name.clone(); } roll -= self.entries[index].weight; index += 1; } // If the rolling fails to produce anything (i.e. there is no // item on the table with a weight large to be spawned // by the roll) then return nothing. return "None".to_string(); } }