159 lines
4.9 KiB
Rust
Executable File
159 lines
4.9 KiB
Rust
Executable File
use atomig::Atom;
|
|
use hashbrown::HashMap;
|
|
|
|
use crate::StringKey;
|
|
|
|
/// A unique key that can be used to store a reference to a type. Opaque reference to a byte
|
|
/// internally.
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Atom)]
|
|
#[repr(C)]
|
|
pub struct TypeIdentifier {
|
|
/// The unique internal value.
|
|
val: u8,
|
|
}
|
|
|
|
impl From<u8> for TypeIdentifier {
|
|
fn from(val: u8) -> Self {
|
|
Self { val }
|
|
}
|
|
}
|
|
|
|
impl From<TypeIdentifier> for u8 {
|
|
fn from(id: TypeIdentifier) -> Self {
|
|
id.val
|
|
}
|
|
}
|
|
|
|
/// All data related to types and effectiveness.
|
|
#[derive(Debug)]
|
|
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
|
pub struct TypeLibrary {
|
|
/// A list of types
|
|
types: HashMap<StringKey, TypeIdentifier>,
|
|
/// The effectiveness of the different types against each other.
|
|
effectiveness: Vec<Vec<f32>>,
|
|
}
|
|
|
|
impl TypeLibrary {
|
|
/// Instantiates a new type library with a specific capacity.
|
|
pub fn new(capacity: usize) -> TypeLibrary {
|
|
TypeLibrary {
|
|
types: HashMap::with_capacity(capacity),
|
|
effectiveness: vec![],
|
|
}
|
|
}
|
|
|
|
/// Gets the type identifier for a type with a name.
|
|
pub fn get_type_id(&self, key: &StringKey) -> TypeIdentifier {
|
|
self.types[key]
|
|
}
|
|
|
|
/// Gets the effectiveness for a single attacking type against a single defending type.
|
|
pub fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32 {
|
|
self.effectiveness[attacking.val as usize][defending.val as usize]
|
|
}
|
|
|
|
/// Gets the effectiveness for a single attacking type against an amount of defending types.
|
|
/// This is equivalent to running [`get_single_effectiveness`] on each defending type, and
|
|
/// multiplying the results with each other.
|
|
pub fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> f32 {
|
|
let mut e = 1.0;
|
|
for def in defending {
|
|
e *= self.get_single_effectiveness(attacking, *def);
|
|
}
|
|
e
|
|
}
|
|
|
|
/// Registers a new type in the library.
|
|
pub fn register_type(&mut self, name: &StringKey) -> TypeIdentifier {
|
|
let id = TypeIdentifier {
|
|
val: self.types.len() as u8,
|
|
};
|
|
self.types.insert(name.clone(), id);
|
|
self.effectiveness.resize((id.val + 1) as usize, vec![]);
|
|
for effectiveness in &mut self.effectiveness {
|
|
effectiveness.resize((id.val + 1) as usize, 1.0)
|
|
}
|
|
id
|
|
}
|
|
|
|
/// Sets the effectiveness for an attacking type against a defending type.
|
|
pub fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32) {
|
|
self.effectiveness[attacking.val as usize][defending.val as usize] = effectiveness;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub mod tests {
|
|
use assert_approx_eq::assert_approx_eq;
|
|
|
|
use crate::static_data::libraries::type_library::TypeLibrary;
|
|
|
|
pub fn build() -> TypeLibrary {
|
|
let mut lib = TypeLibrary::new(2);
|
|
|
|
// Borrow as mut so we can insert
|
|
let w = &mut lib;
|
|
let t0 = w.register_type(&"foo".into());
|
|
let t1 = w.register_type(&"bar".into());
|
|
// Drops borrow as mut
|
|
|
|
w.set_effectiveness(t0, t1, 0.5);
|
|
w.set_effectiveness(t1, t0, 2.0);
|
|
|
|
lib
|
|
}
|
|
|
|
#[test]
|
|
fn add_two_types_retrieve_them() {
|
|
let mut lib = TypeLibrary::new(2);
|
|
|
|
// Borrow as mut so we can insert
|
|
let w = &mut lib;
|
|
let t0 = w.register_type(&"foo".into());
|
|
let t1 = w.register_type(&"bar".into());
|
|
// Drops borrow as mut
|
|
|
|
// Borrow as read so we can read
|
|
let r = &lib;
|
|
assert_eq!(r.get_type_id(&"foo".into()), t0);
|
|
assert_eq!(r.get_type_id(&"bar".into()), t1);
|
|
}
|
|
|
|
#[test]
|
|
fn add_two_types_set_effectiveness_retrieve() {
|
|
let mut lib = TypeLibrary::new(2);
|
|
|
|
// Borrow as mut so we can insert
|
|
let w = &mut lib;
|
|
let t0 = w.register_type(&"foo".into());
|
|
let t1 = w.register_type(&"bar".into());
|
|
w.set_effectiveness(t0, t1, 0.5);
|
|
w.set_effectiveness(t1, t0, 2.0);
|
|
// Drops borrow as mut
|
|
|
|
// Borrow as read so we can read
|
|
let r = &lib;
|
|
assert_approx_eq!(r.get_single_effectiveness(t0, t1), 0.5);
|
|
assert_approx_eq!(r.get_single_effectiveness(t1, t0), 2.0);
|
|
}
|
|
|
|
#[test]
|
|
fn add_two_types_get_aggregate_effectiveness() {
|
|
let mut lib = TypeLibrary::new(2);
|
|
|
|
// Borrow as mut so we can insert
|
|
let w = &mut lib;
|
|
let t0 = w.register_type(&"foo".into());
|
|
let t1 = w.register_type(&"bar".into());
|
|
w.set_effectiveness(t0, t1, 0.5);
|
|
w.set_effectiveness(t1, t0, 2.0);
|
|
// Drops borrow as mut
|
|
|
|
// Borrow as read so we can read
|
|
let r = &lib;
|
|
assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]), 0.25);
|
|
assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]), 4.0);
|
|
}
|
|
}
|