riichi_elements/tile_set/
tile_set_37.rs1use core::fmt::{Display, Formatter};
2use core::ops::{Index, IndexMut};
3
4use derive_more::{
5 Constructor, From, Into, IntoIterator, Index, IndexMut,
6};
7
8use crate::tile::Tile;
9
10#[derive(Clone, Debug, Eq, PartialEq, Constructor, From, Into, IntoIterator, Index, IndexMut)]
13pub struct TileSet37(pub [u8; 37]);
14
15impl Index<Tile> for TileSet37 {
16 type Output = u8;
17 fn index(&self, tile: Tile) -> &Self::Output {
18 &self.0[tile.encoding() as usize]
19 }
20}
21
22impl IndexMut<Tile> for TileSet37 {
23 fn index_mut(&mut self, tile: Tile) -> &mut Self::Output {
24 &mut self.0[tile.encoding() as usize]
25 }
26}
27
28impl Default for TileSet37 {
29 fn default() -> Self { TileSet37([0; 37]) }
30}
31
32impl Display for TileSet37 {
33 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
34 for xs in [
35 &self.0[0..9],
36 &self.0[9..18],
37 &self.0[18..27],
38 &self.0[27..34],
39 &self.0[34..37],
40 ] {
41 for x in xs {
42 write!(f, "{}", x)?;
43 }
44 write!(f, ",")?;
45 }
46 Ok(())
47 }
48}
49
50impl FromIterator<Tile> for TileSet37 {
51 fn from_iter<T: IntoIterator<Item=Tile>>(tiles: T) -> Self {
52 let mut ts = Self::default();
53 for tile in tiles {
54 ts[tile] += 1;
55 }
56 ts
57 }
58}
59
60impl TileSet37 {
61 pub const fn empty_set() -> Self { TileSet37([0; 37]) }
63
64 pub const fn complete_set(num_reds: [u8; 3]) -> Self {
68 let mut a = [4; 37];
69 a[34] = num_reds[0];
70 a[35] = num_reds[1];
71 a[36] = num_reds[2];
72 a[4] = 4 - num_reds[0];
73 a[13] = 4 - num_reds[1];
74 a[22] = 4 - num_reds[2];
75 TileSet37(a)
76 }
77
78 pub fn packed_34(&self) -> [u32; 4] {
80 let mut packed = [0u32; 4];
81 let h = &self.0;
82 for i in (0..34).rev() {
83 let s = i / 9;
84 packed[s] = (packed[s] << 3) | (h[i] as u32);
85 }
86 packed[0] += (h[34] as u32) << (3 * 4);
87 packed[1] += (h[35] as u32) << (3 * 4);
88 packed[2] += (h[36] as u32) << (3 * 4);
89 packed
90 }
91
92 pub fn iter_tiles(&self) -> impl Iterator<Item=Tile> {
94 self.0.into_iter().enumerate().flat_map(|(encoding, count)|
95 itertools::repeat_n(
96 Tile::from_encoding(encoding as u8).unwrap(),
97 count as usize))
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::tile::*;
105
106 #[test]
107 fn tile_set_is_indexable_with_tile() {
108 let mut h = TileSet37::from_iter(tiles_from_str("1112345678999m"));
109 h[t!("9m")] -= 2;
110 h[t!("7z")] += 2;
111 assert_eq!(h, [
112 3, 1, 1, 1, 1, 1, 1, 1, 1,
113 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 2,
116 0, 0, 0u8,
117 ].into());
118 }
119}