Skip to main content

karty/figures/
standard.rs

1//! Module containing implementation of standard figures.
2//! # Licence:
3//! MIT: [https://mit-license.org/](https://mit-license.org/)
4//! # Authors:
5//! [morovintaas](mailto:moroviintaas@gmail.com)
6//!
7use std::cmp::Ordering;
8use std::fmt::{Debug, Formatter};
9use comparator::Comparator;
10#[cfg(feature = "random")]
11use karty_proc_macro::RandomSymbol;
12#[cfg(feature = "random")]
13use rand::prelude::Distribution;
14#[cfg(feature = "random")]
15use rand::Rng;
16
17///Maximal symbol on standard deck figure `=10`
18pub const MAX_NUMBER_FIGURE: u8 = 10;
19///Minimal symbol on standard deck figure `=2`
20pub const MIN_NUMBER_FIGURE: u8 = 2;
21
22#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
23#[cfg_attr(feature = "random", derive(RandomSymbol))]
24#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct NumberFigure {
27    power: u8
28}
29impl NumberFigure {
30    /// Constructor of [`NumberedFigure`](crate::figures::NumberFigure).
31    /// # Panics:
32    /// When power is lesser than [`MIN_NUMBER_FIGURE`](crate::figures::MIN_NUMBER_FIGURE) or greater than [`MAX_NUMBER_FIGURE`](crate::figures::MAX_NUMBER_FIGURE).
33    ///
34    pub fn new(power: u8) -> Self{
35        match power{
36            legit @MIN_NUMBER_FIGURE..=MAX_NUMBER_FIGURE => Self{power: legit},
37            e => panic!("Invalid power value {e:?}")
38        }
39    }
40
41    /// Returns order number (could be interpreted as [`CardSymbol`](crate::symbol::CardSymbol) if figure is stand alone symbol).
42    /// # Warn!
43    /// Might be deleted in the future.
44    pub fn order_number(&self) -> usize {
45        usize::from(self.power - 2 )
46    }
47
48
49    /// Returns a mask of a figure as in example. It can be used for optimised storing in true/false arrays.
50    /// # Example:
51    /// ```
52    /// use karty::figures::{*};
53    /// assert_eq!(F2.mask(), 0x04);
54    /// assert_eq!(F3.mask(), 0x08);
55    /// assert_eq!(F4.mask(), 0x10);
56    /// assert_eq!(F5.mask(), 0x20);
57    /// assert_eq!(F6.mask(), 0x40);
58    /// assert_eq!(F7.mask(), 0x80);
59    /// assert_eq!(F8.mask(), 0x100);
60    /// assert_eq!(F9.mask(), 0x200);
61    /// assert_eq!(F10.mask(), 0x400);
62    ///
63    /// ```
64    pub fn mask(&self) -> u64{
65        1u64<<self.power
66    }
67
68    /// ```
69    /// use karty::figures::NumberFigure;
70    /// assert_eq!(NumberFigure::new(2).repr_char(), '2');
71    /// assert_eq!(NumberFigure::new(9).repr_char(), '9');
72    /// assert_eq!(NumberFigure::new(10).repr_char(), 'T');
73    /// ```
74    pub fn repr_char(&self) -> char{
75        match self.power{
76            10 => 'T',
77            legit @ 2..=9 => (0x30 + legit) as char,
78            bad => panic!("Bad number in NumberedFigure:{bad:} (should not happen, it is a bug).")
79        }
80    }
81
82}
83
84impl std::fmt::Display for NumberFigure {
85    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86        write!(f, "{:?}", self.power)
87    }
88}
89
90impl Ord for NumberFigure {
91    fn cmp(&self, other: &Self) -> Ordering {
92        self.power.cmp(&other.power)
93    }
94}
95
96impl PartialOrd<Self> for NumberFigure {
97    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98        Some(self.cmp(other))
99    }
100}
101
102impl CardSymbol for NumberFigure {
103    const SYMBOL_SPACE: usize = 9;
104
105    /// ```
106    /// use karty::figures::{NumberFigure};
107    /// use karty::symbol::CardSymbol;
108    /// assert_eq!(NumberFigure::new(2).usize_index(), 0);
109    /// assert_eq!(NumberFigure::new(10).usize_index(), 8);
110    /// ```
111    fn usize_index(&self) -> usize {
112        (self.power - 2) as usize
113    }
114
115    ///
116    /// ```
117    /// use karty::figures::{NumberFigure};
118    /// use karty::symbol::CardSymbol;
119    /// assert_eq!(NumberFigure::from_usize_index(6).unwrap(), NumberFigure::new(8));
120    /// assert_eq!(NumberFigure::from_usize_index(3).unwrap(), NumberFigure::new(5));
121    /// ```
122    fn from_usize_index(position: usize) -> Result<Self, CardError> {
123        match position{
124            p@ 0..=8 => Ok(Self{power: (p + 2) as u8 }),
125            s => Err(CardError::WrongFigurePosition(s))
126        }
127    }
128}
129
130impl FigureTrait for NumberFigure {
131    const NUMBER_OF_FIGURES: usize = Self::SYMBOL_SPACE;
132
133}
134
135
136
137
138#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
139#[cfg_attr(feature = "random", derive(RandomSymbol))]
140#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub enum Figure {
143    Ace,
144    King,
145    Queen,
146    Jack,
147    ///Figure with number symbol (2-10)
148    Numbered(NumberFigure)
149}
150impl Figure {
151
152
153    /// Returns a mask for figure for efficient storing bool tables
154    /// ```
155    /// use karty::figures::{F2, F10};
156    /// use karty::figures::Figure;
157    /// assert_eq!(Figure::Ace.mask(),      0b0100000000000000);
158    /// assert_eq!(Figure::King.mask(),     0b0010000000000000);
159    /// assert_eq!(Figure::Queen.mask(),    0b0001000000000000);
160    /// assert_eq!(Figure::Jack.mask(),     0b0000100000000000);
161    /// assert_eq!(F10.mask(),              0b0000010000000000);
162    /// assert_eq!(F2.mask(),               0b0000000000000100);
163    /// ```
164    pub fn mask(&self) -> u64{
165        match self{
166            Figure::Ace => 0x4000,
167            Figure::King => 0x2000,
168            Figure::Queen => 0x1000,
169            Figure::Jack => 0x800,
170            Numbered(n) => n.mask()
171
172        }
173    }
174
175    fn power(&self) -> u8{
176        match self{
177            Ace => 14,
178            King=> 13,
179            Queen=> 12,
180            Jack=> 11,
181            Numbered(fig) => fig.power
182        }
183    }
184    fn from_power(power: u8) -> Option<Self>{
185        match power{
186            14 => Some(Self::Ace),
187            13 => Some(Self::King),
188            12 => Some(Self::Queen),
189            11 => Some(Self::Jack),
190            n @ 2..=10 => Some(Self::Numbered(NumberFigure {power: n})),
191            _ => None
192        }
193    }
194    ///
195    /// ```
196    /// use karty::figures::Figure;
197    /// use karty::figures::{F2, King};
198    /// assert_eq!(Figure::from_mask(0b0100).unwrap(), F2);
199    /// assert_eq!(Figure::from_mask(0x2000).unwrap(), King);
200    ///
201    /// ```
202    pub fn from_mask(mask: u64) -> Option<Self>{
203        if mask.count_ones() != 1{
204            None
205        }
206        else{
207            let power = mask.trailing_zeros() as u8;
208            Self::from_power(power)
209        }
210        
211    }
212
213    pub fn repr_char(&self) -> char{
214        match self{
215            Ace => 'A',
216            King => 'K',
217            Queen => 'Q',
218            Jack => 'J',
219            Numbered(n) => n.repr_char()
220        }
221
222    }
223
224
225
226
227
228}
229
230impl CardSymbol for Figure {
231    const SYMBOL_SPACE: usize = 13;
232
233    /// ```
234    /// use karty::figures::{F10, F2, Queen};
235    /// use karty::symbol::CardSymbol;
236    /// assert_eq!(F2.usize_index(), 0);
237    /// assert_eq!(F10.usize_index(), 8);
238    /// assert_eq!(Queen.usize_index(), 10);
239    /// ```
240    fn usize_index(&self) -> usize {
241        match self{
242            Ace => 12,
243            King => 11,
244            Queen => 10,
245            Jack => 9,
246            Numbered(fig) => fig.order_number()
247        }
248    }
249    /// ```
250    /// use karty::figures::{F5, F8, Figure, King};
251    /// use karty::symbol::CardSymbol;
252    /// assert_eq!(Figure::from_usize_index(6).unwrap(), F8);
253    /// assert_eq!(Figure::from_usize_index(3).unwrap(), F5);
254    /// assert_eq!(Figure::from_usize_index(11).unwrap(), King);
255    /// ```
256    fn from_usize_index(position: usize) -> Result<Self, CardError> {
257        match position{
258            p@ 0..=8 => Ok(Numbered(NumberFigure::from_usize_index(p)?)),
259            9 => Ok(Jack),
260            10 => Ok(Queen),
261            11 => Ok(King),
262            12 => Ok(Ace),
263            s => Err(CardError::WrongFigurePosition(s))
264        }
265    }
266}
267
268impl FigureTrait for Figure {
269    const NUMBER_OF_FIGURES: usize = Self::SYMBOL_SPACE;
270
271}
272
273impl std::fmt::Display for Figure {
274    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
275        if f.alternate(){
276            match self{
277                Ace => write!(f, "𝑨"),
278                King => write!(f, "𝑲"),
279                Queen => write!(f, "𝑸"),
280                Jack => write!(f, "𝑱"),
281                Numbered(n) => write!(f, "{n}")
282            }
283        }
284        else{
285            match self{
286                Ace => write!(f, "Ace"),
287                King => write!(f, "King"),
288                Queen => write!(f, "Queen"),
289                Jack => write!(f, "Jack"),
290                Numbered(n) => write!(f, "{n}")
291            }
292
293        }
294    }
295}
296/// Array of standard figures in ascending order
297pub const FIGURES: [Figure;13] = [Numbered(NumberFigure {power: 2}), Numbered(NumberFigure {power: 3}),
298    Numbered(NumberFigure {power: 4}),Numbered(NumberFigure {power: 5}),
299    Numbered(NumberFigure {power: 6}), Numbered(NumberFigure {power: 7}),
300    Numbered(NumberFigure {power: 8}), Numbered(NumberFigure {power: 9}),
301    Numbered(NumberFigure {power: 10}), Jack,  Queen, King, Ace        ];
302
303impl PartialOrd for Figure {
304    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
305        Some(self.power().cmp(&other.power()))
306        //Some()
307    }
308}
309
310impl Ord for Figure {
311    fn cmp(&self, other: &Self) -> Ordering {
312        self.power().cmp(&other.power())
313    }
314}
315
316#[derive(Default, Clone, Copy, Debug)]
317pub struct FigureComparator {
318}
319impl Comparator<Figure> for FigureComparator {
320    fn compare(&self, l: &Figure, r: &Figure) -> Ordering {
321        l.power().cmp(&r.power())
322    }
323}
324
325#[cfg(test)]
326mod tests{
327    use crate::figures::{F10, F2};
328    use crate::figures::standard::{Figure, NumberFigure};
329
330    #[test]
331    fn test_ordering(){
332        let king = Figure::King;
333        let ten = Figure::Numbered(NumberFigure::new(10));
334        let four = Figure::Numbered(NumberFigure::new(4));
335        let ace = Figure::Ace;
336        let king2 = Figure::King;
337
338        assert!(king > ten);
339        assert!(four < ten);
340        assert!(king < ace);
341
342        assert_eq!(king, king2);
343    }
344
345    #[test]
346    fn masks(){
347
348        assert_eq!(Figure::Ace.mask(), 0b0100000000000000);
349        assert_eq!(Figure::King.mask(), 0b0010000000000000);
350        assert_eq!(Figure::Queen.mask(), 0b0001000000000000);
351        assert_eq!(Figure::Jack.mask(), 0b0000100000000000);
352        assert_eq!(F10.mask(),      0b0000010000000000);
353        assert_eq!(F2.mask(),       0b0000000000000100);
354    }
355
356    #[test]
357    fn formatting(){
358        assert_eq!(format!("{:#}", Figure::Ace), String::from("𝑨"))
359    }
360
361    #[test]
362    #[cfg(feature = "speedy")]
363    fn test_speedy(){
364        use speedy::{Readable, Writable};
365        let serialized_king = Figure::King.write_to_vec().unwrap();
366        let serialized_10 = F10.write_to_vec().unwrap();
367        let deserialized_king = Figure::read_from_buffer(&serialized_king).unwrap();
368        let deserialized_10 = Figure::read_from_buffer(&serialized_10).unwrap();
369
370        assert_eq!(deserialized_king, Figure::King);
371        assert_eq!(deserialized_10, F10);
372    }
373
374    #[test]
375    #[cfg(feature = "serde_ron")]
376    fn test_serde_ron(){
377        use ron::ser::to_string_pretty;
378        let f: NumberFigure = ron::from_str("NumberFigure(power: 7)").unwrap();
379        assert_eq!(f, NumberFigure::new(7));
380
381        let mut pc = ron::ser::PrettyConfig::new();
382        pc.struct_names = true;
383        let king = to_string_pretty(&Figure::King, pc).unwrap();
384        assert_eq!(king, "King");
385    }
386}
387
388/// Alias for Figure with symbol 2
389pub const F2: Figure = Numbered(NumberFigure {power: 2});
390/// Alias for Figure with symbol 3
391pub const F3: Figure = Numbered(NumberFigure {power: 3});
392/// Alias for Figure with symbol 4
393pub const F4: Figure = Numbered(NumberFigure {power: 4});
394/// Alias for Figure with symbol 5
395pub const F5: Figure = Numbered(NumberFigure {power: 5});
396/// Alias for Figure with symbol 6
397pub const F6: Figure = Numbered(NumberFigure {power: 6});
398/// Alias for Figure with symbol 7
399pub const F7: Figure = Numbered(NumberFigure {power: 7});
400/// Alias for Figure with symbol 8
401pub const F8: Figure = Numbered(NumberFigure {power: 8});
402/// Alias for Figure with symbol 9
403pub const F9: Figure = Numbered(NumberFigure {power: 9});
404/// Alias for Figure with symbol 10
405pub const F10: Figure = Numbered(NumberFigure {power: 10});
406
407pub use Figure::{Ace, King, Queen, Jack};
408use crate::symbol::CardSymbol;
409use crate::error::CardError;
410use crate::figures::Figure::Numbered;
411use crate::figures::FigureTrait;