X7KNY5KWCOLA2V345PUT4EVXVNHL6RGSJK3NNR6DHPOUC33HHCCAC
use regex::Regex;
use std::{
collections::{HashMap, HashSet},
sync::{Arc, Mutex, OnceLock},
};
#[derive(Debug, Clone)]
pub enum Card {
Magister {},
Fragment {},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FragmentProperties {
/// Is not sent to the graveyard on resolution
Lingering,
/// Must be Set before it can be activated
Prepared,
/// Can be activated during any time GES is half-closed
/// (as compared to the default of whes GES is open during *your* Main Phase(s))
Impulse,
/// Can be activated the turn it is set.
Rush,
}
pub enum Card {}
pub struct Subtype(HashSet<Arc<str>>);
impl Subtype {
pub fn new<S: AsRef<str>>(subtype: S) -> Self {
Self(
subtype
.as_ref()
.trim()
.to_lowercase()
.split_whitespace()
.map(|s| Arc::from(s))
.collect(),
)
}
/// Provide an [`Iterator`] of all subtypes
pub fn subtypes(&self) -> impl ExactSizeIterator<Item = &str> {
self.0.iter().map(|s| s.as_ref())
}
/// Check if this subtype is a member of a given subtype group
pub fn is_member<S: AsRef<str>>(&self, member: S) -> bool {
let member = member.as_ref().to_lowercase();
self.0.iter().any(|sm| sm.as_ref() == member)
}
/// Check if this subtype is a quasimember of a given subtype group
pub fn is_quasimember<S: AsRef<str>>(&self, quasimember: S) -> bool {
static SUBTYPE_REGEXES: OnceLock<Mutex<HashMap<Arc<str>, Regex>>> = OnceLock::new();
let mut subtype_regex_map = SUBTYPE_REGEXES
.get_or_init(|| Mutex::new(HashMap::new()))
.lock()
.unwrap();
let subtype_regex = subtype_regex_map
.entry(Arc::from(quasimember.as_ref()))
.or_insert(
Regex::new(&format!(
r"\b{}\b",
regex::escape(&quasimember.as_ref().to_lowercase())
))
.unwrap(),
);
self.0.iter().any(|sm| subtype_regex.is_match(&sm))
}
}
#[cfg(test)]
mod tests {
use super::Subtype;
#[test]
fn membership_will_only_match_whole_subtypes() {
let subtype = Subtype::new("Mad Relic");
let subtype2 = Subtype::new("Mad-Devouring Dragon");
assert!(subtype.is_member("Mad"));
assert!(!subtype2.is_member("Mad"));
}
#[test]
fn quasimembership_matches_words_in_subtypes() {
let subtype = Subtype::new("Mad Relic");
let subtype2 = Subtype::new("Mad-Devouring Dragon");
assert!(subtype.is_quasimember("Mad"));
assert!(subtype2.is_quasimember("Mad"));
assert!(!subtype2.is_quasimember("evo"));
}
#[test]
fn membership_and_quasimembership_are_caseinsensitive() {
let subtype = Subtype::new("Magic-Spellcaster Ruler");
assert!(subtype.is_member("MAGIC-SPELLCASTER"));
assert!(subtype.is_quasimember("SPELLcAsTeR"));
}
}