PkmnLib_rs/src/static_data/libraries/type_library.rs

220 lines
7.2 KiB
Rust
Raw Normal View History

2022-07-01 16:44:09 +00:00
use atomig::Atom;
2022-06-06 11:54:59 +00:00
use hashbrown::HashMap;
2022-12-24 11:00:50 +00:00
use std::fmt::Debug;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier};
2022-07-01 15:07:22 +00:00
/// A unique key that can be used to store a reference to a type. Opaque reference to a byte
/// internally.
2022-07-01 16:44:09 +00:00
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Atom)]
2022-09-18 16:02:13 +00:00
#[repr(C)]
2022-07-01 15:07:22 +00:00
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
2022-08-20 10:22:12 +00:00
}
}
2022-12-24 11:00:50 +00:00
/// All data related to types and effectiveness.
pub trait TypeLibrary: Debug + ValueIdentifiable {
/// Gets the type identifier for a type with a name.
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier>;
/// Gets the type name from the type identifier.
fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey>;
/// Gets the effectiveness for a single attacking type against a single defending type.
fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32;
/// 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.
fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> f32;
/// Registers a new type in the library.
fn register_type(&mut self, name: &StringKey) -> TypeIdentifier;
/// Sets the effectiveness for an attacking type against a defending type.
fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32);
}
2022-07-01 15:07:22 +00:00
/// All data related to types and effectiveness.
#[derive(Debug)]
2022-12-24 11:00:50 +00:00
pub struct TypeLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
2022-07-01 15:07:22 +00:00
/// A list of types
types: HashMap<StringKey, TypeIdentifier>,
/// The effectiveness of the different types against each other.
effectiveness: Vec<Vec<f32>>,
}
2022-12-24 11:00:50 +00:00
impl TypeLibraryImpl {
2022-07-01 15:07:22 +00:00
/// Instantiates a new type library with a specific capacity.
2022-12-24 11:00:50 +00:00
pub fn new(capacity: usize) -> Self {
Self {
identifier: Default::default(),
types: HashMap::with_capacity(capacity),
effectiveness: vec![],
}
}
2022-12-24 11:00:50 +00:00
}
2022-12-24 11:00:50 +00:00
impl TypeLibrary for TypeLibraryImpl {
2022-07-01 15:07:22 +00:00
/// Gets the type identifier for a type with a name.
2022-12-24 11:00:50 +00:00
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> {
2022-10-01 13:40:15 +00:00
self.types.get(key).cloned()
}
/// Gets the type name from the type identifier.
2022-12-24 11:00:50 +00:00
fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey> {
2022-10-01 13:40:15 +00:00
for kv in &self.types {
if *kv.1 == t {
return Some(kv.0.clone());
}
}
None
}
2022-07-01 15:07:22 +00:00
/// Gets the effectiveness for a single attacking type against a single defending type.
2022-12-24 11:00:50 +00:00
fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> f32 {
2022-10-01 13:40:15 +00:00
self.effectiveness[(attacking.val - 1) as usize][(defending.val - 1) as usize]
}
2022-07-01 15:07:22 +00:00
/// 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.
2022-12-24 11:00:50 +00:00
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
}
2022-07-01 15:07:22 +00:00
/// Registers a new type in the library.
2022-12-24 11:00:50 +00:00
fn register_type(&mut self, name: &StringKey) -> TypeIdentifier {
2022-07-01 15:07:22 +00:00
let id = TypeIdentifier {
2022-10-01 13:40:15 +00:00
val: (self.types.len() + 1) as u8,
2022-07-01 15:07:22 +00:00
};
self.types.insert(name.clone(), id);
2022-10-01 13:40:15 +00:00
self.effectiveness.resize((id.val) as usize, vec![]);
for effectiveness in &mut self.effectiveness {
2022-10-01 13:40:15 +00:00
effectiveness.resize((id.val) as usize, 1.0)
}
id
}
2022-07-01 15:07:22 +00:00
/// Sets the effectiveness for an attacking type against a defending type.
2022-12-24 11:00:50 +00:00
fn set_effectiveness(&mut self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32) {
2022-10-01 13:40:15 +00:00
self.effectiveness[(attacking.val - 1) as usize][(defending.val - 1) as usize] = effectiveness;
}
}
2022-12-24 11:00:50 +00:00
impl ValueIdentifiable for TypeLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)]
pub mod tests {
use assert_approx_eq::assert_approx_eq;
2022-12-24 11:00:50 +00:00
use super::*;
2022-07-01 15:07:22 +00:00
use crate::static_data::libraries::type_library::TypeLibrary;
2022-12-24 11:00:50 +00:00
pub fn build() -> TypeLibraryImpl {
let mut lib = TypeLibraryImpl::new(2);
// Borrow as mut so we can insert
let w = &mut lib;
2022-07-01 15:07:22 +00:00
let t0 = w.register_type(&"foo".into());
let t1 = w.register_type(&"bar".into());
// Drops borrow as mut
2022-07-01 15:07:22 +00:00
w.set_effectiveness(t0, t1, 0.5);
w.set_effectiveness(t1, t0, 2.0);
lib
}
#[test]
fn add_two_types_retrieve_them() {
2022-12-24 11:00:50 +00:00
let mut lib = TypeLibraryImpl::new(2);
// Borrow as mut so we can insert
let w = &mut lib;
2022-07-01 15:07:22 +00:00
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;
2022-10-01 13:40:15 +00:00
assert_eq!(r.get_type_id(&"foo".into()).unwrap(), t0);
assert_eq!(r.get_type_id(&"bar".into()).unwrap(), t1);
}
#[test]
fn add_two_types_set_effectiveness_retrieve() {
2022-12-24 11:00:50 +00:00
let mut lib = TypeLibraryImpl::new(2);
// Borrow as mut so we can insert
let w = &mut lib;
2022-07-01 15:07:22 +00:00
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;
2022-07-01 15:07:22 +00:00
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() {
2022-12-24 11:00:50 +00:00
let mut lib = TypeLibraryImpl::new(2);
// Borrow as mut so we can insert
let w = &mut lib;
2022-07-01 15:07:22 +00:00
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;
2022-07-01 15:07:22 +00:00
assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]), 0.25);
assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]), 4.0);
}
2022-11-26 14:33:50 +00:00
#[test]
fn add_two_types_get_type_name() {
2022-12-24 11:00:50 +00:00
let mut lib = TypeLibraryImpl::new(2);
2022-11-26 14:33:50 +00:00
// 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_name(t0).unwrap(), "foo".into());
assert_eq!(r.get_type_name(t1).unwrap(), "bar".into());
}
}