Skip to main content

openpql_range_parser/ast/
card.rs

1use super::{
2    CardRank, CardSuit, Display, From, RankConst, RankVar, SuitConst, SuitVar,
3};
4
5/// Card pattern within a range, combining rank and suit as concrete, variable, or any.
6#[derive(Copy, Clone, PartialEq, Eq, Debug, Display)]
7pub enum RangeCard {
8    /// Concrete rank and concrete suit.
9    #[display("{_0}{_1}")]
10    CC(RankConst, SuitConst),
11    /// Concrete rank and suit variable.
12    #[display("{_0}{_1}")]
13    CV(RankConst, SuitVar),
14    /// Concrete rank with any suit.
15    #[display("{_0}")]
16    CA(RankConst),
17    /// Rank variable and concrete suit.
18    #[display("{_0}{_1}")]
19    VC(RankVar, SuitConst),
20    /// Rank variable and suit variable.
21    #[display("{_0}{_1}")]
22    VV(RankVar, SuitVar),
23    /// Rank variable with any suit.
24    #[display("{_0}")]
25    VA(RankVar),
26    /// Any rank with concrete suit.
27    #[display("{_0}")]
28    AC(SuitConst),
29    /// Any rank with suit variable.
30    #[display("{_0}")]
31    AV(SuitVar),
32    /// Any card.
33    #[display("*")]
34    AA,
35}
36
37impl From<(CardRank, CardSuit)> for RangeCard {
38    fn from(t: (CardRank, CardSuit)) -> Self {
39        match t {
40            (CardRank::Const(r), CardSuit::Const(s)) => Self::CC(r, s),
41            (CardRank::Const(r), CardSuit::Var(s)) => Self::CV(r, s),
42            (CardRank::Var(r), CardSuit::Const(s)) => Self::VC(r, s),
43            (CardRank::Var(r), CardSuit::Var(s)) => Self::VV(r, s),
44            (CardRank::Any, CardSuit::Const(s)) => Self::AC(s),
45            (CardRank::Any, CardSuit::Var(s)) => Self::AV(s),
46        }
47    }
48}
49
50impl From<CardRank> for RangeCard {
51    fn from(r: CardRank) -> Self {
52        match r {
53            CardRank::Const(c) => Self::CA(c),
54            CardRank::Var(v) => Self::VA(v),
55            CardRank::Any => Self::AA,
56        }
57    }
58}
59
60impl From<CardSuit> for RangeCard {
61    fn from(s: CardSuit) -> Self {
62        match s {
63            CardSuit::Const(c) => Self::AC(c),
64            CardSuit::Var(v) => Self::AV(v),
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::*;
73
74    impl Arbitrary for RangeCard {
75        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
76            match *g.choose(&[0, 1, 2, 3, 4, 5, 6, 7, 8]).unwrap() {
77                0 => Self::CC(RankConst::arbitrary(g), SuitConst::arbitrary(g)),
78                1 => Self::CV(RankConst::arbitrary(g), SuitVar::arbitrary(g)),
79                2 => Self::CA(RankConst::arbitrary(g)),
80                3 => Self::VC(RankVar::arbitrary(g), SuitConst::arbitrary(g)),
81                4 => Self::VV(RankVar::arbitrary(g), SuitVar::arbitrary(g)),
82                5 => Self::VA(RankVar::arbitrary(g)),
83                6 => Self::AC(SuitConst::arbitrary(g)),
84                7 => Self::AV(SuitVar::arbitrary(g)),
85                _ => Self::AA,
86            }
87        }
88    }
89
90    #[test]
91    fn test_card_cc() {
92        assert_range_card("As", "As");
93    }
94
95    #[test]
96    fn test_card_cv() {
97        assert_range_card("Aw", "Aw");
98    }
99
100    #[test]
101    fn test_card_ca() {
102        assert_range_card("A", "A");
103    }
104
105    #[test]
106    fn test_card_vc() {
107        assert_range_card("Bs", "Bs");
108    }
109
110    #[test]
111    fn test_card_vv() {
112        assert_range_card("Bw", "Bw");
113    }
114
115    #[test]
116    fn test_card_va() {
117        assert_range_card("B", "B");
118    }
119
120    #[test]
121    fn test_card_ac() {
122        assert_range_card("s", "s");
123        assert_range_card("*s", "s");
124    }
125
126    #[test]
127    fn test_card_av() {
128        assert_range_card("w", "w");
129        assert_range_card("*w", "w");
130    }
131
132    #[test]
133    fn test_card_aa() {
134        assert_range_card("*", "*");
135    }
136
137    #[quickcheck]
138    fn test_shortdeck(card: RangeCard) {
139        let src = card.to_string();
140        if src.chars().any(|c| ['2', '3', '4', '5'].contains(&c)) {
141            assert!(parse_card_sd(&src).is_err());
142        } else {
143            assert_eq!(Ok(card), parse_card_sd(&src));
144        }
145    }
146
147    fn assert_range_card_sd_err(s: &str, expected: Error) {
148        assert_eq!(parse_card_sd(s), Err(expected.into()));
149    }
150
151    #[test]
152    fn test_shortdeck_error() {
153        assert_range_card_sd_err("2", Error::InvalidRank((0, 1)));
154        assert_range_card_sd_err("3", Error::InvalidRank((0, 1)));
155        assert_range_card_sd_err("4", Error::InvalidRank((0, 1)));
156        assert_range_card_sd_err("5", Error::InvalidRank((0, 1)));
157    }
158}