]> git.scottworley.com Git - pluta-lesnura/blob - src/lib.rs
b7dc954b6d430de16bfc2f0ccccdd3e027f41c24
[pluta-lesnura] / src / lib.rs
1 use rand::Rng;
2
3 pub const NUM_RANKS: u8 = 13;
4 pub const NUM_SUITS: u8 = 4;
5 pub const NUM_CARDS: u8 = NUM_RANKS * NUM_SUITS;
6
7 #[derive(Clone, Copy, Eq, PartialEq)]
8 pub struct Rank(u8);
9
10 #[derive(Clone, Copy, Eq, PartialEq)]
11 pub struct Suit(u8);
12
13 #[derive(Clone, Copy, Eq, PartialEq)]
14 pub struct Card(u8);
15 impl Card {
16 #[must_use]
17 pub fn rank(&self) -> Rank {
18 Rank(self.0 >> 2)
19 }
20 #[must_use]
21 pub fn suit(&self) -> Suit {
22 Suit(self.0 & 3)
23 }
24 }
25
26 #[must_use]
27 pub fn deck() -> Vec<Card> {
28 (0..NUM_CARDS).map(Card).collect()
29 }
30
31 #[derive(Clone, Copy)]
32 pub struct PathLength(Rank);
33
34 #[derive(Clone, Copy, Default)]
35 pub struct PathLengthInfo(u16);
36 impl PathLengthInfo {
37 #[must_use]
38 pub fn is_showing(&self, i: Rank) -> bool {
39 (self.0 >> i.0) & 1 == 1
40 }
41 fn reveal(&mut self, i: Rank) {
42 self.0 |= 1 << i.0;
43 }
44 pub fn reveal_random(&mut self, true_length: PathLength) -> Option<Rank> {
45 let showing = u8::try_from(self.0.count_ones()).expect("There aren't that many bits");
46 let not_showing = NUM_RANKS - showing;
47 if not_showing <= 1 {
48 return None;
49 }
50
51 let mut show = rand::thread_rng().gen_range(0..not_showing - 1);
52 for i in 0..NUM_RANKS {
53 let r = Rank(i);
54 if !self.is_showing(r) && r != true_length.0 {
55 if show == 0 {
56 self.reveal(r);
57 return Some(r);
58 }
59 show -= 1;
60 }
61 }
62 unreachable!()
63 }
64 }
65
66 #[cfg(test)]
67 mod tests {
68 use super::*;
69
70 #[test]
71 fn path_length_info_random_reveal() {
72 let length = PathLength(Rank(7));
73 let mut pli = PathLengthInfo::default();
74 for _ in 0..12 {
75 let old_pli = PathLengthInfo::clone(&pli);
76 match pli.reveal_random(length) {
77 None => panic!("Nothing revealed?"),
78 Some(r) => {
79 assert!(!old_pli.is_showing(r));
80 assert!(pli.is_showing(r));
81 }
82 }
83 assert_eq!(pli.0.count_ones(), 1 + old_pli.0.count_ones());
84 }
85 assert!(pli.reveal_random(length).is_none());
86 }
87
88 #[test]
89 fn test_deck() {
90 let _d = deck();
91 }
92 }