card-game 0.2.0

Framework for building card games
Documentation
use crate::events::{
    AddEventListener, DynEventListener, Event, EventActionID, EventActionIDBuilder, EventListener,
    EventListenerConstructor, EventValidAction,
};
use crate::identifications::{ActionIdentifier, SourceCardID, ValidCardID};
use card_stack::priority::PriorityMut;
use card_stack::{NonEmptyInput, priority::GetState};
use state_validation::{
    StateFilter, StateFilterInputCombination, StateFilterInputConversion, ValidAction,
};

mod events;
mod manager;
pub use events::*;
pub use manager::*;

#[derive(Debug, Clone)]
pub struct Card<Kind> {
    id: CardID,
    kind: Kind,
}

impl<Kind> Card<Kind> {
    pub fn new(card_id: CardID, kind: Kind) -> Self {
        Card { id: card_id, kind }
    }
    pub fn id(&self) -> CardID {
        self.id
    }
    pub fn kind(&self) -> &Kind {
        &self.kind
    }
    pub fn kind_mut(&mut self) -> &mut Kind {
        &mut self.kind
    }
    pub fn take_kind(self) -> Kind {
        self.kind
    }
    pub fn replace_kind<NewKind>(self, f: impl FnOnce(Kind) -> NewKind) -> Card<NewKind> {
        Card {
            id: self.id,
            kind: f(self.kind),
        }
    }
    pub fn into_kind<NewKind>(self) -> Card<NewKind>
    where
        Kind: Into<NewKind>,
    {
        Card {
            id: self.id,
            kind: self.kind.into(),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CardID(usize);
impl NonEmptyInput for CardID {}
impl CardID {
    pub const fn new(id: usize) -> Self {
        CardID(id)
    }
    pub fn value(&self) -> usize {
        self.0
    }
    pub(crate) fn clone_id(&self) -> Self {
        CardID::new(self.0)
    }
}
impl std::fmt::Display for CardID {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

pub struct CardBuilder<'a, EventManager> {
    card_actions: &'a mut CardActions,
    event_action_id_builder: &'a mut EventActionIDBuilder,
    event_manager: &'a mut EventManager,
    card_event_tracker: &'a mut CardEventTracker<EventManager>,
    next_id: &'a mut usize,
}

impl<'a, EventManager> CardBuilder<'a, EventManager> {
    pub(crate) fn new(
        card_actions: &'a mut CardActions,
        event_action_id_builder: &'a mut EventActionIDBuilder,
        event_manager: &'a mut EventManager,
        card_event_tracker: &'a mut CardEventTracker<EventManager>,
        next_id: &'a mut usize,
    ) -> Self {
        CardBuilder {
            card_actions,
            event_action_id_builder,
            event_manager,
            card_event_tracker,
            next_id,
        }
    }
    pub fn build<Kind>(&mut self, kind: Kind) -> CardKindBuilder<'_, EventManager, Kind> {
        let id = CardID::new(*self.next_id);
        *self.next_id += 1;
        CardKindBuilder {
            card_actions: self.card_actions,
            event_action_id_builder: self.event_action_id_builder,
            event_manager: self.event_manager,
            card_event_tracker: self.card_event_tracker,
            card: Card::new(id, kind),
        }
    }
}

pub struct CardKindBuilder<'a, EventManager, Kind> {
    card_actions: &'a mut CardActions,
    event_action_id_builder: &'a mut EventActionIDBuilder,
    event_manager: &'a mut EventManager,
    card_event_tracker: &'a mut CardEventTracker<EventManager>,
    card: Card<Kind>,
}

impl<'a, EventManager, Kind> CardKindBuilder<'a, EventManager, Kind> {
    pub fn with_action<Action: ActionIdentifier>(self) -> Self {
        self.card_actions
            .insert_action(Action::action_id(), self.card.id());
        self
    }
    pub fn copy_actions(self, card_id: CardID) -> Self {
        self.card_actions.copy_actions(self.card.id(), card_id);
        self
    }
    pub fn with_event(self) -> CardKindEffectBuilder<'a, EventManager, Kind> {
        CardKindEffectBuilder {
            event_action_id: self.event_action_id_builder.build(),
            card_actions: self.card_actions,
            event_action_id_builder: self.event_action_id_builder,
            event_manager: self.event_manager,
            card_event_tracker: self.card_event_tracker,
            card: self.card,
        }
    }
    pub fn copy_events(self, card_id: CardID) -> Self {
        self.card_event_tracker
            .copy_events(self.event_manager, self.card.id(), card_id);
        self
    }
    pub fn kind_mut(&mut self) -> &mut Kind {
        self.card.kind_mut()
    }
    pub fn finish(self) -> Card<Kind> {
        self.card
    }
}

pub struct CardKindEffectBuilder<'a, EventManager, Kind> {
    event_action_id: EventActionID,
    card_actions: &'a mut CardActions,
    event_action_id_builder: &'a mut EventActionIDBuilder,
    event_manager: &'a mut EventManager,
    card_event_tracker: &'a mut CardEventTracker<EventManager>,
    card: Card<Kind>,
}

impl<'a, EventManager, Kind> CardKindEffectBuilder<'a, EventManager, Kind> {
    pub fn listen_for<
        State: 'static,
        Ev: Event<PriorityMut<State>>,
        Listener: EventListenerConstructor<State, Ev>,
    >(
        self,
        listener_input: Listener::Input,
    ) -> Self
    where
        EventManager: AddEventListener<State, Ev>,
        <Listener::Action as EventValidAction<PriorityMut<State>, Listener::ActionInput>>::Output:
            Into<EventManager::Output>,
    {
        let card_id = self.card.id();
        let event_listener = Listener::new_listener(SourceCardID(card_id), listener_input.clone());
        let (id, index) = self
            .event_manager
            .add_listener(self.event_action_id, event_listener);
        self.card_event_tracker.track_event::<_, _, Listener>(
            card_id,
            self.event_action_id,
            id,
            index,
            listener_input,
        );
        self
    }
    pub fn finish_event(self) -> CardKindBuilder<'a, EventManager, Kind> {
        CardKindBuilder {
            card_actions: self.card_actions,
            event_action_id_builder: self.event_action_id_builder,
            event_manager: self.event_manager,
            card_event_tracker: self.card_event_tracker,
            card: self.card,
        }
    }
}

pub struct SourceCardFilter<Action>(std::marker::PhantomData<Action>);
impl<
    Input: StateFilterInputConversion<SourceCardID>,
    Action: ValidAction<State, Input> + ActionIdentifier,
    State: GetState<CardActions>,
> StateFilter<State, Input> for SourceCardFilter<Action>
where
    Input::Remainder: StateFilterInputCombination<ValidCardID<()>>,
{
    type ValidOutput = <Input::Remainder as StateFilterInputCombination<ValidCardID<()>>>::Combined;
    type Error = InvalidSourceCardError;
    fn filter(state: &State, value: Input) -> Result<Self::ValidOutput, Self::Error> {
        let (source_card_id, remainder) = value.split_take();
        if state
            .state()
            .contains_action(Action::action_id(), source_card_id.0)
        {
            Ok(remainder.combine(ValidCardID::new(source_card_id.0)))
        } else {
            Err(InvalidSourceCardError(source_card_id))
        }
    }
}
#[derive(thiserror::Error, Debug)]
#[error("invalid source card {0}")]
pub struct InvalidSourceCardError(SourceCardID);