riichi_elements/meld/
chii.rs1use core::fmt::{Display, Formatter};
2
3use crate::{
4 tile::Tile,
5 tile_set::*,
6 utils::{sort2, sort3},
7};
8
9use super::packed::{PackedMeld, PackedMeldKind};
10
11#[derive(Copy, Clone, Debug, Eq, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[non_exhaustive]
16pub struct Chii {
17 pub own: [Tile; 2],
19
20 pub called: Tile,
22
23 pub min: Tile,
25}
26
27impl Chii {
28 pub const fn dir(self) -> u8 { self.called.normal_num() - self.min.num() }
29 pub const fn suit(self) -> u8 { self.called.suit() }
30
31 pub fn from_tiles(own0: Tile, own1: Tile, called: Tile) -> Option<Self> {
33 let suit = called.suit();
34 if own0.suit() != suit || own1.suit() != suit { return None; }
35 let (own0, own1) = sort2(own0, own1);
36 let (a, b, c) = sort3(
37 own0.to_normal(),
38 own1.to_normal(),
39 called.to_normal());
40 if !(b == a.succ().unwrap() && c == b.succ().unwrap()) { return None; }
41 Some(Chii { own: [own0, own1], called, min: a })
42 }
43
44 pub fn is_in_hand(self, hand: &TileSet37) -> bool {
46 hand[self.own[0]] >= 1 && hand[self.own[1]] >= 1
47 }
48
49 pub fn consume_from_hand(self, hand: &mut TileSet37) {
51 hand[self.own[0]] -= 1;
52 hand[self.own[1]] -= 1;
53 }
54}
55
56impl Display for Chii {
57 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
58 write!(f, "C{}{}{}{}",
59 self.called.num(),
60 self.own[0].num(),
61 self.own[1].num(),
62 self.called.suit_char())
63 }
64}
65
66impl TryFrom<PackedMeld> for Chii {
67 type Error = ();
68
69 fn try_from(raw: PackedMeld) -> Result<Self, Self::Error> {
70 if raw.kind() != PackedMeldKind::Chii as u8 { return Err(()); }
71 let mut a = raw.get_tile().ok_or(())?;
72 let mut b = a.succ().unwrap();
73 let mut c = b.succ().unwrap();
74 if raw.red() > 0 {
75 a = a.to_red();
76 b = b.to_red();
77 c = c.to_red();
78 }
79 match raw.dir() {
80 0 => Chii::from_tiles(b, c, a),
81 1 => Chii::from_tiles(a, c, b),
82 2 => Chii::from_tiles(a, b, c),
83 _ => return Err(()),
84 }.ok_or(())
85 }
86}
87
88impl From<Chii> for PackedMeld {
89 fn from(chii: Chii) -> Self {
90 let [own0, own1] = chii.own;
91 let red = own0.is_red() || own1.is_red() || chii.called.is_red();
92 PackedMeld::new()
93 .with_tile(chii.min.encoding())
94 .with_dir(chii.dir())
95 .with_red(red as u8)
96 .with_kind(PackedMeldKind::Chii as u8)
97 }
98}