riichi_elements/tile_set/
tile_set_34.rs1use core::fmt::{Display, Formatter};
2use core::ops::{Index, IndexMut};
3
4use super::TileSet37;
5
6use derive_more::{
7 Constructor, From, Into, IntoIterator, Index, IndexMut,
8};
9
10use crate::tile::Tile;
11
12#[derive(Clone, Debug, Eq, PartialEq, Constructor, From, Into, IntoIterator, Index, IndexMut)]
15pub struct TileSet34(pub [u8; 34]);
16
17impl Index<Tile> for TileSet34 {
18 type Output = u8;
19 fn index(&self, tile: Tile) -> &Self::Output {
20 &self.0[tile.normal_encoding() as usize] }
22}
23
24impl IndexMut<Tile> for TileSet34 {
25 fn index_mut(&mut self, tile: Tile) -> &mut Self::Output {
26 &mut self.0[tile.normal_encoding() as usize] }
28}
29
30impl Default for TileSet34 {
31 fn default() -> Self { TileSet34([0u8; 34]) }
32}
33
34impl Display for TileSet34 {
35 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
36 for xs in self.0.chunks(9) {
37 for x in xs {
38 write!(f, "{}", x)?;
39 }
40 write!(f, ",")?;
41 }
42 Ok(())
43 }
44}
45
46impl From<&TileSet37> for TileSet34 {
48 fn from(original: &TileSet37) -> Self {
49 let mut result: [u8; 34] = (original[..34]).try_into().unwrap();
50 result[4] += original[34];
51 result[13] += original[35];
52 result[22] += original[36];
53 Self(result)
54 }
55}
56
57impl FromIterator<Tile> for TileSet34 {
58 fn from_iter<T: IntoIterator<Item=Tile>>(tiles: T) -> Self {
59 let mut ts = Self::default();
60 for tile in tiles {
61 ts[tile.to_normal()] += 1;
62 }
63 ts
64 }
65}
66
67impl TileSet34 {
68 pub const fn empty_set() -> Self { TileSet34([0; 34]) }
70
71 pub const fn complete_set() -> Self { TileSet34([4; 34]) }
74
75 pub fn from_packed(packed: [u32; 4]) -> Self {
77 let mut ts34 = Self::default();
78 let mut i = 0;
79 for s in 0..3 {
80 let mut m = packed[s];
81 for _ in 0..9 {
82 ts34[i] = (m & 0o7) as u8;
83 i += 1;
84 m >>= 3;
85 }
86 }
87 let mut m = packed[3];
88 for _ in 0..7 {
89 ts34[i] = (m & 0o7) as u8;
90 i += 1;
91 m >>= 3;
92 }
93 ts34
94 }
95
96 pub fn packed_34(&self) -> [u32; 4] {
101 let mut packed = [0u32; 4];
102 let h = &self.0;
103 for i in (0..34).rev() {
104 let s = i / 9;
105 packed[s] = (packed[s] << 3) | (h[i] as u32);
106 }
107 packed
108 }
109
110 pub fn iter_tiles(&self) -> impl Iterator<Item=Tile> {
112 self.0.into_iter().enumerate().flat_map(|(encoding, count)|
113 itertools::repeat_n(
114 Tile::from_encoding(encoding as u8).unwrap(),
115 count as usize))
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::tile::*;
123
124 #[test]
125 fn ts34_treats_red_as_normal() {
126 let mut h = TileSet34::default();
127 h[t!("5m")] = 1;
128 h[t!("0p")] = 2;
129 h[t!("6s")] = 3;
130 assert_eq!(h, [
131 0, 0, 0, 0, 1, 0, 0, 0, 0,
132 0, 0, 0, 0, 2, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 3, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0,
135 ].into());
136 }
137
138 #[test]
139 fn ts34_packs_correctly() {
140 let h = TileSet34::from_iter(tiles_from_str("147m258p369s77z"));
141 assert_eq!(h.packed_34(), [
142 0o001001001,
143 0o010010010,
144 0o100100100,
145 0o2000000,
146 ]);
147 assert_eq!(TileSet34::from_packed(h.packed_34()), h);
148 }
149}