manabrew-engine 0.6.0

Magic: The Gathering rules engine — a Rust port of Forge
Documentation
use crate::game::GameState;
use crate::ids::{CardId, PlayerId};
use crate::player::player_predicates;
use forge_foundation::ZoneType;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PlayerCollection(pub Vec<PlayerId>);

impl IntoIterator for PlayerCollection {
    type Item = PlayerId;
    type IntoIter = std::vec::IntoIter<PlayerId>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<'a> IntoIterator for &'a PlayerCollection {
    type Item = &'a PlayerId;
    type IntoIter = std::slice::Iter<'a, PlayerId>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl PlayerCollection {
    pub fn new(players: Vec<PlayerId>) -> Self {
        Self(players)
    }

    pub fn alive(game: &GameState) -> Self {
        Self(game.alive_players())
    }

    pub fn opponents_of(game: &GameState, player: PlayerId) -> Self {
        Self(
            game.player_order
                .iter()
                .copied()
                .filter(|&pid| player_predicates::is_opponent_of(game, player, pid))
                .collect(),
        )
    }

    pub fn teammates_of(game: &GameState, player: PlayerId) -> Self {
        Self(
            game.player_order
                .iter()
                .copied()
                .filter(|&pid| player_predicates::same_team(game, player, pid))
                .collect(),
        )
    }

    pub fn contains(&self, player: PlayerId) -> bool {
        self.0.contains(&player)
    }

    pub fn cards_in(&self, game: &GameState, zone: ZoneType) -> Vec<CardId> {
        self.0
            .iter()
            .flat_map(|&pid| game.cards_in_zone(zone, pid).iter().copied())
            .collect()
    }

    pub fn cards_in_zones(
        &self,
        game: &GameState,
        zones: impl IntoIterator<Item = ZoneType>,
    ) -> Vec<CardId> {
        zones
            .into_iter()
            .flat_map(|zone| self.cards_in(game, zone))
            .collect()
    }

    pub fn creatures_in_play(&self, game: &GameState) -> Vec<CardId> {
        self.cards_in(game, ZoneType::Battlefield)
            .into_iter()
            .filter(|&cid| game.card(cid).is_creature())
            .collect()
    }

    pub fn filter<F>(&self, predicate: F) -> Self
    where
        F: Fn(PlayerId) -> bool,
    {
        Self(
            self.0
                .iter()
                .copied()
                .filter(|&pid| predicate(pid))
                .collect(),
        )
    }

    pub fn min<F>(&self, score: F) -> Option<PlayerId>
    where
        F: Fn(PlayerId) -> i32,
    {
        self.0.iter().copied().min_by_key(|&pid| score(pid))
    }

    pub fn max<F>(&self, score: F) -> Option<PlayerId>
    where
        F: Fn(PlayerId) -> i32,
    {
        self.0.iter().copied().max_by_key(|&pid| score(pid))
    }

    pub fn sum<F>(&self, score: F) -> i32
    where
        F: Fn(PlayerId) -> i32,
    {
        self.0.iter().copied().map(score).sum()
    }
}