riichi_elements/meld/
packed.rs1use bitfield_struct::bitfield;
2
3use crate::tile::Tile;
4use super::{Meld, Chii, Pon, Kakan, Daiminkan, Ankan};
5
6#[bitfield(u16)]
46pub(crate) struct PackedMeld {
47 #[bits(6)]
48 pub tile: u8,
49
50 #[bits(2)]
51 pub dir: u8,
52
53 #[bits(4)]
54 pub red: u8,
55
56 #[bits(3)]
57 pub kind: u8,
58
59 #[bits(1)]
60 pub _reserved0: u8,
61}
62
63impl PackedMeld {
64 pub fn get_tile(self) -> Option<Tile> {
65 Tile::from_encoding(self.tile()).map(|t| t.to_normal())
66 }
67}
68
69#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, strum::FromRepr)]
72#[repr(u8)]
73pub(crate) enum PackedMeldKind {
74 #[default]
75 Chii = 1,
76 Pon = 2,
77 Kakan = 3,
78 Daiminkan = 4,
79 Ankan = 5,
80}
81
82impl TryFrom<PackedMeld> for Meld {
83 type Error = ();
84
85 fn try_from(raw: PackedMeld) -> Result<Self, Self::Error> {
86 match PackedMeldKind::from_repr(raw.kind()).ok_or(())? {
87 PackedMeldKind::Chii =>
88 Chii::try_from(raw).map(Meld::Chii),
89 PackedMeldKind::Pon =>
90 Pon::try_from(raw).map(Meld::Pon),
91 PackedMeldKind::Kakan =>
92 Kakan::try_from(raw).map(Meld::Kakan),
93 PackedMeldKind::Daiminkan =>
94 Daiminkan::try_from(raw).map(Meld::Daiminkan),
95 PackedMeldKind::Ankan =>
96 Ankan::try_from(raw).map(Meld::Ankan),
97 }
98 }
99}
100
101impl From<Meld> for PackedMeld {
102 fn from(meld: Meld) -> Self {
103 match meld {
104 Meld::Chii(chii) => PackedMeld::from(chii),
105 Meld::Pon(pon) => PackedMeld::from(pon),
106 Meld::Kakan(kakan) => PackedMeld::from(kakan),
107 Meld::Daiminkan(daiminkan) => PackedMeld::from(daiminkan),
108 Meld::Ankan(ankan) => PackedMeld::from(ankan),
109 }
110 }
111}
112
113impl Meld {
114 pub fn from_packed(packed: u16) -> Option<Self> {
116 Meld::try_from(PackedMeld::try_from(packed).ok()?).ok()
117 }
118 pub fn packed(self) -> u16 {
120 u16::from(PackedMeld::from(self))
121 }
122}
123
124const fn normalize_bits(x: u8, n: u8) -> u8 {
128 let lsbs = x & ((1 << n) - 1);
129 let msbs = x & !((1 << n) - 1);
130 let new_lsbs = (1u8 << lsbs.count_ones()) - 1u8;
131 msbs | new_lsbs
132}
133
134const fn normalize_mask(n: u8) -> u64 {
135 let mut mask = 0u64;
136 let mut x = 0u8;
137 while x < 16u8 {
138 mask |= (normalize_bits(x, n) as u64) << (x * 4);
139 x += 1;
140 }
141 mask
142}
143
144const MASK_PON_KAKAN: u64 = normalize_mask(2);
145const MASK_DAIMINKAN: u64 = normalize_mask(3);
146const MASK_ANKAN: u64 = normalize_mask(4);
147
148pub const fn normalize_pon(x: u8) -> u8 { ((MASK_PON_KAKAN >> (x * 4)) & 0b0111) as u8 }
149pub const fn normalize_kakan(x: u8) -> u8 { ((MASK_PON_KAKAN >> (x * 4)) & 0b1111) as u8 }
150pub const fn normalize_daiminkan(x: u8) -> u8 { ((MASK_DAIMINKAN >> (x * 4)) & 0b1111) as u8 }
151pub const fn normalize_ankan(x: u8) -> u8 { ((MASK_ANKAN >> (x * 4)) & 0b1111) as u8 }
152