fantasy_realms_unofficial_api 0.1.0

An unofficial API for the Fantasy Realms card game.
Documentation
use strum_macros::EnumIter;

use crate::card_collection::*;
use crate::hand::*;

/// All card names in the game.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, EnumIter)]
pub enum Name {
    Mountain,         Cavern,           BellTower,        Forest,           EarthElemental,
    FountainOfLife,   Swamp,            GreatFlood,       Island,           WaterElemental,
    Rainstorm,        Blizzard,         Smoke,            Whirlwind,        AirElemental,
    Wildfire,         Candle,           Forge,            Lightning,        FireElemental,
    Knights,          ElvenArchers,     LightCavalry,     DwarvishInfantry, Rangers,
    Collector,        Beastmaster,      Necromancer,      WarlockLord,      Enchantress,
    King,             Queen,            Princess,         Warlord,          Empress,
    Unicorn,          Basilisk,         Warhorse,         Dragon,           Hydra,
    Warship,          MagicWand,        SwordOfKeth,      ElvenLongbow,     WarDirigible,
    ShieldOfKeth,     GemOfOrder,       WorldTree,        BookOfChanges,    ProtectionRune,
    Shapeshifter,     Mirage,           Doppelganger,
}

/// All suits in the game.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, EnumIter)]
pub enum Suit {
    Land,
    Flood,
    Weather,
    Flame,
    Army,
    Wizard,
    Leader,
    Beast,
    Weapon,
    Artifact,
    Wild,
}

pub(crate) mod mountain;           pub(crate) use mountain::MOUNTAIN;
pub(crate) mod cavern;             pub(crate) use cavern::CAVERN;
pub(crate) mod bell_tower;         pub(crate) use bell_tower::BELL_TOWER;
pub(crate) mod forest;             pub(crate) use forest::FOREST;
pub(crate) mod earth_elemental;    pub(crate) use earth_elemental::EARTH_ELEMENTAL;
pub(crate) mod fountain_of_life;   pub(crate) use fountain_of_life::FOUNTAIN_OF_LIFE;
pub(crate) mod swamp;              pub(crate) use swamp::SWAMP;
pub(crate) mod great_flood;        pub(crate) use great_flood::GREAT_FLOOD;
pub(crate) mod island;             pub(crate) use island::ISLAND;
pub(crate) mod water_elemental;    pub(crate) use water_elemental::WATER_ELEMENTAL;
pub(crate) mod rainstorm;          pub(crate) use rainstorm::RAINSTORM;
pub(crate) mod blizzard;           pub(crate) use blizzard::BLIZZARD;
pub(crate) mod smoke;              pub(crate) use smoke::SMOKE;
pub(crate) mod whirlwind;          pub(crate) use whirlwind::WHIRLWIND;
pub(crate) mod air_elemental;      pub(crate) use air_elemental::AIR_ELEMENTAL;
pub(crate) mod wildfire;           pub(crate) use wildfire::WILDFIRE;
pub(crate) mod candle;             pub(crate) use candle::CANDLE;
pub(crate) mod forge;              pub(crate) use forge::FORGE;
pub(crate) mod lightning;          pub(crate) use lightning::LIGHTNING;
pub(crate) mod fire_elemental;     pub(crate) use fire_elemental::FIRE_ELEMENTAL;
pub(crate) mod knights;            pub(crate) use knights::KNIGHTS;
pub(crate) mod elven_archers;      pub(crate) use elven_archers::ELVEN_ARCHERS;
pub(crate) mod light_cavalry;      pub(crate) use light_cavalry::LIGHT_CAVALRY;
pub(crate) mod dwarvish_infantry;  pub(crate) use dwarvish_infantry::DWARVISH_INFANTRY;
pub(crate) mod rangers;            pub(crate) use rangers::RANGERS;
pub(crate) mod collector;          pub(crate) use collector::COLLECTOR;
pub(crate) mod beastmaster;        pub(crate) use beastmaster::BEASTMASTER;
pub(crate) mod necromancer;        pub(crate) use necromancer::NECROMANCER;
pub(crate) mod warlock_lord;       pub(crate) use warlock_lord::WARLOCK_LORD;
pub(crate) mod enchantress;        pub(crate) use enchantress::ENCHANTRESS;
pub(crate) mod king;               pub(crate) use king::KING;
pub(crate) mod queen;              pub(crate) use queen::QUEEN;
pub(crate) mod princess;           pub(crate) use princess::PRINCESS;
pub(crate) mod warlord;            pub(crate) use warlord::WARLORD;
pub(crate) mod empress;            pub(crate) use empress::EMPRESS;
pub(crate) mod unicorn;            pub(crate) use unicorn::UNICORN;
pub(crate) mod basilisk;           pub(crate) use basilisk::BASILISK;
pub(crate) mod warhorse;           pub(crate) use warhorse::WARHORSE;
pub(crate) mod dragon;             pub(crate) use dragon::DRAGON;
pub(crate) mod hydra;              pub(crate) use hydra::HYDRA;
pub(crate) mod warship;            pub(crate) use warship::WARSHIP;
pub(crate) mod magic_wand;         pub(crate) use magic_wand::MAGIC_WAND;
pub(crate) mod sword_of_keth;      pub(crate) use sword_of_keth::SWORD_OF_KETH;
pub(crate) mod elven_longbow;      pub(crate) use elven_longbow::ELVEN_LONGBOW;
pub(crate) mod war_dirigible;      pub(crate) use war_dirigible::WAR_DIRIGIBLE;
pub(crate) mod shield_of_keth;     pub(crate) use shield_of_keth::SHIELD_OF_KETH;
pub(crate) mod gem_of_order;       pub(crate) use gem_of_order::GEM_OF_ORDER;
pub(crate) mod world_tree;         pub(crate) use world_tree::WORLD_TREE;
pub(crate) mod book_of_changes;    pub(crate) use book_of_changes::BOOK_OF_CHANGES;
pub(crate) mod protection_rune;    pub(crate) use protection_rune::PROTECTION_RUNE;
pub(crate) mod shapeshifter;       pub(crate) use shapeshifter::SHAPESHIFTER;
pub(crate) mod mirage;             pub(crate) use mirage::MIRAGE;
pub(crate) mod doppelganger;       pub(crate) use doppelganger::DOPPELGANGER;

/// Represents a card.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Card {
    /// The name of the card.
    pub(crate) name: Name,
    /// The suit of the card.
    pub(crate) suit: Suit,
    /// The base strength of the card.
    pub(crate) strength: i16,
    /// A function that adds cards to the hand.
    /// # Arguments
    /// * hand - A `&Vec<Card>` representing the hand the card is in.
    /// * discard_pile - A `&CardCollection` representing the cards in the discard pile.
    /// # Returns
    /// A `Vec<Vec<Card>>` all possible hands that can be created with this card.
    pub(crate) adder: Option<fn(&Vec<Card>, &CardCollection) -> Vec<Vec<Card>>>,
    /// A function that transforms this card into other cards.
    /// # Arguments
    /// * hand - A `&Vec<Card>` representing the hand the card is in.
    /// * index - A `usize` representing the location of the card in the hand.
    /// # Returns
    /// A `Vec<Vec<Card>>` all possible hands that can be created with this card.
    pub(crate) wild: Option<fn(&Vec<Card>, usize) -> Vec<Vec<Card>>>,
    /// A function that modifies other cards in the hand.
    /// # Arguments
    /// * hand - A `&Vec<Card>` representing the hand the card is in.
    /// # Returns
    /// A `Vec<Vec<Card>>` all possible hands that can be created with this card.
    pub(crate) modifier: Option<fn(&Vec<Card>) -> Vec<Vec<Card>>>,
    /// A function that makes cards immune to penalties.
    /// # Arguments
    /// * immunity - A `&mut CardCollection` representing the cards that are excluded from penalties.
    /// # Side Effects
    /// * **immunity**:
    ///    * Adds the cards that are excluded from penalties.
    pub(crate) immunity: Option<fn(&mut CardCollection)>,
    /// A function that blanks other cards.
    /// # Arguments
    /// * hand - A `&Vec<Card>` representing the hand the card is in.
    /// * immunity - A `&CardCollection` representing the cards that are excluded from penalties.
    /// * blanks - A `&mut CardCollection` representing the cards that are excluded from penalties.
    /// # Side Effects
    /// * **blanks**:
    ///    * Adds the cards that are blanked.
    pub(crate) blanks: Option<fn(&Vec<Card>, &CardCollection, &mut CardCollection)>,
    /// A function that finds the bonus of the card.
    /// # Arguments 
    /// * hand - A `&ScoringHand` representing the hand the card is in.
    /// # Returns 
    /// An `i16` representing what is added to the score due to the bonus. 
    pub(crate) bonus: Option<fn(&ScoringHand) -> i16>,
    /// A function that finds the penalty of the card.
    /// # Arguments 
    /// * hand - A `&ScoringHand` representing the hand the card is in.
    /// * immunity - A `&CardCollection` representing the cards that are excluded from penalties.
    /// # Returns 
    /// An `i16` representing what is subtracted from the score due to the penalty.
    pub(crate) penalty: Option<fn(&ScoringHand, &CardCollection) -> i16>,
}

use std::fmt;
impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let name = match self.name {
            Name::Mountain          => "mountain",
            Name::Cavern            => "cavern",
            Name::BellTower         => "bell tower",
            Name::Forest            => "forest",
            Name::EarthElemental    => "earth elemental",
            Name::FountainOfLife    => "fountain of life",
            Name::Swamp             => "swamp",
            Name::GreatFlood        => "great flood",
            Name::Island            => "island",
            Name::WaterElemental    => "water elemental",
            Name::Rainstorm         => "rainstorm",
            Name::Blizzard          => "blizzard",
            Name::Smoke             => "smoke",
            Name::Whirlwind         => "whirlwind",
            Name::AirElemental      => "air elemental",
            Name::Wildfire          => "wild fire",
            Name::Candle            => "candle",
            Name::Forge             => "forge",
            Name::Lightning         => "lightning",
            Name::FireElemental     => "fire elemental",
            Name::Knights           => "knights",
            Name::ElvenArchers      => "elven archers",
            Name::LightCavalry      => "light cavalry",
            Name::DwarvishInfantry  => "dwarvish infantry",
            Name::Rangers           => "rangers",
            Name::Collector         => "collector",
            Name::Beastmaster       => "beastmaster",
            Name::Necromancer       => "necromancer",
            Name::WarlockLord       => "warlock lord",
            Name::Enchantress       => "enchantress",
            Name::King              => "king",
            Name::Queen             => "queen",
            Name::Princess          => "princess",
            Name::Warlord           => "warlord",
            Name::Empress           => "empress",
            Name::Unicorn           => "unicorn",
            Name::Basilisk          => "basilisk",
            Name::Warhorse          => "warhorse",
            Name::Dragon            => "dragon",
            Name::Hydra             => "hydra",
            Name::Warship           => "warship",
            Name::MagicWand         => "magic wand",
            Name::SwordOfKeth       => "sword of keth",
            Name::ElvenLongbow      => "elven longbow",
            Name::WarDirigible      => "war dirigible",
            Name::ShieldOfKeth      => "shield of keth",
            Name::GemOfOrder        => "gem of order",
            Name::WorldTree         => "world tree",
            Name::BookOfChanges     => "book of changes",
            Name::ProtectionRune    => "protection rune",
            Name::Shapeshifter      => "shapeshifter",
            Name::Mirage            => "mirage",
            Name::Doppelganger      => "doppelganger",
        };
        write!(f, "{}", name)
    }
}

use std::str::FromStr;
impl FromStr for Card {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "mountain"           => Ok(MOUNTAIN),
            "cavern"            => Ok(CAVERN),
            "bell tower"        => Ok(BELL_TOWER),
            "forest"            => Ok(FOREST),
            "earth elemental"   => Ok(EARTH_ELEMENTAL),
            "fountain of life"  => Ok(FOUNTAIN_OF_LIFE),
            "swamp"             => Ok(SWAMP),
            "great flood"       => Ok(GREAT_FLOOD),  
            "island"            => Ok(ISLAND),
            "water elemental"   => Ok(WATER_ELEMENTAL),
            "rainstorm"         => Ok(RAINSTORM),
            "blizzard"          => Ok(BLIZZARD),
            "smoke"             => Ok(SMOKE),
            "whirlwind"         => Ok(WHIRLWIND),
            "air elemental"     => Ok(AIR_ELEMENTAL),
            "wildfire"         => Ok(WILDFIRE),
            "candle"            => Ok(CANDLE),
            "forge"             => Ok(FORGE),
            "lightning"         => Ok(LIGHTNING),
            "fire elemental"    => Ok(FIRE_ELEMENTAL),
            "knights"           => Ok(KNIGHTS),
            "elven archers"     => Ok(ELVEN_ARCHERS),
            "light cavalry"     => Ok(LIGHT_CAVALRY), 
            "dwarvish infantry" => Ok(DWARVISH_INFANTRY), 
            "rangers"           => Ok(RANGERS),
            "collector"         => Ok(COLLECTOR),
            "beastmaster"       => Ok(BEASTMASTER),
            "necromancer"       => Ok(NECROMANCER),  
            "warlock lord"      => Ok(WARLOCK_LORD),
            "enchantress"       => Ok(ENCHANTRESS),
            "king"              => Ok(KING),
            "queen"             => Ok(QUEEN),
            "princess"          => Ok(PRINCESS),
            "warlord"           => Ok(WARLORD),
            "empress"           => Ok(EMPRESS),
            "unicorn"           => Ok(UNICORN),
            "basilisk"          => Ok(BASILISK),
            "warhorse"          => Ok(WARHORSE),
            "dragon"            => Ok(DRAGON),
            "hydra"             => Ok(HYDRA),
            "warship"           => Ok(WARSHIP),
            "magic wand"        => Ok(MAGIC_WAND),
            "sword of keth"     => Ok(SWORD_OF_KETH),
            "elven longbow"     => Ok(ELVEN_LONGBOW),
            "war dirigible"     => Ok(WAR_DIRIGIBLE),
            "shield of keth"    => Ok(SHIELD_OF_KETH),
            "gem of order"      => Ok(GEM_OF_ORDER),
            "world tree"        => Ok(WORLD_TREE),
            "book of changes"   => Ok(BOOK_OF_CHANGES),
            "protection rune"   => Ok(PROTECTION_RUNE),
            "shapeshifter"      => Ok(SHAPESHIFTER),
            "mirage"            => Ok(MIRAGE),
            "doppelganger"      => Ok(DOPPELGANGER),
            _ => Err("Invalid card name.".to_string()),
        }
    }
}

impl From<Name> for Card {
    fn from(n: Name) -> Self {
        match n {
            Name::Mountain         => MOUNTAIN,
            Name::Cavern           => CAVERN,
            Name::BellTower        => BELL_TOWER,
            Name::Forest           => FOREST,
            Name::EarthElemental   => EARTH_ELEMENTAL,
            Name::FountainOfLife   => FOUNTAIN_OF_LIFE,
            Name::Swamp            => SWAMP,
            Name::GreatFlood       => GREAT_FLOOD,
            Name::Island           => ISLAND,
            Name::WaterElemental   => WATER_ELEMENTAL,
            Name::Rainstorm        => RAINSTORM,
            Name::Blizzard         => BLIZZARD,
            Name::Smoke            => SMOKE,
            Name::Whirlwind        => WHIRLWIND,
            Name::AirElemental     => AIR_ELEMENTAL,
            Name::Wildfire         => WILDFIRE,
            Name::Candle           => CANDLE,
            Name::Forge            => FORGE,
            Name::Lightning        => LIGHTNING,
            Name::FireElemental    => FIRE_ELEMENTAL,
            Name::Knights          => KNIGHTS,
            Name::ElvenArchers     => ELVEN_ARCHERS,
            Name::LightCavalry     => LIGHT_CAVALRY,
            Name::DwarvishInfantry => DWARVISH_INFANTRY,
            Name::Rangers          => RANGERS,
            Name::Collector        => COLLECTOR,
            Name::Beastmaster      => BEASTMASTER,
            Name::Necromancer      => NECROMANCER,
            Name::WarlockLord      => WARLOCK_LORD,
            Name::Enchantress      => ENCHANTRESS,
            Name::King             => KING,
            Name::Queen            => QUEEN,
            Name::Princess         => PRINCESS,
            Name::Warlord          => WARLORD,
            Name::Empress          => EMPRESS,
            Name::Unicorn          => UNICORN,
            Name::Basilisk         => BASILISK,
            Name::Warhorse         => WARHORSE,
            Name::Dragon           => DRAGON,
            Name::Hydra            => HYDRA,
            Name::Warship          => WARSHIP,
            Name::MagicWand        => MAGIC_WAND,
            Name::SwordOfKeth      => SWORD_OF_KETH,
            Name::ElvenLongbow     => ELVEN_LONGBOW,
            Name::WarDirigible     => WAR_DIRIGIBLE,
            Name::ShieldOfKeth     => SHIELD_OF_KETH,
            Name::GemOfOrder       => GEM_OF_ORDER,
            Name::WorldTree        => WORLD_TREE,
            Name::BookOfChanges    => BOOK_OF_CHANGES,
            Name::ProtectionRune   => PROTECTION_RUNE,
            Name::Shapeshifter     => SHAPESHIFTER,
            Name::Mirage           => MIRAGE,
            Name::Doppelganger     => DOPPELGANGER,
        }
    }
}

impl From<u8> for Card {
    fn from(n: u8) -> Self {
        match n {
            0  => MOUNTAIN,
            1  => CAVERN,
            2  => BELL_TOWER,
            3  => FOREST,
            4  => EARTH_ELEMENTAL,
            5  => FOUNTAIN_OF_LIFE,
            6  => SWAMP,
            7  => GREAT_FLOOD,
            8  => ISLAND,
            9  => WATER_ELEMENTAL,
            10 => RAINSTORM,
            11 => BLIZZARD,
            12 => SMOKE,
            13 => WHIRLWIND,
            14 => AIR_ELEMENTAL,
            15 => WILDFIRE,
            16 => CANDLE,
            17 => FORGE,
            18 => LIGHTNING,
            19 => FIRE_ELEMENTAL,
            20 => KNIGHTS,
            21 => ELVEN_ARCHERS,
            22 => LIGHT_CAVALRY,
            23 => DWARVISH_INFANTRY,
            24 => RANGERS,
            25 => COLLECTOR,
            26 => BEASTMASTER,
            27 => NECROMANCER,
            28 => WARLOCK_LORD,
            29 => ENCHANTRESS,
            30 => KING,
            31 => QUEEN,
            32 => PRINCESS,
            33 => WARLORD,
            34 => EMPRESS,
            35 => UNICORN,
            36 => BASILISK,
            37 => WARHORSE,
            38 => DRAGON,
            39 => HYDRA,
            40 => WARSHIP,
            41 => MAGIC_WAND,
            42 => SWORD_OF_KETH,
            43 => ELVEN_LONGBOW,
            44 => WAR_DIRIGIBLE,
            45 => SHIELD_OF_KETH,
            46 => GEM_OF_ORDER,
            47 => WORLD_TREE,
            48 => BOOK_OF_CHANGES,
            49 => PROTECTION_RUNE,
            50 => SHAPESHIFTER,
            51 => MIRAGE,
            52 => DOPPELGANGER,
            _  => panic!("Invalid card index: {}", n),
        }
    }
}