rust-rl/src/random_table.rs

79 lines
2.6 KiB
Rust

use rltk::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<S: ToString>(name: S, weight: i32) -> RandomEntry {
RandomEntry { name: name.to_string(), weight }
}
}
#[derive(Default)]
pub struct RandomTable {
entries: Vec<RandomEntry>,
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<S: ToString>(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();
}
}