use dicebag::DiceExt;
use serde::{Deserialize, Deserializer, Serialize};
use crate::resolve::resolve_in_place::ResolveInPlace;
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone, Copy)]
pub enum Gender {
Unspecified,
Male,
Female,
NeverApplicable,
}
impl PartialOrd for Gender {
fn partial_cmp(&self, _: &Self) -> Option<std::cmp::Ordering> {
Some(std::cmp::Ordering::Equal)
}
}
fn bias10_filter<'de, D>(deserializer: D) -> Result<u32, D::Error>
where D: Deserializer<'de> {
let v = u32::deserialize(deserializer)?;
Ok(v.min(10))
}
#[derive(Debug, Deserialize, Clone, Copy)]
pub struct Bias10 {
#[serde(deserialize_with = "bias10_filter")]
value: u32,
}
impl Default for Bias10 {
fn default() -> Self {
Self { value: 0 }
}
}
#[derive(Debug, Deserialize, Clone, Copy)]
pub enum GenderBias {
Male(Bias10),
Male23,
Female(Bias10),
Female23,
None
}
impl Default for GenderBias {
fn default() -> Self {
Self::None }
}
pub trait HasGenderBias {
fn gender_bias(&self) -> GenderBias;
}
impl Gender {
pub fn random() -> Self {
Self::random_biased(GenderBias::None)
}
pub fn random_biased(bias: GenderBias) -> Self {
if 1.d20() +
match bias {
GenderBias::Male23 => -3, GenderBias::Male(v) => -(v.value as i32),
GenderBias::Female23 => 4, GenderBias::Female(v) => v.value as i32,
_ => 0
} <= 10 { Self::Male }
else { Self::Female }
}
pub fn get_or_random(&self) -> Self {
match self {
Self::Unspecified => Self::random_biased(GenderBias::None),
_ => *self
}
}
pub fn resolve_biased(&mut self, bias: GenderBias) {
match self {
Self::Unspecified => *self = Self::random_biased(bias),
_ => ()
}
}
}
impl From<&str> for Gender {
fn from(value: &str) -> Self {
match value.to_lowercase().as_str() {
"m"|"male"|"mies" => Gender::Male,
"f"|"n"|"female"|"nainen"|"t"|"tyttö"|"tytto" => Gender::Female,
_ => unimplemented!("No such gender as '{value}' defined.")
}
}
}
impl From<Option<String>> for Gender {
fn from(value: Option<String>) -> Self {
if let Some(value) = value {
Self::from(value.as_str())
} else {
Self::random()
}
}
}
pub trait HasGender {
fn gender(&self) -> Gender;
}
impl Default for Gender {
fn default() -> Self {
Self::Unspecified
}
}
impl ResolveInPlace for Gender {
fn resolve(&mut self) {
match self {
Self::Unspecified => *self = Self::random_biased(GenderBias::None),
_ => ()
}
}
}