riichi_elements/meld/
ankan.rs1use core::fmt::{Display, Formatter};
2
3use crate::{
4 tile::Tile,
5 tile_set::*,
6 utils::{pack4, unpack4},
7};
8
9use super::{
10 packed::{normalize_ankan, PackedMeld, PackedMeldKind},
11 utils::{ankan_tiles, count_for_kan},
12};
13
14#[derive(Copy, Clone, Debug, Eq, PartialEq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[non_exhaustive]
21pub struct Ankan {
22 pub own: [Tile; 4],
23}
24
25impl Ankan {
26 pub const fn num(self) -> u8 {
27 self.own[0].normal_num()
28 }
29 pub const fn suit(self) -> u8 {
30 self.own[0].suit()
31 }
32
33 pub fn from_tiles(mut own: [Tile; 4]) -> Option<Self> {
35 if own[0].to_normal() != own[1].to_normal()
36 || own[0].to_normal() != own[2].to_normal()
37 || own[0].to_normal() != own[3].to_normal()
38 {
39 return None;
40 }
41 own.sort();
42 Some(Ankan { own })
43 }
44
45 pub fn from_hand(hand: &TileSet37, tile: Tile) -> Option<Self> {
47 let normal = tile.to_normal();
48 let (num_normal, num_red) = count_for_kan(hand, normal);
49 if num_normal + num_red != 4 {
50 return None;
51 }
52 Self::from_tiles(ankan_tiles(normal, num_red))
53 }
54
55 pub fn consume_from_hand(self, hand: &mut TileSet37) {
57 hand[self.own[0]] = 0;
58 hand[self.own[3]] = 0;
59 }
60}
61
62impl Display for Ankan {
63 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
64 let (n0, n1, n2, n3, s) = (
65 self.own[0].num(),
66 self.own[1].num(),
67 self.own[2].num(),
68 self.own[3].num(),
69 self.own[0].suit_char(),
70 );
71 write!(f, "A{}{}{}{}{}", n0, n1, n2, n3, s)
72 }
73}
74
75impl TryFrom<PackedMeld> for Ankan {
77 type Error = ();
78
79 fn try_from(raw: PackedMeld) -> Result<Self, Self::Error> {
80 if raw.kind() != PackedMeldKind::Ankan as u8 {
81 return Err(());
82 }
83 let t = raw.get_tile().ok_or(())?;
84 let (mut own0, mut own1, mut own2, mut own3) = (t, t, t, t);
85 let (r0, r1, r2, r3) = unpack4(normalize_ankan(raw.red()));
86 if r0 { own0 = own0.to_red(); }
87 if r1 { own1 = own1.to_red(); }
88 if r2 { own2 = own2.to_red(); }
89 if r3 { own3 = own3.to_red(); }
90 Ankan::from_tiles([own0, own1, own2, own3]).ok_or(())
91 }
92}
93
94impl From<Ankan> for PackedMeld {
95 fn from(ankan: Ankan) -> Self {
96 let [own0, own1, own2, own3] = ankan.own;
97 PackedMeld::new()
98 .with_tile(own0.normal_encoding())
99 .with_dir(0)
100 .with_red(pack4(own0.is_red(), own1.is_red(), own2.is_red(), own3.is_red()))
101 .with_kind(PackedMeldKind::Ankan as u8)
102 }
103}