use derivative::Derivative;
use rustc_hash::FxHashSet as HashSet;
use semver::Version;
#[cfg(feature = "serde")]
use serde_with::{
serde_as, skip_serializing_none,
As, DisplayFromStr
};
use riichi_elements::prelude::*;
use crate::{
yaku::Yaku,
};
#[derive(Derivative)]
#[derive(Clone, Debug)]
#[derivative(Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", serde_as)]
#[cfg_attr(feature = "serde", skip_serializing_none)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct Ruleset {
#[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
#[derivative(Default(value = "crate::VERSION.clone()"))]
pub version: Version,
#[derivative(Default(value = "7"))]
pub kyoku_max_soft: u8,
#[derivative(Default(value = "15"))]
pub kyoku_max_hard: u8,
#[derivative(Default(value = "30000"))]
pub points_min_qualify: GamePoints,
#[derivative(Default(value = "2"))]
pub ron_max_num_players: u8,
#[derivative(Default(value = "false"))]
pub ron_first_only: bool,
#[derivative(Default(value = "true"))]
pub dora_allow_ura: bool,
#[derivative(Default(value = "true"))]
pub dora_allow_kan: bool,
#[derivative(Default(value = "true"))]
pub dora_allow_kan_ura: bool,
#[derivative(Default(value = "true"))]
pub yaku_allow_open_tanyao: bool,
pub yaku_extra: HashSet<Yaku>,
pub yaku_block: HashSet<Yaku>,
#[derivative(Default(value = "false"))]
pub kokushi_chankan_allow_ankan: bool,
#[derivative(Default(value = "false"))]
pub swap_call_allow_same: bool,
#[derivative(Default(value = "false"))]
pub swap_call_allow_other: bool,
#[derivative(Default(value = "true"))]
pub riichi_ankan_strict_mode: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "serde")]
mod serde_tests {
use assert_json_diff::assert_json_eq;
use super::*;
#[test]
fn ruleset_example() {
let ruleset = Ruleset {
yaku_block: HashSet::from_iter([Yaku::Iipeikou]),
kyoku_max_soft: 3,
kyoku_max_hard: 7,
..Ruleset::default()
};
let json = serde_json::json!({
"version": crate::VERSION_STR,
"kyoku_max_soft": 3,
"kyoku_max_hard": 7,
"points_min_qualify": 30000,
"ron_max_num_players": 2,
"ron_first_only": false,
"dora_allow_ura": true,
"dora_allow_kan": true,
"dora_allow_kan_ura": true,
"yaku_allow_open_tanyao": true,
"yaku_extra": [],
"yaku_block": ["Iipeikou"],
"kokushi_chankan_allow_ankan": true,
"swap_call_allow_same": false,
"swap_call_allow_other": false,
"riichi_ankan_strict_mode": true,
});
let serialized = serde_json::to_value(ruleset.clone()).unwrap();
let deserialized: Ruleset = serde_json::from_value(json.clone()).unwrap();
assert_json_eq!(serialized, json);
assert_eq!(deserialized, ruleset);
}
}
}