use serde::{Deserialize, Serialize};
use crate::core::EarthlyBranch;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PalaceRelation {
Same,
Opposite,
Trine,
SanFangSiZheng,
Adjacent,
ClampedBy,
}
pub fn opposite(branch: EarthlyBranch) -> EarthlyBranch {
branch.offset(6)
}
pub fn trine_branches(branch: EarthlyBranch) -> [EarthlyBranch; 3] {
[branch, branch.offset(4), branch.offset(8)]
}
pub fn san_fang_si_zheng(branch: EarthlyBranch) -> [EarthlyBranch; 4] {
[branch, branch.offset(6), branch.offset(4), branch.offset(8)]
}
pub fn is_opposite(anchor: EarthlyBranch, target: EarthlyBranch) -> bool {
opposite(anchor) == target
}
pub fn is_in_trine_group(anchor: EarthlyBranch, target: EarthlyBranch) -> bool {
trine_branches(anchor).contains(&target)
}
pub fn is_in_san_fang_si_zheng(anchor: EarthlyBranch, target: EarthlyBranch) -> bool {
san_fang_si_zheng(anchor).contains(&target)
}
pub fn clamp_branches(branch: EarthlyBranch) -> [EarthlyBranch; 2] {
[branch.offset(-1), branch.offset(1)]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::EarthlyBranch::{Chen, Mao, Shen, Si, Wei, Yin, You, Zi};
#[test]
fn opposite_is_offset_six() {
assert_eq!(opposite(Yin), Shen);
assert_eq!(opposite(Zi), EarthlyBranch::Wu);
}
#[test]
fn trine_branches_are_self_plus_four_and_eight() {
assert_eq!(
trine_branches(Yin),
[Yin, EarthlyBranch::Wu, EarthlyBranch::Xu]
);
}
#[test]
fn san_fang_si_zheng_is_self_opposite_and_trine() {
let set = san_fang_si_zheng(Yin);
assert!(set.contains(&Yin));
assert!(set.contains(&Shen)); assert!(set.contains(&EarthlyBranch::Wu)); assert!(set.contains(&EarthlyBranch::Xu)); assert_eq!(set.len(), 4);
}
#[test]
fn is_in_san_fang_si_zheng_membership() {
assert!(is_in_san_fang_si_zheng(Yin, Yin));
assert!(is_in_san_fang_si_zheng(Yin, Shen));
assert!(is_in_san_fang_si_zheng(Yin, EarthlyBranch::Wu));
assert!(!is_in_san_fang_si_zheng(Yin, Mao));
for b in [Chen, Si, Wei, You] {
assert!(!is_in_san_fang_si_zheng(Yin, b));
}
}
#[test]
fn is_in_trine_group_includes_anchor() {
assert!(is_in_trine_group(Yin, Yin)); assert!(is_in_trine_group(Yin, EarthlyBranch::Wu)); assert!(is_in_trine_group(Yin, EarthlyBranch::Xu)); assert!(!is_in_trine_group(Yin, Shen)); }
#[test]
fn clamp_branches_are_neighbours() {
assert_eq!(clamp_branches(Mao), [Yin, Chen]);
}
}