openpql-range-parser 0.1.0

Poker Range Notation Parser
Documentation
use super::{
    Array, Card, From, Idx, Rank16, RankDiff, VarCondition, VarConditionRank,
    ast::RankConst,
};

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub enum ConstrainRank<const N: usize>
where
    [Idx; N]: Array<Item = Idx>,
{
    Match(Rank16),
    Diff(Idx, RankDiff),
    Var(VarConditionRank<N>),
    #[default]
    Nil,
}

pub const fn rank_diff(lhs: Card, rhs: Card) -> RankDiff {
    (lhs.rank as RankDiff) - (rhs.rank as RankDiff)
}

impl<const N: usize> ConstrainRank<N>
where
    [Idx; N]: Array<Item = Idx>,
{
    #[inline]
    pub fn reject(&self, cs: &[Card], perm: &[Idx], i: usize) -> bool {
        match self {
            Self::Match(r16) => {
                if !r16.contains_rank(cs[i].rank) {
                    return true;
                }
            }

            Self::Diff(original_idx, d) => {
                if let Some(j) = perm.iter().position(|k| original_idx == k)
                    && rank_diff(cs[j], cs[i]) != *d
                {
                    return true;
                }
            }

            Self::Var(VarConditionRank(VarCondition {
                equal,
                not_equal,
                banned,
                ..
            })) => {
                if banned.contains_rank(cs[i].rank) {
                    return true;
                }

                for original_idx in equal {
                    if let Some(j) = perm.iter().position(|k| original_idx == k)
                        && cs[i].rank != cs[j].rank
                    {
                        return true;
                    }
                }

                for original_idx in not_equal {
                    if let Some(j) = perm.iter().position(|k| original_idx == k)
                        && cs[i].rank == cs[j].rank
                    {
                        return true;
                    }
                }
            }

            Self::Nil => (),
        }

        false
    }
}

impl<const N: usize> From<Rank16> for ConstrainRank<N>
where
    [Idx; N]: Array<Item = Idx>,
{
    fn from(r: Rank16) -> Self {
        Self::Match(r)
    }
}

impl<const N: usize> From<RankConst> for ConstrainRank<N>
where
    [Idx; N]: Array<Item = Idx>,
{
    fn from(r: RankConst) -> Self {
        Self::Match(Rank16::from(1 << r as u8))
    }
}