use std::fmt::{Display, Formatter};
use riichi_elements::prelude::*;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "tiles"))]
pub enum Reaction {
Chii(Tile, Tile),
Pon(Tile, Tile),
Daiminkan,
RonAgari,
}
impl Reaction {
pub fn from_meld(meld: Meld) -> Option<Self> {
match meld {
Meld::Chii(chii) => Some(Self::Chii(chii.own[0], chii.own[1])),
Meld::Pon(pon) => Some(Self::Pon(pon.own[0], pon.own[1])),
Meld::Daiminkan(_) => Some(Self::Daiminkan),
_ => None,
}
}
}
impl Display for Reaction {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Reaction::Chii(a, b) => write!(f, "Chii({}{})", a.num(), b),
Reaction::Pon(a, b) => write!(f, "Pon({}{})", a.num(), b),
Reaction::Daiminkan => write!(f, "Daiminkan"),
Reaction::RonAgari => write!(f, "Ron"),
}
}
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
use super::*;
#[test]
fn reaction_order_by_priority() {
use Reaction::*;
let reactions = [
Chii(t!("1s"), t!("2s")),
Chii(t!("2s"), t!("3s")),
Pon(t!("0p"), t!("5p")),
Pon(t!("8p"), t!("8p")),
Daiminkan,
RonAgari,
];
for (low, high) in reactions.into_iter().tuple_windows() {
assert!(low < high);
}
}
#[cfg(feature = "serde")]
mod serde_tests {
use assert_json_diff::assert_json_eq;
use super::*;
#[test]
fn serde_two_args() {
let reaction = Reaction::Chii(t!("1s"), t!("2s"));
let json = serde_json::json!({"type": "Chii", "tiles": ["1s", "2s"]});
let serialized = serde_json::to_value(reaction).unwrap();
let deserialized: Reaction = serde_json::from_value(json.clone()).unwrap();
assert_json_eq!(serialized, json);
assert_eq!(deserialized, reaction);
}
#[test]
fn serde_no_args() {
let reaction = Reaction::RonAgari;
let json = serde_json::json!({"type": "RonAgari"});
let serialized = serde_json::to_value(reaction).unwrap();
let deserialized: Reaction = serde_json::from_value(json.clone()).unwrap();
assert_json_eq!(serialized, json);
assert_eq!(deserialized, reaction);
}
}
}