2023-04-19 16:44:11 +00:00
|
|
|
use anyhow_ext::Result;
|
2022-07-01 16:44:09 +00:00
|
|
|
use atomig::Atom;
|
2022-06-06 11:54:59 +00:00
|
|
|
use hashbrown::HashMap;
|
2023-06-24 12:44:23 +00:00
|
|
|
use parking_lot::{RwLock, RwLockReadGuard};
|
2023-04-19 16:44:11 +00:00
|
|
|
use std::fmt::{Debug, Display};
|
2021-01-30 21:29:59 +00:00
|
|
|
|
2023-06-24 12:44:23 +00:00
|
|
|
use crate::{PkmnError, StringKey};
|
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)]
|
2023-07-22 10:23:33 +00:00
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[repr(transparent)]
|
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 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-26 16:23:35 +00:00
|
|
|
impl From<TypeIdentifier> for u8 {
|
|
|
|
fn from(id: TypeIdentifier) -> Self {
|
|
|
|
id.val
|
2022-08-20 10:22:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-19 16:44:11 +00:00
|
|
|
impl Display for TypeIdentifier {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "TypeId({})", self.val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-24 11:00:50 +00:00
|
|
|
/// All data related to types and effectiveness.
|
2023-06-24 12:44:23 +00:00
|
|
|
pub trait TypeLibrary: Debug {
|
2022-12-24 11:00:50 +00:00
|
|
|
/// 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.
|
2023-04-19 16:44:11 +00:00
|
|
|
fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result<f32>;
|
2022-12-24 11:00:50 +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.
|
2023-04-19 16:44:11 +00:00
|
|
|
fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32>;
|
2022-12-24 11:00:50 +00:00
|
|
|
|
|
|
|
/// Registers a new type in the library.
|
2023-06-24 12:44:23 +00:00
|
|
|
fn register_type(&self, name: &StringKey) -> TypeIdentifier;
|
2022-12-24 11:00:50 +00:00
|
|
|
|
|
|
|
/// Sets the effectiveness for an attacking type against a defending type.
|
2023-06-24 12:44:23 +00:00
|
|
|
fn set_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32)
|
|
|
|
-> Result<()>;
|
2022-12-24 11:00:50 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 15:07:22 +00:00
|
|
|
/// All data related to types and effectiveness.
|
2021-01-30 21:29:59 +00:00
|
|
|
#[derive(Debug)]
|
2022-12-24 11:00:50 +00:00
|
|
|
pub struct TypeLibraryImpl {
|
2022-07-01 15:07:22 +00:00
|
|
|
/// A list of types
|
2023-06-24 12:44:23 +00:00
|
|
|
types: RwLock<HashMap<StringKey, TypeIdentifier>>,
|
2022-07-01 15:07:22 +00:00
|
|
|
/// The effectiveness of the different types against each other.
|
2023-06-24 12:44:23 +00:00
|
|
|
effectiveness: RwLock<Vec<Vec<f32>>>,
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
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 {
|
2023-06-24 12:44:23 +00:00
|
|
|
types: RwLock::new(HashMap::with_capacity(capacity)),
|
|
|
|
effectiveness: RwLock::new(vec![]),
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-24 11:00:50 +00:00
|
|
|
}
|
2021-01-30 21:29:59 +00:00
|
|
|
|
2023-06-24 12:44:23 +00:00
|
|
|
impl TypeLibraryImpl {
|
2023-06-24 13:05:58 +00:00
|
|
|
/// Helper function to get the effectiveness for a single attacking type against a single
|
|
|
|
/// defending type, without having to acquire read locks multiple times when used in a loop.
|
|
|
|
#[inline]
|
2023-06-24 12:44:23 +00:00
|
|
|
fn get_single_effectiveness_with_lock(
|
|
|
|
lock: &RwLockReadGuard<Vec<Vec<f32>>>,
|
|
|
|
attacking: TypeIdentifier,
|
|
|
|
defending: TypeIdentifier,
|
|
|
|
) -> Result<f32> {
|
|
|
|
Ok(*lock
|
|
|
|
.get((attacking.val - 1) as usize)
|
|
|
|
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
|
|
|
.get((defending.val - 1) as usize)
|
|
|
|
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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> {
|
2023-06-24 12:44:23 +00:00
|
|
|
self.types.read().get(key).cloned()
|
2022-10-01 13:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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> {
|
2023-06-24 12:44:23 +00:00
|
|
|
let types = self.types.read();
|
|
|
|
for kv in types.iter() {
|
2022-10-01 13:40:15 +00:00
|
|
|
if *kv.1 == t {
|
|
|
|
return Some(kv.0.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 15:07:22 +00:00
|
|
|
/// Gets the effectiveness for a single attacking type against a single defending type.
|
2023-04-19 16:44:11 +00:00
|
|
|
fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result<f32> {
|
2023-06-24 12:44:23 +00:00
|
|
|
Self::get_single_effectiveness_with_lock(&self.effectiveness.read(), attacking, defending)
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
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.
|
2023-04-19 16:44:11 +00:00
|
|
|
fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32> {
|
2021-01-30 21:29:59 +00:00
|
|
|
let mut e = 1.0;
|
2023-06-24 12:44:23 +00:00
|
|
|
let lock = self.effectiveness.read();
|
2021-01-30 21:29:59 +00:00
|
|
|
for def in defending {
|
2023-06-24 12:44:23 +00:00
|
|
|
e *= Self::get_single_effectiveness_with_lock(&lock, attacking, *def)?;
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
2023-04-19 16:44:11 +00:00
|
|
|
Ok(e)
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 15:07:22 +00:00
|
|
|
/// Registers a new type in the library.
|
2023-06-24 12:44:23 +00:00
|
|
|
fn register_type(&self, name: &StringKey) -> TypeIdentifier {
|
|
|
|
let mut types_write_lock = self.types.write();
|
|
|
|
let mut effectiveness_write_lock = self.effectiveness.write();
|
|
|
|
|
2022-07-01 15:07:22 +00:00
|
|
|
let id = TypeIdentifier {
|
2023-06-24 12:44:23 +00:00
|
|
|
val: (types_write_lock.len() + 1) as u8,
|
2022-07-01 15:07:22 +00:00
|
|
|
};
|
2023-06-24 12:44:23 +00:00
|
|
|
types_write_lock.insert(name.clone(), id);
|
|
|
|
effectiveness_write_lock.resize((id.val) as usize, vec![]);
|
|
|
|
for effectiveness in &mut effectiveness_write_lock.iter_mut() {
|
2022-10-01 13:40:15 +00:00
|
|
|
effectiveness.resize((id.val) as usize, 1.0)
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2022-07-01 15:07:22 +00:00
|
|
|
/// Sets the effectiveness for an attacking type against a defending type.
|
2023-04-19 16:44:11 +00:00
|
|
|
fn set_effectiveness(
|
2023-06-24 12:44:23 +00:00
|
|
|
&self,
|
2023-04-19 16:44:11 +00:00
|
|
|
attacking: TypeIdentifier,
|
|
|
|
defending: TypeIdentifier,
|
|
|
|
effectiveness: f32,
|
|
|
|
) -> Result<()> {
|
|
|
|
*self
|
|
|
|
.effectiveness
|
2023-06-24 12:44:23 +00:00
|
|
|
.write()
|
2023-04-19 16:44:11 +00:00
|
|
|
.get_mut((attacking.val - 1) as usize)
|
|
|
|
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
|
|
|
.get_mut((defending.val - 1) as usize)
|
|
|
|
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })? = effectiveness;
|
|
|
|
Ok(())
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2023-04-19 16:44:11 +00:00
|
|
|
#[allow(clippy::indexing_slicing)]
|
|
|
|
#[allow(clippy::unwrap_used)]
|
2021-01-31 16:31:22 +00:00
|
|
|
pub mod tests {
|
2021-01-30 21:29:59 +00:00
|
|
|
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);
|
2021-01-31 16:31:22 +00:00
|
|
|
|
|
|
|
// 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());
|
2021-01-31 16:31:22 +00:00
|
|
|
// Drops borrow as mut
|
|
|
|
|
2023-04-19 16:44:11 +00:00
|
|
|
w.set_effectiveness(t0, t1, 0.5).unwrap();
|
|
|
|
w.set_effectiveness(t1, t0, 2.0).unwrap();
|
2021-01-31 16:31:22 +00:00
|
|
|
|
|
|
|
lib
|
|
|
|
}
|
|
|
|
|
2021-01-30 21:29:59 +00:00
|
|
|
#[test]
|
|
|
|
fn add_two_types_retrieve_them() {
|
2022-12-24 11:00:50 +00:00
|
|
|
let mut lib = TypeLibraryImpl::new(2);
|
2021-01-30 21:29:59 +00:00
|
|
|
|
|
|
|
// 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());
|
2021-01-30 21:29:59 +00:00
|
|
|
// 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);
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_two_types_set_effectiveness_retrieve() {
|
2022-12-24 11:00:50 +00:00
|
|
|
let mut lib = TypeLibraryImpl::new(2);
|
2021-01-30 21:29:59 +00:00
|
|
|
|
|
|
|
// 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());
|
2023-04-19 16:44:11 +00:00
|
|
|
w.set_effectiveness(t0, t1, 0.5).unwrap();
|
|
|
|
w.set_effectiveness(t1, t0, 2.0).unwrap();
|
2021-01-30 21:29:59 +00:00
|
|
|
// Drops borrow as mut
|
|
|
|
|
|
|
|
// Borrow as read so we can read
|
|
|
|
let r = &lib;
|
2023-04-19 16:44:11 +00:00
|
|
|
assert_approx_eq!(r.get_single_effectiveness(t0, t1).unwrap(), 0.5);
|
|
|
|
assert_approx_eq!(r.get_single_effectiveness(t1, t0).unwrap(), 2.0);
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_two_types_get_aggregate_effectiveness() {
|
2022-12-24 11:00:50 +00:00
|
|
|
let mut lib = TypeLibraryImpl::new(2);
|
2021-01-30 21:29:59 +00:00
|
|
|
|
|
|
|
// 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());
|
2023-04-19 16:44:11 +00:00
|
|
|
w.set_effectiveness(t0, t1, 0.5).unwrap();
|
|
|
|
w.set_effectiveness(t1, t0, 2.0).unwrap();
|
2021-01-30 21:29:59 +00:00
|
|
|
// Drops borrow as mut
|
|
|
|
|
|
|
|
// Borrow as read so we can read
|
|
|
|
let r = &lib;
|
2023-04-19 16:44:11 +00:00
|
|
|
assert_approx_eq!(r.get_effectiveness(t0, &[t1, t1]).unwrap(), 0.25);
|
|
|
|
assert_approx_eq!(r.get_effectiveness(t1, &[t0, t0]).unwrap(), 4.0);
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|
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());
|
|
|
|
}
|
2021-01-30 21:29:59 +00:00
|
|
|
}
|