tbg 0.1.3

A library for implementing turn based games logic
Documentation
pub use crate::card::Card;
pub use crate::cardinal::Point;
pub use crate::grid::Grid;
pub use crate::misc::{LayeredEffect, Phase, Zone};
pub use crate::player::Player;
pub use crate::usize_wrapper::{CardID, DeckID, GridID, IDCounter, PlayerID};
use rand::seq::SliceRandom;
use rand::Rng;
use std::collections::{BTreeMap, VecDeque};
use std::fmt::Debug;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
pub struct Deck<DeckType> {
    id: DeckID,
    deck_type: DeckType,
    cards: Vec<CardID>,
    owner: Option<PlayerID>,
}

impl<DeckType> Deck<DeckType>
where
    DeckType: Clone + Eq,
{
    pub fn id(&self) -> DeckID {
        self.id
    }

    pub fn size(&self) -> usize {
        self.cards.len()
    }

    pub fn top(&self) -> Option<CardID> {
        self.cards.last().cloned()
    }

    pub fn deck_type(&self) -> DeckType {
        self.deck_type.clone()
    }

    pub fn owner(&self) -> Option<PlayerID> {
        self.owner
    }

    pub fn all(&self) -> &[CardID] {
        &self.cards
    }

    pub(super) fn new(id: DeckID, deck_type: DeckType, owner: Option<PlayerID>) -> Deck<DeckType> {
        Deck {
            id,
            owner,
            deck_type,
            cards: Vec::new(),
        }
    }

    pub fn draw(&mut self) -> Option<CardID> {
        self.cards.pop()
    }

    pub fn remove_card_from_deck(&mut self, card: CardID) {
        self.cards.retain(|a| *a != card);
    }

    pub fn put_card_on_top(&mut self, card: CardID) {
        self.cards.push(card);
    }

    pub fn put_card_on_bottom(&mut self, card: CardID) {
        self.cards.insert(0, card);
    }

    pub fn shuffle<R: SliceRandom + Rng>(&mut self, rng: &mut R) {
        self.cards.shuffle(rng);
    }
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
pub struct TBG<Msg, Event, Trigger, Effect, EffectLayer, AttName, DeckType, CardType, PhaseType>
where
    AttName: Ord,
    Effect: Eq,
    EffectLayer: Ord,
    Event: Eq,
    DeckType: Eq,
    PhaseType: Default + Eq,
{
    messages: VecDeque<Msg>,
    events: VecDeque<Event>,
    triggers: VecDeque<Trigger>,
    effects: Vec<LayeredEffect<Effect, EffectLayer>>,
    phase: Phase<PhaseType>,
    decks: BTreeMap<DeckID, Deck<DeckType>>,
    cards: BTreeMap<CardID, Card<CardType, AttName>>,
    players: BTreeMap<PlayerID, Player<AttName>>,
    grids: BTreeMap<GridID, Grid<Option<CardID>>>,
    deck_ids: IDCounter<DeckID>,
    grid_ids: IDCounter<GridID>,
    card_ids: IDCounter<CardID>,
    player_ids: IDCounter<PlayerID>,
}

pub trait TurnBasedGame<Trigger, Event, Effect, EffectLayer, Msg> {
    fn handle_trigger(&mut self, event: &Event, trigger: &Trigger) -> bool;
    fn handle_effect(&mut self, effect: &LayeredEffect<Effect, EffectLayer>);
    fn handle_msg(&mut self, msg: &Msg);
}

impl<Msg, Event, Trigger, Effect, EffectLayer, AttName, DeckType, CardType, PhaseType>
    TBG<Msg, Event, Trigger, Effect, EffectLayer, AttName, DeckType, CardType, PhaseType>
where
    AttName: Ord + Default,
    Effect: Eq + Clone,
    EffectLayer: Ord + Clone,
    Event: Eq,
    DeckType: Eq + Copy + Clone + Debug,
    PhaseType: Default + Eq,
    Trigger: Clone,
    Self: TurnBasedGame<Trigger, Event, Effect, EffectLayer, Msg>,
{
    pub fn add_trigger(&mut self, trigger: Trigger) {
        self.triggers.push_back(trigger);
    }

    pub fn add_event(&mut self, event: Event) {
        self.events.push_back(event);
    }

    pub fn add_effect(&mut self, effect: LayeredEffect<Effect, EffectLayer>) {
        self.effects.push(effect);
        self.effects.sort_by(|a, b| a.layer.cmp(&b.layer));
    }

    pub fn create_player(&mut self, name: String) -> &mut Player<AttName> {
        let id = self.player_ids.increment();
        self.players.insert(id, Player::new(id, name));
        self.players.get_mut(&id).unwrap()
    }

    pub fn create_card(
        &mut self,
        card_type: CardType,
        owner: Option<PlayerID>,
    ) -> &mut Card<CardType, AttName> {
        let id = self.card_ids.increment();
        let card = Card::new(id, card_type, owner);
        self.cards.insert(id, card);
        self.cards.get_mut(&id).unwrap()
    }

    pub fn create_deck(
        &mut self,
        deck_type: DeckType,
        owner: Option<PlayerID>,
    ) -> &mut Deck<DeckType> {
        let id = self.deck_ids.increment();
        self.decks.insert(id, Deck::new(id, deck_type, owner));
        self.decks.get_mut(&id).unwrap()
    }

    pub fn create_grid(
        &mut self,
        w: usize,
        h: usize,
        init: Option<CardID>,
    ) -> &mut Grid<Option<CardID>> {
        let id = self.grid_ids.increment();
        self.grids.insert(id, Grid::new(w, h, init));
        self.grids.get_mut(&id).unwrap()
    }

    pub fn get_player_deck(
        &self,
        player: PlayerID,
        deck_type: DeckType,
    ) -> Option<&Deck<DeckType>> {
        self.decks
            .iter()
            .find(|(_, deck)| deck.deck_type() == deck_type && deck.owner() == Some(player))
            .map(|(_, deck)| deck)
    }

    pub fn move_card(&mut self, card_id: CardID, zone: Zone) {
        if let Some(card) = self.cards.get_mut(&card_id) {
            if card.zone == zone {
                return;
            }

            match card.zone {
                Zone::Deck(deck_id) => {
                    if let Some(deck) = self.decks.get_mut(&deck_id) {
                        deck.remove_card_from_deck(card.id());
                    }
                }
                Zone::Grid(grid_id, a, b) => {
                    self.grids.get_mut(&grid_id).map(|g| g.set_area(a, b, None));
                }
                Zone::Nowhere => (),
            }

            match zone {
                Zone::Deck(deck_id) => {
                    if let Some(deck) = self.decks.get_mut(&deck_id) {
                        deck.put_card_on_bottom(card.id());
                    }
                }
                Zone::Grid(grid_id, a, b) => {
                    self.grids
                        .get_mut(&grid_id)
                        .map(|g| g.set_area(a, b, Some(card_id)));
                }
                Zone::Nowhere => (),
            }
            card.zone = zone.clone();
        }
    }

    pub fn move_card_to_player_deck(
        &mut self,
        card_id: CardID,
        player_id: PlayerID,
        deck_type: DeckType,
    ) {
        if let Some(deck) = self.get_player_deck(player_id, deck_type).map(|a| a.id()) {
            self.move_card(card_id, Zone::Deck(deck));
        } else {
            panic!(
                "DeckType {:?} did not exist for player {:?}",
                deck_type, player_id
            );
        }
    }

    pub fn move_card_to_grid(&mut self, card_id: CardID, grid_id: GridID, a: Point, b: Point) {
        self.move_card(card_id, Zone::Grid(grid_id, a, b));
    }

    pub fn get_card_deck(&self, card_id: CardID) -> Option<&Deck<DeckType>> {
        self.cards.get(&card_id).and_then(|card| {
            if let Zone::Deck(deck_id) = card.zone {
                self.decks.get(&deck_id)
            } else {
                None
            }
        })
    }

    pub fn get_card_deck_mut(&mut self, card_id: CardID) -> Option<&mut Deck<DeckType>> {
        if let Some(card) = self.cards.get(&card_id) {
            if let Zone::Deck(deck_id) = card.zone {
                self.decks.get_mut(&deck_id)
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_card_owner(&self, card_id: CardID) -> Option<PlayerID> {
        self.cards.get(&card_id).map(|card| card.owner()).flatten()
    }

    pub fn get_card_controller(&self, card_id: CardID) -> Option<PlayerID> {
        self.get_card_deck(card_id)
            .map(|deck| deck.owner())
            .flatten()
    }

    pub fn get_player_deck_mut(
        &mut self,
        player: PlayerID,
        deck_type: DeckType,
    ) -> Option<&mut Deck<DeckType>> {
        self.decks
            .values_mut()
            .find(|deck| deck.deck_type() == deck_type && deck.owner() == Some(player))
    }

    pub fn set_phase(&mut self, phase_type: PhaseType, time_limit: usize, player: PlayerID) {
        self.phase = Phase::new(phase_type, time_limit, player);
    }

    pub fn step(&mut self) {
        while let Some(msg) = self.messages.pop_front() {
            self.handle_msg(&msg);
        }

        while let Some(event) = self.events.pop_front() {
            let mut deletes = Vec::new();
            let triggers = self.triggers.clone();

            triggers.iter().enumerate().for_each(|(ix, trigger)| {
                if self.handle_trigger(&event, &trigger) {
                    deletes.push(ix);
                }

                self.effects.clone().iter().for_each(|effect| {
                    self.handle_effect(&effect);
                });
            });

            self.triggers = triggers
                .iter()
                .enumerate()
                .filter_map(|(ix, a)| {
                    if deletes.contains(&ix) {
                        None
                    } else {
                        Some(a.clone())
                    }
                })
                .collect();
        }
    }
}