1use 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
17pub const MAX_NUMBER_FIGURE: u8 = 10;
19pub 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 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 pub fn order_number(&self) -> usize {
45 usize::from(self.power - 2 )
46 }
47
48
49 pub fn mask(&self) -> u64{
65 1u64<<self.power
66 }
67
68 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 fn usize_index(&self) -> usize {
112 (self.power - 2) as usize
113 }
114
115 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 Numbered(NumberFigure)
149}
150impl Figure {
151
152
153 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 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 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 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}
296pub 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 }
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
388pub const F2: Figure = Numbered(NumberFigure {power: 2});
390pub const F3: Figure = Numbered(NumberFigure {power: 3});
392pub const F4: Figure = Numbered(NumberFigure {power: 4});
394pub const F5: Figure = Numbered(NumberFigure {power: 5});
396pub const F6: Figure = Numbered(NumberFigure {power: 6});
398pub const F7: Figure = Numbered(NumberFigure {power: 7});
400pub const F8: Figure = Numbered(NumberFigure {power: 8});
402pub const F9: Figure = Numbered(NumberFigure {power: 9});
404pub 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;