riichi_elements/tile_set/
tile_mask_34.rs

1use core::fmt::{Display, Formatter};
2
3use derive_more::{
4    Constructor, From, Into,
5    BitAnd, BitOr, BitXor,
6    BitAndAssign, BitOrAssign, BitXorAssign,
7};
8
9use crate::tile::Tile;
10use super::{TileSet37, TileSet34};
11
12/// 1-bit-per-tile version of [`TileSet34`], i.e. non-multi set, set of tile kinds.
13#[derive(
14    Copy, Clone, Debug, Default, Eq, PartialEq,
15    Constructor, From, Into,
16    BitAnd, BitOr, BitXor,
17    BitAndAssign, BitOrAssign, BitXorAssign,
18)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "serde", serde(transparent))]  // TODO(summivox): don't cheat
21pub struct TileMask34(pub u64);
22
23impl TileMask34 {
24    /// An empty tile set.
25    pub const fn empty_set() -> Self { Self(0) }
26
27    /// The complete set of tiles (all 34 kinds).
28    pub const fn complete_set() -> Self { Self((1 << 34) - 1) }
29
30    /// Returns if this is an empty set.
31    pub fn is_empty(self) -> bool { self.0 == 0 }
32
33    /// Returns if there is at least one kind of tile in the set.
34    pub fn any(self) -> bool { self.0 > 0 }
35
36    /// Tests if this set contains the given tile.
37    pub fn has(self, tile: Tile) -> bool {
38        (self.0 >> (tile.normal_encoding() as u64)) & 1 == 1
39    }
40
41    /// Tests if this set contains the given tile encoding.
42    pub fn has_i(self, i: u8) -> bool {
43        (self.0 >> (i as u64)) & 1 == 1
44    }
45
46    /// Mutates the set to include the given tile.
47    pub fn set(&mut self, tile: Tile) {
48        self.0 |= 1 << (tile.normal_encoding() as u64);
49    }
50
51    /// Mutates the set to exclude the given tile.
52    pub fn clear(&mut self, tile: Tile) {
53        self.0 &= !(1 << (tile.normal_encoding() as u64));
54    }
55}
56
57impl FromIterator<Tile> for TileMask34 {
58    fn from_iter<T: IntoIterator<Item=Tile>>(tiles: T) -> Self {
59        let mut mask = 0u64;
60        for tile in tiles {
61            mask |= 1u64 << tile.normal_encoding() as u64;
62        }
63        Self(mask)
64    }
65}
66
67impl From<TileSet37> for TileMask34 {
68    fn from(ts37: TileSet37) -> Self {
69        let mut mask = 0u64;
70        for i in 0..34 {
71            if ts37[i] > 0 {
72                mask |= 1 << i;
73            }
74        }
75        if ts37[34] > 0 { mask |= 1 << 4; }
76        if ts37[35] > 0 { mask |= 1 << 13; }
77        if ts37[36] > 0 { mask |= 1 << 22; }
78        Self(mask)
79    }
80}
81
82impl From<TileSet34> for TileMask34 {
83    fn from(ts34: TileSet34) -> Self {
84        let mut mask = 0u64;
85        for i in 0..34 {
86            if ts34[i] > 0 {
87                mask |= 1 << i;
88            }
89        }
90        Self(mask)
91    }
92}
93
94impl Display for TileMask34 {
95    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
96        for r in [0..9, 9..18, 18..27, 27..34] {
97            for i in r {
98                write!(f, "{}", (self.0 >> i) & 1)?;
99            }
100            write!(f, ",")?;
101        }
102        Ok(())
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::tile::*;
110
111    #[test]
112    fn mask34_examples() {
113        let tiles1 = tiles_from_str("147m208p369s77z");
114        let mask1 = TileMask34::from_iter(tiles1);
115        assert_eq!(u64::from(mask1), 0b1000000100100100010010010001001001u64);
116
117        let tiles2 = tiles_from_str("1112345678999m");
118        let mask2 = TileMask34::from_iter(tiles2);
119        assert_eq!(u64::from(mask2), 0b111111111u64);
120
121        let mask_and = mask1 & mask2;
122        assert_eq!(u64::from(mask_and), 0b001001001u64);
123    }
124}