use std::fmt::Display;
use std::fmt::Formatter;
use crate::auspice::Auspice;
use crate::enums::QimenDoor;
use crate::enums::QimenStar;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Element {
Wood,
Fire,
Earth,
Metal,
Water,
}
impl Element {
pub const fn name(self) -> &'static str {
match self {
Self::Wood => "木",
Self::Fire => "火",
Self::Earth => "土",
Self::Metal => "金",
Self::Water => "水",
}
}
pub const fn from_heaven_stem_index(index: usize) -> Self {
match index {
0 | 1 => Self::Wood,
2 | 3 => Self::Fire,
4 | 5 => Self::Earth,
6 | 7 => Self::Metal,
_ => Self::Water,
}
}
pub const fn from_earth_branch_index(index: usize) -> Self {
match index {
0 | 11 => Self::Water, 1 | 4 | 7 | 10 => Self::Earth, 2 | 3 => Self::Wood, 5 | 6 => Self::Fire, _ => Self::Metal, }
}
pub const fn from_palace(palace: u8) -> Self {
match palace {
1 => Self::Water,
3 | 4 => Self::Wood,
6 | 7 => Self::Metal,
9 => Self::Fire,
_ => Self::Earth,
}
}
pub const fn relation_to(self, other: Self) -> ElementRelation {
if matches!(
(self, other),
(Self::Wood, Self::Wood)
| (Self::Fire, Self::Fire)
| (Self::Earth, Self::Earth)
| (Self::Metal, Self::Metal)
| (Self::Water, Self::Water)
) {
return ElementRelation::Same;
}
if matches!(
(self, other),
(Self::Wood, Self::Fire)
| (Self::Fire, Self::Earth)
| (Self::Earth, Self::Metal)
| (Self::Metal, Self::Water)
| (Self::Water, Self::Wood)
) {
return ElementRelation::Generates;
}
if matches!(
(self, other),
(Self::Fire, Self::Wood)
| (Self::Earth, Self::Fire)
| (Self::Metal, Self::Earth)
| (Self::Water, Self::Metal)
| (Self::Wood, Self::Water)
) {
return ElementRelation::Generated;
}
if matches!(
(self, other),
(Self::Wood, Self::Earth)
| (Self::Earth, Self::Water)
| (Self::Water, Self::Fire)
| (Self::Fire, Self::Metal)
| (Self::Metal, Self::Wood)
) {
return ElementRelation::Restrains;
}
ElementRelation::Restrained
}
}
impl Display for Element {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(self.name()) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ElementRelation {
Same,
Generates,
Generated,
Restrains,
Restrained,
}
impl ElementRelation {
pub const fn name(self) -> &'static str {
match self {
Self::Same => "比和",
Self::Generates => "生出",
Self::Generated => "受生",
Self::Restrains => "克出",
Self::Restrained => "受克",
}
}
pub const fn auspice_as_self(self) -> Auspice {
match self {
Self::Same | Self::Restrains => Auspice::Neutral,
Self::Generated => Auspice::Auspicious,
Self::Generates | Self::Restrained => Auspice::Inauspicious,
}
}
}
impl Display for ElementRelation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(self.name()) }
}
impl QimenStar {
pub const fn element(self) -> Element {
match self {
Self::TianPeng => Element::Water,
Self::TianChong | Self::TianFu => Element::Wood,
Self::TianYing => Element::Fire,
Self::TianXin | Self::TianZhu => Element::Metal,
Self::TianRui | Self::TianQin | Self::TianRen | Self::QinRui => Element::Earth,
}
}
}
impl QimenDoor {
pub const fn element(self) -> Element {
match self {
Self::Rest => Element::Water,
Self::Life | Self::Death => Element::Earth,
Self::Hurt | Self::Block => Element::Wood,
Self::View => Element::Fire,
Self::Fear | Self::Open => Element::Metal,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn relation_same() {
assert_eq!(Element::Wood.relation_to(Element::Wood), ElementRelation::Same);
assert_eq!(Element::Water.relation_to(Element::Water), ElementRelation::Same);
}
#[test]
fn relation_generation_cycle() {
assert_eq!(Element::Wood.relation_to(Element::Fire), ElementRelation::Generates);
assert_eq!(Element::Fire.relation_to(Element::Earth), ElementRelation::Generates);
assert_eq!(Element::Earth.relation_to(Element::Metal), ElementRelation::Generates);
assert_eq!(Element::Metal.relation_to(Element::Water), ElementRelation::Generates);
assert_eq!(Element::Water.relation_to(Element::Wood), ElementRelation::Generates);
}
#[test]
fn relation_generated_inverse() {
assert_eq!(Element::Fire.relation_to(Element::Wood), ElementRelation::Generated);
assert_eq!(Element::Wood.relation_to(Element::Water), ElementRelation::Generated);
}
#[test]
fn relation_restraint_cycle() {
assert_eq!(Element::Wood.relation_to(Element::Earth), ElementRelation::Restrains);
assert_eq!(Element::Earth.relation_to(Element::Water), ElementRelation::Restrains);
assert_eq!(Element::Water.relation_to(Element::Fire), ElementRelation::Restrains);
assert_eq!(Element::Fire.relation_to(Element::Metal), ElementRelation::Restrains);
assert_eq!(Element::Metal.relation_to(Element::Wood), ElementRelation::Restrains);
}
#[test]
fn relation_restrained_inverse() {
assert_eq!(Element::Earth.relation_to(Element::Wood), ElementRelation::Restrained);
assert_eq!(Element::Wood.relation_to(Element::Metal), ElementRelation::Restrained);
}
#[test]
fn palace_elements() {
assert_eq!(Element::from_palace(1), Element::Water);
assert_eq!(Element::from_palace(2), Element::Earth);
assert_eq!(Element::from_palace(3), Element::Wood);
assert_eq!(Element::from_palace(4), Element::Wood);
assert_eq!(Element::from_palace(5), Element::Earth);
assert_eq!(Element::from_palace(6), Element::Metal);
assert_eq!(Element::from_palace(7), Element::Metal);
assert_eq!(Element::from_palace(8), Element::Earth);
assert_eq!(Element::from_palace(9), Element::Fire);
}
#[test]
fn star_elements() {
assert_eq!(QimenStar::TianPeng.element(), Element::Water);
assert_eq!(QimenStar::TianRui.element(), Element::Earth);
assert_eq!(QimenStar::TianYing.element(), Element::Fire);
assert_eq!(QimenStar::TianXin.element(), Element::Metal);
}
#[test]
fn door_elements() {
assert_eq!(QimenDoor::Rest.element(), Element::Water);
assert_eq!(QimenDoor::Hurt.element(), Element::Wood);
assert_eq!(QimenDoor::View.element(), Element::Fire);
assert_eq!(QimenDoor::Open.element(), Element::Metal);
}
#[test]
fn heaven_stem_elements() {
assert_eq!(Element::from_heaven_stem_index(0), Element::Wood); assert_eq!(Element::from_heaven_stem_index(1), Element::Wood); assert_eq!(Element::from_heaven_stem_index(2), Element::Fire); assert_eq!(Element::from_heaven_stem_index(4), Element::Earth); assert_eq!(Element::from_heaven_stem_index(6), Element::Metal); assert_eq!(Element::from_heaven_stem_index(9), Element::Water); }
#[test]
fn earth_branch_elements() {
assert_eq!(Element::from_earth_branch_index(0), Element::Water); assert_eq!(Element::from_earth_branch_index(2), Element::Wood); assert_eq!(Element::from_earth_branch_index(5), Element::Fire); assert_eq!(Element::from_earth_branch_index(8), Element::Metal); assert_eq!(Element::from_earth_branch_index(4), Element::Earth); }
}