mirror of
https://github.com/minagawah/mikaboshi.git
synced 2026-03-27 08:28:29 +07:00
refactor: (1) Removed useless expressions (2) Applying "cargo fmt"
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mikaboshi"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Hiroki Minagawa
|
||||
Copyright (c) 2023 Hiroki Minagawa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
22
README.md
22
README.md
@@ -175,7 +175,25 @@ You can also explore the actual codes for they contain a lot of _doc tests_.
|
||||
RUST_BACKTRACE=1 cargo test -vv -- --nocapture
|
||||
```
|
||||
|
||||
## 5. Dislaimer
|
||||
## 5. Notes
|
||||
|
||||
### (1) cargo fmt
|
||||
|
||||
Looking into [rustfmt.toml](rustfmt.toml),
|
||||
you see the setting:
|
||||
|
||||
```toml
|
||||
format_strings = true
|
||||
```
|
||||
|
||||
which works only for the Nightly build.
|
||||
So, you need:
|
||||
|
||||
```bash
|
||||
cargo +nightly fmt
|
||||
```
|
||||
|
||||
## 6. Dislaimer
|
||||
|
||||
There is absolutely no gurantee about the accuracy of the service,
|
||||
information, or calculated results provided by the program,
|
||||
@@ -188,6 +206,6 @@ It shall be your own responsibility to ensure the service,
|
||||
information, or calculated results meet your specific requirements.
|
||||
|
||||
|
||||
## 6. License
|
||||
## 7. License
|
||||
|
||||
MIT license ([LICENSE](LICENSE))
|
||||
|
||||
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
format_strings = true # default: false
|
||||
max_width = 54 # default: 100
|
||||
264
src/bagua.rs
264
src/bagua.rs
@@ -1,32 +1,43 @@
|
||||
//! 八卦 (Ba-Gua) is a concept in 易経 (I-Ching) which is merely a concept
|
||||
//! in fortune telling, but also appears frequently in a variety of
|
||||
//! Chinese philosophy. "Gua" (卦) is a conventional unit which characterizes
|
||||
//! certain aspects/qualities in life. "Ba" simply means "8" in Chinese.
|
||||
//! So, "Ba-Gua" (八卦) tells that it consists of 8 卦 (Gua). To the eyes of
|
||||
//! ancient Chinese, everything in this world was of either 陰 (Yin) or 陽 (Yang).
|
||||
//! Or, you could say, the world is divided into 2. However, if you observe
|
||||
//! more carefully, you notice some in Yang may slightly lean toward Yin, and
|
||||
//! some in Yin toward Yang. So, you could probably have another division there,
|
||||
//! for this time, divisions of 4. For greater Yang, you have lesser "Yin"
|
||||
//! and "Yang", or you may call them, "Yang-Yang" and "Yang-Yin". Likewise,
|
||||
//! for Yin, you will have "Yin-Yang" and "Yin-Yin". If you are brave enough,
|
||||
//! you could repeat the process for the one last time. This time, you would
|
||||
//! divide the world into 8. For ancient Chinese perceived the last division
|
||||
//! of 8 being the basic building blocks for observing nature, and called
|
||||
//! them, 八卦 (Ba-Gua)
|
||||
//!
|
||||
//! Now, when we say 八卦 (Ba-Gua), we usually refer to 2 different systems.
|
||||
//! For the division just described above is called "先天八卦" (or
|
||||
//! _"The Primordial Heaven"_), and a diagram to represent this order
|
||||
//! is called "河圖" (He-Tu) (or 伏羲八卦 (Fu-Xi Ba-Gua)). Another one
|
||||
//! is called "後天八卦" (or _"The Manifested Heaven"_), and its diagram
|
||||
//! is called "洛書" (Lo-Shu) (or 文王八卦 (King Wen Ba-Gua)).
|
||||
//! For the former illustrates the world of the original heaven,
|
||||
//! and the latter, the manifested world (for which elements in nature
|
||||
//! play active roles to produce gross material plane of our reality).
|
||||
//!
|
||||
//! Order of 河圖 (He-Tu) (for 先天八卦 _"The Primordial Heaven"_)
|
||||
//!
|
||||
//! 八卦 (Ba-Gua) is a concept in 易経 (I-Ching) which
|
||||
//! is merely a concept in fortune telling, but also
|
||||
//! appears frequently in a variety of Chinese philosophy.
|
||||
//! "Gua" (卦) is a conventional unit which characterizes
|
||||
//! certain aspects/qualities in life. "Ba" simply
|
||||
//! means "8" in Chinese. So, "Ba-Gua" (八卦) tells
|
||||
//! that it consists of 8 卦 (Gua). To the eyes of
|
||||
//! ancient Chinese, everything in this world was of
|
||||
//! either 陰 (Yin) or 陽 (Yang). Or, you could say,
|
||||
//! the world is divided into 2. However, if you
|
||||
//! observe more carefully, you notice some in Yang
|
||||
//! may slightly lean toward Yin, and some in Yin
|
||||
//! toward Yang. So, you could probably have another
|
||||
//! division there, for this time, divisions of 4.
|
||||
//! For greater Yang, you have lesser "Yin" and "Yang",
|
||||
//! or you may call them, "Yang-Yang" and "Yang-Yin".
|
||||
//! Likewise, for Yin, you will have "Yin-Yang" and
|
||||
//! "Yin-Yin". If you are brave enough, you could
|
||||
//! repeat the process for the one last time.
|
||||
//! This time, you would divide the world into 8.
|
||||
//! For ancient Chinese perceived the last division
|
||||
//! of 8 being the basic building blocks for observing
|
||||
//! nature, and called them, 八卦 (Ba-Gua)
|
||||
//!
|
||||
//! Now, when we say 八卦 (Ba-Gua), we usually refer to
|
||||
//! 2 different systems. For the division just described
|
||||
//! above is called "先天八卦" (or _"The Primordial
|
||||
//! Heaven"_), and a diagram to represent this order
|
||||
//! is called "河圖" (He-Tu) (or 伏羲八卦 (Fu-Xi Ba-Gua)).
|
||||
//! Another one is called "後天八卦" (or _"The Manifested
|
||||
//! Heaven"_), and its diagram is called "洛書" (Lo-Shu)
|
||||
//! (or 文王八卦 (King Wen Ba-Gua)). For the former
|
||||
//! illustrates the world of the original heaven, and
|
||||
//! the latter, the manifested world (for which elements
|
||||
//! in nature play active roles to produce gross material
|
||||
//! plane of our reality).
|
||||
//!
|
||||
//! Order of 河圖 (He-Tu) (for 先天八卦 _"The Primordial
|
||||
//! Heaven"_)
|
||||
//!
|
||||
//! [0] 乾 (Qian)
|
||||
//! [1] 兌 (Dui)
|
||||
//! [2] 離 (Li)
|
||||
@@ -35,9 +46,10 @@
|
||||
//! [5] 坎 (Kan)
|
||||
//! [6] 坤 (Kun)
|
||||
//! [7] 艮 (Gen)
|
||||
//!
|
||||
//! Order of 洛書 (Lo-Shu) (for 後天八卦 _"The Manifested Heaven"_)
|
||||
//!
|
||||
//!
|
||||
//! Order of 洛書 (Lo-Shu) (for 後天八卦 _"The Manifested
|
||||
//! Heaven"_)
|
||||
//!
|
||||
//! [0] 坎 (Kan)
|
||||
//! [1] 坤 (Kun)
|
||||
//! [2] 震 (Zhen)
|
||||
@@ -46,47 +58,49 @@
|
||||
//! [5] 兌 (Dui)
|
||||
//! [6] 艮 (Gen)
|
||||
//! [7] 離 (Li)
|
||||
//!
|
||||
//! So, when we talk about 八卦 (Ba-Gua), we need to be specific about
|
||||
//! which world we referring to. As you can see, there are 3 sets
|
||||
//! of vectors defined in this program, namely:
|
||||
//!
|
||||
//!
|
||||
//! So, when we talk about 八卦 (Ba-Gua), we need to be
|
||||
//! specific about which world we referring to. As you
|
||||
//! can see, there are 3 sets of vectors defined in this
|
||||
//! program, namely:
|
||||
//!
|
||||
//! - `BAGUA_HE_TU_ORDER`
|
||||
//! - `BAGUA_LO_SHU_ORDER`
|
||||
//! - `BAGUA_LO_SHU_ORDER_WITH_CENTER`
|
||||
//!
|
||||
//! Notice that the first 2 consists of 8 items, but the third one
|
||||
//! consists of 9. When using 八卦 (Ba-Gua) for Feng-Shui, we usually
|
||||
//! refer to 洛書 (Lo-Shu) diagram (which is `BAGUA_LO_SHU_ORDER`).
|
||||
//! However, we usually plot 洛書 (Lo-Shu) into 9 boxes because it is
|
||||
//! often associated with 九星 (Jiu-Xing) which requires not only
|
||||
//! 8 compass directions, but with an extra box in the middle.
|
||||
//! So, in addition to 八卦 (Ba-Gua), when managing 洛書 (Lo-Shu)
|
||||
//! for Feng-Shui, we need CENTER (or "中" (Zhong) in Chinese),
|
||||
//! and that is what we have for `BAGUA_LO_SHU_ORDER_WITH_CENTER`.
|
||||
//!
|
||||
//! Also, notice of another vector defined in the program, namely,
|
||||
//! `BAGUA_LO_SHU_COMPASS_ORDER`. This is a special vector for which
|
||||
//! the order is _conceptually_ in "Lo-Shu" order, however, mapped
|
||||
//! to 8 compass directions as each 卦 (Gua) plotted in clockwise manner.
|
||||
//! This is specially useful when we have an app with a compass UI
|
||||
//! because you can directly plot 卦 (Gua) out of this vector.
|
||||
//!
|
||||
//! Notice that the first 2 consists of 8 items, but
|
||||
//! the third one consists of 9. When using 八卦 (Ba-Gua)
|
||||
//! for Feng-Shui, we usually refer to 洛書 (Lo-Shu)
|
||||
//! diagram (which is `BAGUA_LO_SHU_ORDER`). However,
|
||||
//! we usually plot 洛書 (Lo-Shu) into 9 boxes because
|
||||
//! it is often associated with 九星 (Jiu-Xing) which
|
||||
//! requires not only 8 compass directions, but with
|
||||
//! an extra box in the middle. So, in addition to
|
||||
//! 八卦 (Ba-Gua), when managing 洛書 (Lo-Shu) for
|
||||
//! Feng-Shui, we need CENTER (or "中" (Zhong)
|
||||
//! in Chinese), and that is what we have for
|
||||
//! `BAGUA_LO_SHU_ORDER_WITH_CENTER`.
|
||||
//!
|
||||
//! Also, notice, another vector defined in
|
||||
//! the program, `BAGUA_LO_SHU_COMPASS_ORDER`.
|
||||
//! This is a special vector for which the order is
|
||||
//! _conceptually_ in "Lo-Shu" order, however, mapped to
|
||||
//! 8 compass directions as each 卦 (Gua) plotted in
|
||||
//! clockwise manner. This is specially useful when we
|
||||
//! have an app with a compass UI because you can
|
||||
//! directly plot 卦 (Gua) out of this vector.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
|
||||
use crate::utils::{
|
||||
get_json,
|
||||
make_sort,
|
||||
};
|
||||
use crate::utils::{get_json, make_sort};
|
||||
|
||||
/// A struct representing 卦 (Gua) and stores its attributes.
|
||||
/// A struct representing 卦 (Gua) and stores its
|
||||
/// attributes.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Gua {
|
||||
pub name: Language,
|
||||
@@ -95,8 +109,8 @@ pub struct Gua {
|
||||
pub element: u8,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining
|
||||
/// a various vectors for 八卦 (Ba-Gua).
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a various vectors for 八卦 (Ba-Gua).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GuaRaw {
|
||||
pub name: LanguageData,
|
||||
@@ -118,26 +132,30 @@ impl NameDataTrait for GuaRaw {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// This is a vector for 八卦 (Ba-Gua) with 9 items where the 5th item
|
||||
/// being "中" (Zhong). By having 9 items instead of 8, it can be
|
||||
/// directly mapped to 9 stars of 九星 (Jiu-Xing). Since 九星 (Jiu-Xing)
|
||||
/// is mapped in "Lo-Shu" (洛書) order, so is this vector.
|
||||
/// Check out the attribute `jiuxing_num` for each data, and you will
|
||||
/// notice it corresponds to the Jiu-Xing number.
|
||||
/// This is a vector for 八卦 (Ba-Gua) with 9 items
|
||||
/// where the 5th item being "中" (Zhong). By having
|
||||
/// 9 items instead of 8, it can be directly mapped
|
||||
/// to 9 stars of 九星 (Jiu-Xing). Since 九星
|
||||
/// (Jiu-Xing) is mapped in "Lo-Shu" (洛書) order,
|
||||
/// so is this vector. Check out the attribute
|
||||
/// `jiuxing_num` for each data, and you will notice
|
||||
/// it corresponds to the Jiu-Xing number.
|
||||
///
|
||||
/// 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order with 中 (Zhong) in the middle:
|
||||
/// 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order with
|
||||
/// 中 (Zhong) in the middle:
|
||||
///
|
||||
/// [0] 坎 (Kan) -> No. 1
|
||||
/// [1] 坤 (Kun) -> No. 2
|
||||
/// [2] 震 (Zhen) -> No. 3
|
||||
/// [3] 巽 (Xun) -> No. 4
|
||||
/// [4] 中 (Zhong) -> No. 5
|
||||
/// [5] 乾 (Qian) -> No. 6
|
||||
/// [6] 兌 (Dui) -> No. 7
|
||||
/// [7] 艮 (Gen) -> No. 8
|
||||
/// [8] 離 (Li) -> No. 9
|
||||
/// [0] 坎 (Kan) -> No. 1
|
||||
/// [1] 坤 (Kun) -> No. 2
|
||||
/// [2] 震 (Zhen) -> No. 3
|
||||
/// [3] 巽 (Xun) -> No. 4
|
||||
/// [4] 中 (Zhong) -> No. 5
|
||||
/// [5] 乾 (Qian) -> No. 6
|
||||
/// [6] 兌 (Dui) -> No. 7
|
||||
/// [7] 艮 (Gen) -> No. 8
|
||||
/// [8] 離 (Li) -> No. 9
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// For attributes details stored in the vector is
|
||||
/// found in JSON file:
|
||||
/// `src/json/bagua.json`
|
||||
pub static ref BAGUA_LO_SHU_ORDER_WITH_CENTER: Vec<Gua> = {
|
||||
let json = &include_str!("../json/bagua.json");
|
||||
@@ -156,16 +174,17 @@ lazy_static! {
|
||||
/// [INDEX] 八卦 (Ba-Gua) in "He-Tu" (河圖) order.
|
||||
pub static ref BAGUA_HE_TU_ORDER_INDEXES: Vec<u8> = vec![0, 1, 2, 3, 5, 6, 7, 8];
|
||||
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "He-Tu" (河圖) order.
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "He-Tu" (河圖)
|
||||
/// order.
|
||||
///
|
||||
/// [0] 乾 (Qian)
|
||||
/// [1] 兌 (Dui)
|
||||
/// [2] 離 (Li)
|
||||
/// [3] 震 (Zhen)
|
||||
/// [4] 巽 (Xun)
|
||||
/// [5] 坎 (Kan)
|
||||
/// [6] 坤 (Kun)
|
||||
/// [7] 艮 (Gen)
|
||||
/// [0] 乾 (Qian)
|
||||
/// [1] 兌 (Dui)
|
||||
/// [2] 離 (Li)
|
||||
/// [3] 震 (Zhen)
|
||||
/// [4] 巽 (Xun)
|
||||
/// [5] 坎 (Kan)
|
||||
/// [6] 坤 (Kun)
|
||||
/// [7] 艮 (Gen)
|
||||
pub static ref BAGUA_HE_TU_ORDER: Vec<Gua> = make_sort(
|
||||
BAGUA_HE_TU_ORDER_INDEXES.to_vec() // order
|
||||
)(
|
||||
@@ -175,41 +194,48 @@ lazy_static! {
|
||||
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order.
|
||||
pub static ref BAGUA_LO_SHU_ORDER_INDEXES: Vec<u8> = vec![0, 1, 2, 3, 5, 6, 7, 8];
|
||||
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" (洛書) order.
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" (洛書)
|
||||
/// order.
|
||||
///
|
||||
/// [0] 坎 (Kan)
|
||||
/// [1] 艮 (Gen)
|
||||
/// [2] 震 (Zhen)
|
||||
/// [3] 巽 (Xun)
|
||||
/// [4] 離 (Li)
|
||||
/// [5] 坤 (Kun)
|
||||
/// [6] 兌 (Dui)
|
||||
/// [7] 乾 (Qian)
|
||||
/// [0] 坎 (Kan)
|
||||
/// [1] 艮 (Gen)
|
||||
/// [2] 震 (Zhen)
|
||||
/// [3] 巽 (Xun)
|
||||
/// [4] 離 (Li)
|
||||
/// [5] 坤 (Kun)
|
||||
/// [6] 兌 (Dui)
|
||||
/// [7] 乾 (Qian)
|
||||
pub static ref BAGUA_LO_SHU_ORDER: Vec<Gua> = make_sort(
|
||||
BAGUA_LO_SHU_ORDER_INDEXES.to_vec() // order
|
||||
)(
|
||||
BAGUA_LO_SHU_ORDER_WITH_CENTER.to_vec() // data source
|
||||
);
|
||||
|
||||
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" order, however, mapped to 8 compass directions.
|
||||
/// [INDEX] 八卦 (Ba-Gua) in "Lo-Shu" order, however,
|
||||
/// mapped to 8 compass directions.
|
||||
pub static ref BAGUA_LO_SHU_COMPASS_ORDER_INDEXES: Vec<u8> = vec![0, 7, 2, 3, 8, 1, 6, 5];
|
||||
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" order, however, mapped to 8 compass directions.
|
||||
/// When "Lo-Shu" (洛書) order is mapped to 8 compass directions, it is convenient
|
||||
/// to have a vector which starts with 卦 (Gua) for _"NORTH"_ which is "坎" (Kan).
|
||||
/// Likewise, we want the second item being 卦 (Gua) for _"NORTH EAST"_ which is "艮" (Gen).
|
||||
/// For the third item, likewise, for _"EAST"_ or "震" (Zhen).
|
||||
/// [ACTUAL DATA] 八卦 (Ba-Gua) in "Lo-Shu" order,
|
||||
/// however, mapped to 8 compass directions. When
|
||||
/// "Lo-Shu" (洛書) order is mapped to 8 compass
|
||||
/// directions, it is convenient to have a vector
|
||||
/// which starts with 卦 (Gua) for _"NORTH"_ which
|
||||
/// is "坎" (Kan). Likewise, we want the second
|
||||
/// item being 卦 (Gua) for _"NORTH EAST"_ which is
|
||||
/// "艮" (Gen). For the third item, likewise, for
|
||||
/// _"EAST"_ or "震" (Zhen).
|
||||
///
|
||||
/// 八卦 (Ba-Gua) in "Lo-Shu" order mapped to 8 directions (starting NORTH):
|
||||
/// 八卦 (Ba-Gua) in "Lo-Shu" order mapped to
|
||||
/// 8 directions (starting NORTH):
|
||||
///
|
||||
/// [0] 坎 (Kan)
|
||||
/// [1] 艮 (Gen)
|
||||
/// [2] 震 (Zhen)
|
||||
/// [3] 巽 (Xun)
|
||||
/// [4] 離 (Li)
|
||||
/// [5] 坤 (Kun)
|
||||
/// [6] 兌 (Dui)
|
||||
/// [7] 乾 (Qian)
|
||||
/// [0] 坎 (Kan)
|
||||
/// [1] 艮 (Gen)
|
||||
/// [2] 震 (Zhen)
|
||||
/// [3] 巽 (Xun)
|
||||
/// [4] 離 (Li)
|
||||
/// [5] 坤 (Kun)
|
||||
/// [6] 兌 (Dui)
|
||||
/// [7] 乾 (Qian)
|
||||
pub static ref BAGUA_LO_SHU_COMPASS_ORDER: Vec<Gua> = make_sort(
|
||||
BAGUA_LO_SHU_COMPASS_ORDER_INDEXES.to_vec() // order
|
||||
)(
|
||||
@@ -230,7 +256,9 @@ lazy_static! {
|
||||
/// JsValue::from_serde(&gua).unwrap()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_gua_compass_order(index: usize) -> Option<&'static Gua> {
|
||||
pub fn get_gua_compass_order(
|
||||
index: usize,
|
||||
) -> Option<&'static Gua> {
|
||||
match BAGUA_LO_SHU_COMPASS_ORDER.get(index) {
|
||||
Some(gua) => Some(gua),
|
||||
None => None,
|
||||
@@ -243,7 +271,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_constant_bagua_list_full() {
|
||||
assert_eq!(BAGUA_LO_SHU_ORDER_WITH_CENTER[0].jiuxing_num, 1);
|
||||
assert_eq!(
|
||||
BAGUA_LO_SHU_ORDER_WITH_CENTER[0]
|
||||
.jiuxing_num,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: BAGUA_LO_SHU_COMPASS_ORDER_INDEXES
|
||||
|
||||
239
src/compass.rs
239
src/compass.rs
@@ -1,19 +1,18 @@
|
||||
//! A module for compass directions. When dividing 360 degrees into 8,
|
||||
//! we get 45 degrees. Ancient Chinese further divided them each into 3
|
||||
//! (called "sectors"), each having 15 degrees. Meaning, there are
|
||||
//! 24 sectors as a total. This is called, 二十四山向 (Er-Shi-Si Shan-Xiang).
|
||||
//! Not only for 8 directions, but these 24 directions (sectors)
|
||||
//! are used in Feng-Shui, and this is the module for these directions.
|
||||
//! A module for compass directions. When dividing 360
|
||||
//! degrees into 8, we get 45 degrees. Ancient Chinese
|
||||
//! further divided them each into 3 (called "sectors"),
|
||||
//! each having 15 degrees. Meaning, there are 24 sectors
|
||||
//! as a total. This is called, 二十四山向 (Er-Shi-Si
|
||||
//! Shan-Xiang). Not only for 8 directions, but these
|
||||
//! 24 directions (sectors) are used in Feng-Shui, and
|
||||
//! this is the module for these directions.
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::bagua::{Gua, BAGUA_LO_SHU_ORDER_WITH_CENTER};
|
||||
use crate::ganzhi::{
|
||||
Branch,
|
||||
Stem,
|
||||
BRANCHES,
|
||||
STEMS,
|
||||
use crate::bagua::{
|
||||
Gua, BAGUA_LO_SHU_ORDER_WITH_CENTER,
|
||||
};
|
||||
use crate::ganzhi::{Branch, Stem, BRANCHES, STEMS};
|
||||
|
||||
/// 二十四山向 (Er-Shi-Si Shan-Xiang) can be
|
||||
/// either 卦 (Gua), 干 (Gan), or 支 (Zhi).
|
||||
@@ -25,14 +24,19 @@ pub enum TwentyFourType<'a> {
|
||||
|
||||
/// A struct representing compass direction.
|
||||
/// For each direction, there are 3 sectors.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Direction {
|
||||
pub direction: String,
|
||||
pub sector: usize,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub fn new(direction: &str, sector: usize) -> Direction {
|
||||
pub fn new(
|
||||
direction: &str,
|
||||
sector: usize,
|
||||
) -> Direction {
|
||||
Direction {
|
||||
direction: direction.to_string(),
|
||||
sector,
|
||||
@@ -41,26 +45,29 @@ impl Direction {
|
||||
}
|
||||
|
||||
/// An array for 8 directions.
|
||||
pub const DIRECTIONS: [&str; 8] = ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
|
||||
pub const DIRECTIONS: [&str; 8] =
|
||||
["n", "ne", "e", "se", "s", "sw", "w", "nw"];
|
||||
|
||||
lazy_static! {
|
||||
/// A hash map with 9 items.
|
||||
/// Say, we have 9 boxes displayed on a device screen.
|
||||
/// Except for the box in the middle, we have 8 boxes
|
||||
/// around the middle to represent 8 compass directions.
|
||||
/// When facing "n" (north), for the first row,
|
||||
/// we have "nw", "n", and "ne". For the second row,
|
||||
/// we have "w", "", and "e" (where "" being the middle box).
|
||||
/// For the last, we have "sw", "s", and "se".
|
||||
/// Say, we have 9 boxes displayed on a device
|
||||
/// screen. Except for the box in the middle, we
|
||||
/// have 8 boxes around the middle to represent
|
||||
/// 8 compass directions. When facing "n" (north),
|
||||
/// for the first row, we have "nw", "n", and "ne".
|
||||
/// For the second row, we have "w", "", and "e"
|
||||
/// (where "" being the middle box). For the last,
|
||||
/// we have "sw", "s", and "se".
|
||||
///
|
||||
/// [0] nw [1] n [2] ne
|
||||
/// [3] w [4] [5] e
|
||||
/// [6] sw [7] s [8] se
|
||||
/// [0] nw [1] n [2] ne
|
||||
/// [3] w [4] [5] e
|
||||
/// [6] sw [7] s [8] se
|
||||
///
|
||||
/// Now, consider when the device rotates.
|
||||
/// Depending on which direction the device is facing,
|
||||
/// we have different labels. For all 8 directions,
|
||||
/// this HashMap provides a map for the positions.
|
||||
/// Depending on which direction the device is
|
||||
/// facing, we have different labels. For all
|
||||
/// 8 directions, this HashMap provides a map for
|
||||
/// the positions.
|
||||
pub static ref DIRECTION_POSITIONS_IN_CHART: HashMap<&'static str, [&'static str; 9]> = [
|
||||
("n", ["nw", "n", "ne", "w", "", "e", "sw", "s", "se"]),
|
||||
("ne", ["n", "ne", "e", "nw", "", "se", "w", "sw", "s"]),
|
||||
@@ -93,7 +100,9 @@ lazy_static! {
|
||||
/// )
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_direction_positions_in_chart(direction: &str) -> Option<&[&str; 9]> {
|
||||
pub fn get_direction_positions_in_chart(
|
||||
direction: &str,
|
||||
) -> Option<&[&str; 9]> {
|
||||
DIRECTION_POSITIONS_IN_CHART.get(direction)
|
||||
}
|
||||
|
||||
@@ -133,25 +142,27 @@ pub fn get_opposite_direction(dir: &str) -> &str {
|
||||
OPPOSITE_DIRECTION[dir]
|
||||
}
|
||||
|
||||
/// An array with 24 items. Imagine having a circlar disc displayed
|
||||
/// on a device screen. When dividing 360 by 8 directions, we get
|
||||
/// 45 degrees for each. When each direction is further divided
|
||||
/// into 3, then each is called a "sector", and it has 15 degrees
|
||||
/// for each "sector". Sectors are placed in clockwise order
|
||||
/// An array with 24 items. Imagine having a circlar
|
||||
/// disc displayed on a device screen. When dividing 360
|
||||
/// by 8 directions, we get 45 degrees for each. When
|
||||
/// each direction is further divided into 3, then each
|
||||
/// is called a "sector", and it has 15 degrees for each
|
||||
/// "sector". Sectors are placed in clockwise order
|
||||
/// (left to right) for each direction, so that you see
|
||||
/// the sector 1 being placed on your very left. Then, you see
|
||||
/// the sector 2 in the middle, and the sector 3 on your right.
|
||||
/// Imagine the device pointing north. On the circular disc,
|
||||
/// what you see at the very top is the sector 2 of "N" (north),
|
||||
/// denoted as "N2". On your left, you see "N1".
|
||||
/// On your right, "N3".
|
||||
/// the sector 1 being placed on your very left. Then,
|
||||
/// you see the sector 2 in the middle, and the sector 3
|
||||
/// on your right. Imagine the device pointing north.
|
||||
/// On the circular disc, what you see at the very top
|
||||
/// is the sector 2 of "N" (north), denoted as "N2".
|
||||
/// On your left, you see "N1". On your right, "N3".
|
||||
///
|
||||
/// When we want to express all the 24 sectors, we want
|
||||
/// an array with 24 items. For the first item in the array [0],
|
||||
/// it is convenient to have "N2". Then, for the second item
|
||||
/// in the array [1], we want "N3". For [2], we want "NE1".
|
||||
/// For [3], we want "NE2". And, so on. As you can imagine,
|
||||
/// "N1" comes to the very last in the array, or [23].
|
||||
/// an array with 24 items. For the first item in the
|
||||
/// array [0], it is convenient to have "N2". Then, for
|
||||
/// the second item in the array [1], we want "N3".
|
||||
/// For [2], we want "NE1". For [3], we want "NE2".
|
||||
/// And, so on. As you can imagine, "N1" comes to the
|
||||
/// very last in the array, or [23].
|
||||
pub const TWENTYFOUR_SECTORS: [u8; 24] = [
|
||||
2, // 0: n
|
||||
3, // 1: n
|
||||
@@ -183,12 +194,12 @@ lazy_static! {
|
||||
/// An array with 24 items, for each represents
|
||||
/// each in 二十四山向 (Er-Shi-Si Shan-Xiang).
|
||||
/// Note, the array begins with "N2"
|
||||
/// (and "N1" is stored at the very last, or [23]).
|
||||
/// Ex.
|
||||
/// 0: Direction { direction: "n", sector: 2 }
|
||||
/// 1: Direction { direction: "n", sector: 3 }
|
||||
/// 2: Direction { direction: "ne", sector: 1 }
|
||||
/// 3: Direction { direction: "ne", sector: 2 }
|
||||
/// (and "N1" is stored at the very last, or [23]).
|
||||
/// Ex.
|
||||
/// 0: Direction { direction: "n", sector: 2 }
|
||||
/// 1: Direction { direction: "n", sector: 3 }
|
||||
/// 2: Direction { direction: "ne", sector: 1 }
|
||||
/// 3: Direction { direction: "ne", sector: 2 }
|
||||
pub static ref TWENTYFOUR_INDEX_TO_DIRECTIONS: Vec<Direction> = {
|
||||
let mut vec: Vec<Direction> = DIRECTIONS
|
||||
.iter()
|
||||
@@ -221,7 +232,9 @@ lazy_static! {
|
||||
/// JsValue::from_serde(dir).unwrap()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_twentyfour_direction_from_index(index: usize) -> &'static Direction {
|
||||
pub fn get_twentyfour_direction_from_index(
|
||||
index: usize,
|
||||
) -> &'static Direction {
|
||||
&TWENTYFOUR_INDEX_TO_DIRECTIONS[index]
|
||||
}
|
||||
|
||||
@@ -229,11 +242,11 @@ lazy_static! {
|
||||
/// A HashMap mapping direction (combination of "direction" and "sector")
|
||||
/// to the corresponding index.
|
||||
///
|
||||
/// n2: 0
|
||||
/// n3: 1
|
||||
/// ne1: 2
|
||||
/// ne2: 3
|
||||
/// ...
|
||||
/// n2: 0
|
||||
/// n3: 1
|
||||
/// ne1: 2
|
||||
/// ne2: 3
|
||||
/// ...
|
||||
/// ...
|
||||
pub static ref TWENTYFOUR_DIRECTIONS_TO_INDEX: HashMap<String, usize> = TWENTYFOUR_INDEX_TO_DIRECTIONS
|
||||
.iter()
|
||||
@@ -245,11 +258,15 @@ lazy_static! {
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// An array with 24 items, each being a tuple. For each tuple,
|
||||
/// the first represents the type of 二十四山向 (Er-Shi-Si Shan-Xiang),
|
||||
/// and the second is the index of the type.
|
||||
/// The type being: [0] BAGUA, [1] STEM, or [2] BRANCH.
|
||||
pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
|
||||
/// An array with 24 items, each being a tuple.
|
||||
/// For each tuple, the first represents the type of
|
||||
/// 二十四山向 (Er-Shi-Si Shan-Xiang), and the second
|
||||
/// is the index of the type. The type being:
|
||||
/// [0] BAGUA, [1] STEM, or [2] BRANCH.
|
||||
pub const TWENTYFOUR_ORDER_START_NORTH: [(
|
||||
usize,
|
||||
usize,
|
||||
); 24] = [
|
||||
(2, 0), // 0: [0] 子
|
||||
(1, 9), // 1: [9] 癸
|
||||
(2, 1), // 2: [1] 丑
|
||||
@@ -276,7 +293,8 @@ pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
|
||||
(1, 8), // 23: [8] 壬
|
||||
];
|
||||
|
||||
/// From index, simply returns the corresponding `TwentyFourType`.
|
||||
/// From index, simply returns the corresponding
|
||||
/// `TwentyFourType`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -293,12 +311,19 @@ pub const TWENTYFOUR_ORDER_START_NORTH: [(usize, usize); 24] = [
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
|
||||
let (t_type, t_index) = TWENTYFOUR_ORDER_START_NORTH[index];
|
||||
pub fn get_twentyfour_data_from_index(
|
||||
index: usize,
|
||||
) -> TwentyFourType<'static> {
|
||||
let (t_type, t_index) =
|
||||
TWENTYFOUR_ORDER_START_NORTH[index];
|
||||
match t_type {
|
||||
0 => TwentyFourType::Gua(&BAGUA_LO_SHU_ORDER_WITH_CENTER[t_index]),
|
||||
0 => TwentyFourType::Gua(
|
||||
&BAGUA_LO_SHU_ORDER_WITH_CENTER[t_index],
|
||||
),
|
||||
1 => TwentyFourType::Stem(&STEMS[t_index]),
|
||||
2 => TwentyFourType::Branch(&BRANCHES[t_index]),
|
||||
2 => {
|
||||
TwentyFourType::Branch(&BRANCHES[t_index])
|
||||
}
|
||||
_ => panic!("Unknown type: {}", t_type),
|
||||
}
|
||||
}
|
||||
@@ -307,7 +332,8 @@ pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
|
||||
// From **DEGREES**
|
||||
// ===========================================================
|
||||
|
||||
/// From the given degrees, returns the corresponding `Direction`.
|
||||
/// From the given degrees, returns the corresponding
|
||||
/// `Direction`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -320,7 +346,9 @@ pub fn get_twentyfour_data_from_index(index: usize) -> TwentyFourType<'static> {
|
||||
/// JsValue::from_serde(&dir).unwrap()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_twentyfour_direction_from_degrees(d: f32) -> Direction {
|
||||
pub fn get_twentyfour_direction_from_degrees(
|
||||
d: f32,
|
||||
) -> Direction {
|
||||
if !(7.5..352.5).contains(&d) {
|
||||
// d >= 352.5 || d < 7.5
|
||||
Direction::new("n", 2)
|
||||
@@ -378,15 +406,23 @@ pub fn get_twentyfour_direction_from_degrees(d: f32) -> Direction {
|
||||
// From **DIRECTION**
|
||||
// ===========================================================
|
||||
|
||||
/// From the given direction and sector, finds the corresponding index
|
||||
/// in `TWENTYFOUR_DIRECTIONS_TO_INDEX`
|
||||
pub fn get_twentyfour_index_from_direction(direction: &str, sector: usize) -> usize {
|
||||
/// From the given direction and sector, finds the
|
||||
/// corresponding index in
|
||||
/// `TWENTYFOUR_DIRECTIONS_TO_INDEX`
|
||||
pub fn get_twentyfour_index_from_direction(
|
||||
direction: &str,
|
||||
sector: usize,
|
||||
) -> usize {
|
||||
*TWENTYFOUR_DIRECTIONS_TO_INDEX
|
||||
.get(format!("{}{}", direction, sector).as_str())
|
||||
.get(
|
||||
format!("{}{}", direction, sector)
|
||||
.as_str(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// From the given direction and sector, returns `TwentyFourType`.
|
||||
/// From the given direction and sector, returns
|
||||
/// `TwentyFourType`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -407,12 +443,23 @@ pub fn get_twentyfour_data_from_direction(
|
||||
direction: &str,
|
||||
sector: usize,
|
||||
) -> TwentyFourType<'static> {
|
||||
get_twentyfour_data_from_index(get_twentyfour_index_from_direction(direction, sector))
|
||||
get_twentyfour_data_from_index(
|
||||
get_twentyfour_index_from_direction(
|
||||
direction, sector,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// From the given direction and sector, returns `Direction`.
|
||||
pub fn get_twentyfour_direction_from_direction(direction: &str, sector: usize) -> &Direction {
|
||||
&TWENTYFOUR_INDEX_TO_DIRECTIONS[get_twentyfour_index_from_direction(direction, sector)]
|
||||
/// From the given direction and sector, returns
|
||||
/// `Direction`.
|
||||
pub fn get_twentyfour_direction_from_direction(
|
||||
direction: &str,
|
||||
sector: usize,
|
||||
) -> &Direction {
|
||||
&TWENTYFOUR_INDEX_TO_DIRECTIONS
|
||||
[get_twentyfour_index_from_direction(
|
||||
direction, sector,
|
||||
)]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -424,8 +471,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_direction_positions_in_chart() {
|
||||
let exp = ["nw", "n", "ne", "w", "", "e", "sw", "s", "se"];
|
||||
assert_eq!(get_direction_positions_in_chart("n").unwrap(), &exp);
|
||||
let exp = [
|
||||
"nw", "n", "ne", "w", "", "e", "sw", "s",
|
||||
"se",
|
||||
];
|
||||
assert_eq!(
|
||||
get_direction_positions_in_chart("n")
|
||||
.unwrap(),
|
||||
&exp
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: OPPOSITE_DIRECTION
|
||||
@@ -433,7 +487,8 @@ mod tests {
|
||||
// TODO: TWENTYFOUR_SECTORS
|
||||
|
||||
#[test]
|
||||
fn test_constant_twentyfour_index_to_directions() {
|
||||
fn test_constant_twentyfour_index_to_directions()
|
||||
{
|
||||
assert_eq!(
|
||||
TWENTYFOUR_INDEX_TO_DIRECTIONS[0],
|
||||
Direction {
|
||||
@@ -449,12 +504,21 @@ mod tests {
|
||||
direction: String::from("n"),
|
||||
sector: 2,
|
||||
};
|
||||
assert_eq!(get_twentyfour_direction_from_index(0), &exp);
|
||||
assert_eq!(
|
||||
get_twentyfour_direction_from_index(0),
|
||||
&exp
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_constant_twentyfour_directions_to_index() {
|
||||
assert_eq!(*TWENTYFOUR_DIRECTIONS_TO_INDEX.get("n2").unwrap(), 0_usize);
|
||||
fn test_constant_twentyfour_directions_to_index()
|
||||
{
|
||||
assert_eq!(
|
||||
*TWENTYFOUR_DIRECTIONS_TO_INDEX
|
||||
.get("n2")
|
||||
.unwrap(),
|
||||
0_usize
|
||||
);
|
||||
}
|
||||
|
||||
// Only for test
|
||||
@@ -471,13 +535,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_twentyfour_data_from_index() {
|
||||
assert!(get_twentyfour_data_from_index(0).is_branch());
|
||||
assert!(get_twentyfour_data_from_index(0)
|
||||
.is_branch());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_twentyfour_direction_from_degrees() {
|
||||
assert_eq!(
|
||||
get_twentyfour_direction_from_degrees(0_f32),
|
||||
get_twentyfour_direction_from_degrees(
|
||||
0_f32
|
||||
),
|
||||
Direction {
|
||||
direction: String::from("n"),
|
||||
sector: 2,
|
||||
|
||||
495
src/ganzhi.rs
495
src/ganzhi.rs
@@ -1,10 +1,13 @@
|
||||
//! Based on 5 elements in nature with its 陰 (Yin) and 陽 (Yang) for each,
|
||||
//! ancient Chinese described the plant growth using 10 conventional symbols
|
||||
//! known as "10 Gan" (十干). Also, they tracked the motion of Jupiter
|
||||
//! (which has 12 year cycle) and so they did divided the night sky into 12 regions,
|
||||
//! and this is known as "12 Zhi" (十二支). When they record time and space,
|
||||
//! they used the combinations of 10 Gan (干) and 12 Zhi (支)
|
||||
//! which makes 60 patterns, and this is called 干支 (Gan-Zhi).
|
||||
//! Based on 5 elements in nature with its 陰 (Yin) and
|
||||
//! 陽 (Yang) for each, ancient Chinese described the
|
||||
//! plant growth using 10 conventional symbols known as
|
||||
//! "10 Gan" (十干). Also, they tracked the motion of
|
||||
//! Jupiter (which has 12 year cycle) and so they did
|
||||
//! divided the night sky into 12 regions, and this is
|
||||
//! known as "12 Zhi" (十二支). When they record time
|
||||
//! and space, they used the combinations of 10 Gan (干)
|
||||
//! and 12 Zhi (支) which makes 60 patterns, and this
|
||||
//! is called 干支 (Gan-Zhi).
|
||||
//!
|
||||
//! 10 Gan (干):
|
||||
//!
|
||||
@@ -34,66 +37,56 @@
|
||||
//! [10] 戌 (Xu)
|
||||
//! [11] 亥 (Hai)
|
||||
|
||||
use chrono::naive::{NaiveDate, NaiveTime};
|
||||
use chrono::offset::{FixedOffset, Utc};
|
||||
use chrono::{DateTime, Datelike, Timelike};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{
|
||||
DateTime,
|
||||
Datelike,
|
||||
Timelike,
|
||||
};
|
||||
use chrono::offset::{
|
||||
Utc,
|
||||
FixedOffset,
|
||||
};
|
||||
use chrono::naive::{
|
||||
NaiveDate,
|
||||
NaiveTime,
|
||||
};
|
||||
|
||||
use sowngwala::time::{
|
||||
julian_day_from_generic_date,
|
||||
julian_day_from_generic_datetime,
|
||||
modified_julian_day_from_generic_datetime,
|
||||
naive_date_from_generic_datetime,
|
||||
naive_time_from_generic_datetime,
|
||||
utc_from_fixed,
|
||||
naive_time_from_generic_datetime, utc_from_fixed,
|
||||
};
|
||||
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
|
||||
use crate::solar_terms::get_lichun;
|
||||
|
||||
use crate::utils::{
|
||||
get_json,
|
||||
longitude_of_the_sun_from_generic_date,
|
||||
get_json, longitude_of_the_sun_from_generic_date,
|
||||
};
|
||||
|
||||
/// A struct representing 干 (Gan) or "Stem" and stores its attributes.
|
||||
/// A struct representing 干 (Gan) or "Stem" and stores
|
||||
/// its attributes.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Stem {
|
||||
pub num: u8,
|
||||
pub name: Language,
|
||||
}
|
||||
|
||||
/// A struct representing 支 (Zhi) or "Branch" and stores its attributes.
|
||||
/// A struct representing 支 (Zhi) or "Branch" and
|
||||
/// stores its attributes.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Branch {
|
||||
pub num: u8,
|
||||
pub name: Language,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining a static const `STEMS`.
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a static const `STEMS`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StemRawData {
|
||||
pub num: u8,
|
||||
pub name: LanguageData,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining a static const `BRANCHES`.
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a static const `BRANCHES`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BranchRawData {
|
||||
pub num: u8,
|
||||
@@ -112,17 +105,19 @@ impl NameDataTrait for BranchRawData {
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct for holding `Stem` and `Branch`, or denoted as 干支 (Gan-Zhi).
|
||||
/// A struct for holding `Stem` and `Branch`, or denoted
|
||||
/// as 干支 (Gan-Zhi).
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct GanZhi<'a> {
|
||||
pub stem: &'a Stem,
|
||||
pub branch: &'a Branch,
|
||||
}
|
||||
|
||||
/// A struct representing 八字 (Bazi) and stores `GanZhi` as its attributes.
|
||||
/// It is referred as "The Four Pillars of Destiny" in English
|
||||
/// mainly because the structure of 八字 (Bazi) necessary
|
||||
/// for divinations in 四柱命理学 (_"The Four Pillars of Destiny"_).
|
||||
/// A struct representing 八字 (Bazi) and stores `GanZhi`
|
||||
/// as its attributes. It is referred as "The Four
|
||||
/// Pillars of Destiny" in English mainly because the
|
||||
/// structure of 八字 (Bazi) necessary for divinations
|
||||
/// in 四柱命理学 (_"The Four Pillars of Destiny"_).
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Bazi<'a> {
|
||||
pub year: GanZhi<'a>,
|
||||
@@ -144,22 +139,37 @@ impl LanguageTrait for Branch {
|
||||
}
|
||||
|
||||
impl GanZhi<'_> {
|
||||
/// Concatenate Stem & Branch (for Chinese characters)
|
||||
/// Concatenate Stem & Branch (for Chinese
|
||||
/// characters)
|
||||
#[allow(dead_code)]
|
||||
fn alphabet(&self) -> String {
|
||||
format!("{}{}", self.stem.alphabet(), self.branch.alphabet())
|
||||
format!(
|
||||
"{}{}",
|
||||
self.stem.alphabet(),
|
||||
self.branch.alphabet()
|
||||
)
|
||||
}
|
||||
|
||||
/// Concatenate Stem & Branch (for Chinese phonetics)
|
||||
/// Concatenate Stem & Branch (for Chinese
|
||||
/// phonetics)
|
||||
#[allow(dead_code)]
|
||||
fn phonetic(&self) -> String {
|
||||
format!("{} {}", self.stem.phonetic(), self.branch.phonetic())
|
||||
format!(
|
||||
"{} {}",
|
||||
self.stem.phonetic(),
|
||||
self.branch.phonetic()
|
||||
)
|
||||
}
|
||||
|
||||
/// Concatenate Stem & Branch (for Japanese characters)
|
||||
/// Concatenate Stem & Branch (for Japanese
|
||||
/// characters)
|
||||
#[allow(dead_code)]
|
||||
fn alphabet_ja(&self) -> String {
|
||||
format!("{}・{}", self.stem.alphabet_ja(), self.branch.alphabet_ja())
|
||||
format!(
|
||||
"{}・{}",
|
||||
self.stem.alphabet_ja(),
|
||||
self.branch.alphabet_ja()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +188,8 @@ impl<'a> Bazi<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Bazi` from localtime (`DateTime`) and zone (`i8`).
|
||||
/// Returns `Bazi` from localtime (`DateTime`) and
|
||||
/// zone (`i8`).
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -202,35 +213,52 @@ impl<'a> Bazi<'a> {
|
||||
/// ).unwrap()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn from_fixed(fixed: DateTime<FixedOffset>) -> Bazi<'a> {
|
||||
pub fn from_fixed(
|
||||
fixed: DateTime<FixedOffset>,
|
||||
) -> Bazi<'a> {
|
||||
let utc = utc_from_fixed(fixed);
|
||||
let year = get_year_ganzhi(utc);
|
||||
let month = get_month_ganzhi(Box::new(utc), year.stem.num);
|
||||
let month = get_month_ganzhi(
|
||||
Box::new(utc),
|
||||
year.stem.num,
|
||||
);
|
||||
let day = get_day_ganzhi(Box::new(utc));
|
||||
let hour = get_hour_ganzhi(
|
||||
Box::new(
|
||||
naive_time_from_generic_datetime(fixed)
|
||||
naive_time_from_generic_datetime(
|
||||
fixed,
|
||||
),
|
||||
),
|
||||
day.stem.num
|
||||
day.stem.num,
|
||||
);
|
||||
|
||||
Bazi::new(year, month, day, hour)
|
||||
}
|
||||
|
||||
pub fn from_utc(utc: DateTime<Utc>, t: NaiveTime) -> Bazi<'a> {
|
||||
pub fn from_utc(
|
||||
utc: DateTime<Utc>,
|
||||
t: NaiveTime,
|
||||
) -> Bazi<'a> {
|
||||
let year = get_year_ganzhi(utc);
|
||||
let month = get_month_ganzhi(Box::new(utc), year.stem.num);
|
||||
let month = get_month_ganzhi(
|
||||
Box::new(utc),
|
||||
year.stem.num,
|
||||
);
|
||||
let day = get_day_ganzhi(Box::new(utc));
|
||||
let hour = get_hour_ganzhi(Box::new(t), day.stem.num);
|
||||
let hour = get_hour_ganzhi(
|
||||
Box::new(t),
|
||||
day.stem.num,
|
||||
);
|
||||
|
||||
Bazi::new(year, month, day, hour)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A static vector with 60 items. `Vec<usize, usize>` where the first
|
||||
/// `usize` being the `STEMS` index, and the second for the `BRANCHES`.
|
||||
/// It is simply the combination of 10 stems and 12 branches
|
||||
/// A static vector with 60 items. `Vec<usize, usize>`
|
||||
/// where the first `usize` being the `STEMS` index,
|
||||
/// and the second for the `BRANCHES`. It is simply
|
||||
/// the combination of 10 stems and 12 branches
|
||||
/// which eventually adds up to 60 patterns.
|
||||
pub static ref GANZHI_SEXAGESIMAL: Vec<(usize, usize)> = {
|
||||
let mut v = vec![];
|
||||
@@ -242,21 +270,23 @@ lazy_static! {
|
||||
v
|
||||
};
|
||||
|
||||
/// A static vector with 10 items, each represents 干 (Gan).
|
||||
/// Each stores associated attributes for the 干 (Gan).
|
||||
/// A static vector with 10 items, each represents
|
||||
/// 干 (Gan). Each stores associated attributes for
|
||||
/// the 干 (Gan).
|
||||
///
|
||||
/// [0] 甲 (Jia)
|
||||
/// [1] 乙 (Yi)
|
||||
/// [2] 丙 (Bing)
|
||||
/// [3] 丁 (Ding)
|
||||
/// [4] 戊 (Wu)
|
||||
/// [5] 己 (Ji)
|
||||
/// [6] 庚 (Geng)
|
||||
/// [7] 辛 (Xin)
|
||||
/// [8] 壬 (Ren)
|
||||
/// [9] 癸 (Gui)
|
||||
/// [0] 甲 (Jia)
|
||||
/// [1] 乙 (Yi)
|
||||
/// [2] 丙 (Bing)
|
||||
/// [3] 丁 (Ding)
|
||||
/// [4] 戊 (Wu)
|
||||
/// [5] 己 (Ji)
|
||||
/// [6] 庚 (Geng)
|
||||
/// [7] 辛 (Xin)
|
||||
/// [8] 壬 (Ren)
|
||||
/// [9] 癸 (Gui)
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// For attributes details stored in the vector is
|
||||
/// found in JSON file:
|
||||
/// `src/json/ganzhi_stems.json`
|
||||
pub static ref STEMS: Vec<Stem> = {
|
||||
let json = &include_str!("../json/ganzhi_stems.json");
|
||||
@@ -270,21 +300,22 @@ lazy_static! {
|
||||
}).collect()
|
||||
};
|
||||
|
||||
/// A static vector with 10 items, each represents 支 (Zhi).
|
||||
/// Each stores associated attributes for the 支 (Zhi).
|
||||
/// A static vector with 10 items, each represents 支
|
||||
/// (Zhi). Each stores associated attributes for the
|
||||
/// 支 (Zhi).
|
||||
///
|
||||
/// [0] 子 (Zi)
|
||||
/// [1] 丑 (Chou)
|
||||
/// [2] 寅 (Yin)
|
||||
/// [3] 卯 (Mao)
|
||||
/// [4] 辰 (Chen)
|
||||
/// [5] 巳 (Si)
|
||||
/// [6] 午 (Wu)
|
||||
/// [7] 未 (Wei)
|
||||
/// [8] 申 (Shen)
|
||||
/// [9] 酉 (You)
|
||||
/// [10] 戌 (Xu)
|
||||
/// [11] 亥 (Hai)
|
||||
/// [0] 子 (Zi)
|
||||
/// [1] 丑 (Chou)
|
||||
/// [2] 寅 (Yin)
|
||||
/// [3] 卯 (Mao)
|
||||
/// [4] 辰 (Chen)
|
||||
/// [5] 巳 (Si)
|
||||
/// [6] 午 (Wu)
|
||||
/// [7] 未 (Wei)
|
||||
/// [8] 申 (Shen)
|
||||
/// [9] 酉 (You)
|
||||
/// [10] 戌 (Xu)
|
||||
/// [11] 亥 (Hai)
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// `src/json/ganzhi_branches.json`
|
||||
@@ -301,31 +332,32 @@ lazy_static! {
|
||||
};
|
||||
|
||||
/// This is a table used when finding "Hour Stem".
|
||||
/// Columns represents "Day Stem" groups, and there are 5 groups.
|
||||
/// For insntace, if you have 甲 for "Day Stem",
|
||||
/// you are looking into the first column (group).
|
||||
/// Rows represents "Hour Branches" for which there are 12.
|
||||
/// For instance, if you have 子 for "Hour Branch",
|
||||
/// you are looking into the first row.
|
||||
/// So, when you have 甲 for "Day Stem",
|
||||
/// and 子 for "Hour Branch", "Hour Stem" is located
|
||||
/// in the first column in the first row, which is 甲.
|
||||
/// Columns represents "Day Stem" groups, and
|
||||
/// there are 5 groups. For insntace, if you have
|
||||
/// 甲 for "Day Stem", you are looking into the
|
||||
/// first column (group). Rows represents "Hour
|
||||
/// Branches" for which there are 12. For instance,
|
||||
/// if you have 子 for "Hour Branch", you are
|
||||
/// looking into the first row. So, when you have
|
||||
/// 甲 for "Day Stem", and 子 for "Hour Branch",
|
||||
/// "Hour Stem" is located in the first column in
|
||||
/// the first row, which is 甲.
|
||||
///
|
||||
/// 甲乙丙丁戊
|
||||
/// 己庚辛壬癸
|
||||
/// ‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
/// 子: 甲丙戊庚壬
|
||||
/// 丑: 乙丁己辛癸
|
||||
/// 寅: 丙戊庚壬甲
|
||||
/// 卯: 丁己辛癸乙
|
||||
/// 辰: 戊庚壬甲丙
|
||||
/// 巳: 己辛癸乙丁
|
||||
/// 午: 庚壬甲丙戊
|
||||
/// 未: 辛癸乙丁己
|
||||
/// 申: 壬甲丙戊庚
|
||||
/// 酉: 癸乙丁己辛
|
||||
/// 戌: 甲丙戊庚壬
|
||||
/// 亥: 乙丁己辛癸
|
||||
/// 甲乙丙丁戊
|
||||
/// 己庚辛壬癸
|
||||
/// ‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
/// 子: 甲丙戊庚壬
|
||||
/// 丑: 乙丁己辛癸
|
||||
/// 寅: 丙戊庚壬甲
|
||||
/// 卯: 丁己辛癸乙
|
||||
/// 辰: 戊庚壬甲丙
|
||||
/// 巳: 己辛癸乙丁
|
||||
/// 午: 庚壬甲丙戊
|
||||
/// 未: 辛癸乙丁己
|
||||
/// 申: 壬甲丙戊庚
|
||||
/// 酉: 癸乙丁己辛
|
||||
/// 戌: 甲丙戊庚壬
|
||||
/// 亥: 乙丁己辛癸
|
||||
pub static ref HOUR_STEM_TABLE: [[usize; 5]; 12] = [
|
||||
// 子
|
||||
[0, 2, 4, 6, 8], // 甲丙戊庚壬
|
||||
@@ -355,23 +387,24 @@ lazy_static! {
|
||||
}
|
||||
|
||||
/// Year Ganzhi
|
||||
fn get_year_ganzhi(utc: DateTime<Utc>) -> GanZhi<'static> {
|
||||
fn get_year_ganzhi(
|
||||
utc: DateTime<Utc>,
|
||||
) -> GanZhi<'static> {
|
||||
// Year Stem and Branch are easily found.
|
||||
// However, we must watch out if it is before
|
||||
// or after Lichun. The year begins from Lichun,
|
||||
// and it belongs to last year if the date
|
||||
// is before Lichun.
|
||||
|
||||
let lichun: NaiveDate = get_lichun(utc.year());
|
||||
|
||||
let year: i32 =
|
||||
if julian_day_from_generic_datetime(utc)
|
||||
< julian_day_from_generic_date(lichun)
|
||||
{
|
||||
utc.year() - 1
|
||||
} else {
|
||||
utc.year()
|
||||
};
|
||||
< julian_day_from_generic_date(lichun)
|
||||
{
|
||||
utc.year() - 1
|
||||
} else {
|
||||
utc.year()
|
||||
};
|
||||
|
||||
// Stem is found from the last digit of the year.
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
@@ -402,70 +435,86 @@ fn get_month_ganzhi(
|
||||
) -> GanZhi<'static> {
|
||||
let utc = *utc;
|
||||
|
||||
let lng: f64 = longitude_of_the_sun_from_generic_date(
|
||||
naive_date_from_generic_datetime(utc)
|
||||
);
|
||||
let lng: f64 =
|
||||
longitude_of_the_sun_from_generic_date(
|
||||
naive_date_from_generic_datetime(utc),
|
||||
);
|
||||
|
||||
// Branch is easily found by looking at the longitude of the sun.
|
||||
let branch_index: usize = if (315.0..345.0).contains(&lng) {
|
||||
0 // 立春 (lichun) + 雨水 (yushui) ---> 寅 (yin)
|
||||
} else if !(15.0..345.0).contains(&lng) {
|
||||
1 // 啓蟄 (jingzhe) + 春分 (chunfen) ---> 卯 (mao)
|
||||
} else if (15.0..45.0).contains(&lng) {
|
||||
2 // 清明 (qingming) + 穀雨 (guyu) ---> 辰 (chen)
|
||||
} else if (45.0..75.0).contains(&lng) {
|
||||
3 // 立夏 (lixia) + 小滿 (xiaoman) ---> 巳 (si)
|
||||
} else if (75.0..105.0).contains(&lng) {
|
||||
4 // 芒種 (mangzhong) + 夏至 (xiazhi) ---> 午 (wu)
|
||||
} else if (105.0..135.0).contains(&lng) {
|
||||
5 // 小暑 (xiaoshu) + 大暑 (dashu) ---> 未 (wei)
|
||||
} else if (135.0..165.0).contains(&lng) {
|
||||
6 // 立秋 (liqiu) + 處暑 (chushu) ---> 申 (shen)
|
||||
} else if (165.0..195.0).contains(&lng) {
|
||||
7 // 白露 (bailu) + 秋分 (qiufen) ---> 酉 (you)
|
||||
} else if (195.0..225.0).contains(&lng) {
|
||||
8 // 寒露 (hanlu) + 霜降 (shuangjiang) ---> 戌 (xu)
|
||||
} else if (225.0..255.0).contains(&lng) {
|
||||
9 // 立冬 (lidong) + 小雪 (xiaoxue) ---> 亥 (hai)
|
||||
} else if (255.0..285.0).contains(&lng) {
|
||||
10 // 大雪 (daxue) + 冬至 (dongzhi) ---> 子 (zi)
|
||||
} else {
|
||||
// lng >= 285.0 || lng < 315.0
|
||||
11 // 小寒 (xiaohan) + 大寒 (dahan) ---> 丑 (chou)
|
||||
};
|
||||
// Branch is easily found by looking at the
|
||||
// longitude of the sun.
|
||||
let branch_index: usize =
|
||||
if (315.0..345.0).contains(&lng) {
|
||||
0 // 立春 (lichun) + 雨水 (yushui) ---> 寅 (yin)
|
||||
} else if !(15.0..345.0).contains(&lng) {
|
||||
1 // 啓蟄 (jingzhe) + 春分 (chunfen) ---> 卯 (mao)
|
||||
} else if (15.0..45.0).contains(&lng) {
|
||||
2 // 清明 (qingming) + 穀雨 (guyu) ---> 辰 (chen)
|
||||
} else if (45.0..75.0).contains(&lng) {
|
||||
3 // 立夏 (lixia) + 小滿 (xiaoman) ---> 巳 (si)
|
||||
} else if (75.0..105.0).contains(&lng) {
|
||||
4 // 芒種 (mangzhong) + 夏至 (xiazhi) ---> 午 (wu)
|
||||
} else if (105.0..135.0).contains(&lng) {
|
||||
5 // 小暑 (xiaoshu) + 大暑 (dashu) ---> 未 (wei)
|
||||
} else if (135.0..165.0).contains(&lng) {
|
||||
6 // 立秋 (liqiu) + 處暑 (chushu) ---> 申 (shen)
|
||||
} else if (165.0..195.0).contains(&lng) {
|
||||
7 // 白露 (bailu) + 秋分 (qiufen) ---> 酉 (you)
|
||||
} else if (195.0..225.0).contains(&lng) {
|
||||
8 // 寒露 (hanlu) + 霜降 (shuangjiang) ---> 戌 (xu)
|
||||
} else if (225.0..255.0).contains(&lng) {
|
||||
9 // 立冬 (lidong) + 小雪 (xiaoxue) ---> 亥 (hai)
|
||||
} else if (255.0..285.0).contains(&lng) {
|
||||
10 // 大雪 (daxue) + 冬至 (dongzhi) ---> 子 (zi)
|
||||
} else {
|
||||
// lng >= 285.0 || lng < 315.0
|
||||
11 // 小寒 (xiaohan) + 大寒 (dahan) ---> 丑 (chou)
|
||||
};
|
||||
|
||||
// Stem is found using the Year Stem.
|
||||
// For a given year, you can find the first Month Stem.
|
||||
// Once you find the first Month Stem,
|
||||
// you simply count up to the current month.
|
||||
// This is done by adding 'branch_id' because 'branch_id'
|
||||
// is nothing but how many month from the beginning (Lichun).
|
||||
let stem_index: usize = if year_stem_num == 1 || year_stem_num == 6 {
|
||||
// Stem is found using the Year Stem. For a given
|
||||
// year, you can find the first Month Stem. Once
|
||||
// you find the first Month Stem, you simply count
|
||||
// up to the current month. This is done by adding
|
||||
// 'branch_id' because 'branch_id' is nothing but
|
||||
// how many month from the beginning (Lichun).
|
||||
let stem_index: usize = if year_stem_num == 1
|
||||
|| year_stem_num == 6
|
||||
{
|
||||
2 // 甲(jia:1) or 己(ji:6) ---> 丙(bing:3)
|
||||
} else if year_stem_num == 2 || year_stem_num == 7 {
|
||||
} else if year_stem_num == 2 || year_stem_num == 7
|
||||
{
|
||||
4 // 乙(yi:2) or 庚(geng:7) ---> 戊(wu:5)
|
||||
} else if year_stem_num == 3 || year_stem_num == 8 {
|
||||
} else if year_stem_num == 3 || year_stem_num == 8
|
||||
{
|
||||
6 // 丙(bing:3) or 辛(xin:8) ---> 庚(geng:7)
|
||||
} else if year_stem_num == 4 || year_stem_num == 9 {
|
||||
} else if year_stem_num == 4 || year_stem_num == 9
|
||||
{
|
||||
8 // 丁(ding:4) or 壬(ren:9) ---> 壬(ren:9)
|
||||
} else {
|
||||
0 // 戊(wu:5) or 癸(gui:10) ---> 甲(jia:1)
|
||||
};
|
||||
|
||||
GanZhi {
|
||||
stem: &STEMS[(stem_index + branch_index) % 10],
|
||||
stem: &STEMS
|
||||
[(stem_index + branch_index) % 10],
|
||||
branch: &BRANCHES[(branch_index + 2) % 12],
|
||||
}
|
||||
}
|
||||
|
||||
/// Day Ganzhi
|
||||
#[allow(clippy::boxed_local)]
|
||||
fn get_day_ganzhi(utc: Box<DateTime<Utc>>) -> GanZhi<'static> {
|
||||
fn get_day_ganzhi(
|
||||
utc: Box<DateTime<Utc>>,
|
||||
) -> GanZhi<'static> {
|
||||
let utc = *utc;
|
||||
let mjd: f64 = modified_julian_day_from_generic_datetime(utc);
|
||||
let index = ((mjd - 10.0) % 60.0).floor() as usize;
|
||||
let mjd: f64 =
|
||||
modified_julian_day_from_generic_datetime(
|
||||
utc,
|
||||
);
|
||||
let index =
|
||||
((mjd - 10.0) % 60.0).floor() as usize;
|
||||
|
||||
let (stem_id, branch_id) = GANZHI_SEXAGESIMAL[index];
|
||||
let (stem_id, branch_id) =
|
||||
GANZHI_SEXAGESIMAL[index];
|
||||
|
||||
GanZhi {
|
||||
stem: &STEMS[stem_id],
|
||||
@@ -475,38 +524,45 @@ fn get_day_ganzhi(utc: Box<DateTime<Utc>>) -> GanZhi<'static> {
|
||||
|
||||
/// Hour Ganzhi
|
||||
#[allow(clippy::boxed_local)]
|
||||
fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
|
||||
// The branch is easily found by looking at the hour range of the day.
|
||||
let branch_id: usize = if t.hour() == 23 || t.hour() == 0 {
|
||||
0
|
||||
} else if t.hour() < 3 {
|
||||
1
|
||||
} else if t.hour() <= 4 {
|
||||
2
|
||||
} else if t.hour() <= 6 {
|
||||
3
|
||||
} else if t.hour() <= 8 {
|
||||
4
|
||||
} else if t.hour() <= 10 {
|
||||
5
|
||||
} else if t.hour() <= 12 {
|
||||
6
|
||||
} else if t.hour() <= 14 {
|
||||
7
|
||||
} else if t.hour() <= 16 {
|
||||
8
|
||||
} else if t.hour() <= 18 {
|
||||
9
|
||||
} else if t.hour() <= 20 {
|
||||
10
|
||||
} else {
|
||||
11 // if t.hour() <= 22
|
||||
};
|
||||
fn get_hour_ganzhi(
|
||||
t: Box<NaiveTime>,
|
||||
day_stem_num: u8,
|
||||
) -> GanZhi<'static> {
|
||||
// The branch is easily found by looking at the
|
||||
// hour range of the day.
|
||||
let branch_id: usize =
|
||||
if t.hour() == 23 || t.hour() == 0 {
|
||||
0
|
||||
} else if t.hour() < 3 {
|
||||
1
|
||||
} else if t.hour() <= 4 {
|
||||
2
|
||||
} else if t.hour() <= 6 {
|
||||
3
|
||||
} else if t.hour() <= 8 {
|
||||
4
|
||||
} else if t.hour() <= 10 {
|
||||
5
|
||||
} else if t.hour() <= 12 {
|
||||
6
|
||||
} else if t.hour() <= 14 {
|
||||
7
|
||||
} else if t.hour() <= 16 {
|
||||
8
|
||||
} else if t.hour() <= 18 {
|
||||
9
|
||||
} else if t.hour() <= 20 {
|
||||
10
|
||||
} else {
|
||||
11 // if t.hour() <= 22
|
||||
};
|
||||
|
||||
// The stem is found by looking at a special table.
|
||||
// Read comments for 'HOUR_STEM_TABLE' for details.
|
||||
|
||||
let group_id: usize = if day_stem_num == 1 || day_stem_num == 6 {
|
||||
// The stem is found by looking at a special
|
||||
// table. Read comments for 'HOUR_STEM_TABLE' for
|
||||
// details.
|
||||
let group_id: usize = if day_stem_num == 1
|
||||
|| day_stem_num == 6
|
||||
{
|
||||
0
|
||||
} else if day_stem_num == 2 || day_stem_num == 7 {
|
||||
1
|
||||
@@ -518,7 +574,8 @@ fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
|
||||
4 // day_stem_num == 5 || day_stem_num == 10
|
||||
};
|
||||
|
||||
let stem_id: usize = HOUR_STEM_TABLE[branch_id][group_id];
|
||||
let stem_id: usize =
|
||||
HOUR_STEM_TABLE[branch_id][group_id];
|
||||
|
||||
GanZhi {
|
||||
stem: &STEMS[stem_id],
|
||||
@@ -529,10 +586,7 @@ fn get_hour_ganzhi(t: Box<NaiveTime>, day_stem_num: u8) -> GanZhi<'static> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sowngwala::time::{
|
||||
build_fixed,
|
||||
build_utc,
|
||||
};
|
||||
use sowngwala::time::{build_fixed, build_utc};
|
||||
|
||||
// TODO: GANZHI_SEXAGESIMAL
|
||||
|
||||
@@ -555,7 +609,8 @@ mod tests {
|
||||
|
||||
let fixed: DateTime<FixedOffset> =
|
||||
build_fixed(
|
||||
2021, 7, 6, 14, 57, 17, nanosecond, zone,
|
||||
2021, 7, 6, 14, 57, 17, nanosecond,
|
||||
zone,
|
||||
);
|
||||
|
||||
let bazi: Bazi = Bazi::from_fixed(fixed);
|
||||
@@ -566,10 +621,26 @@ mod tests {
|
||||
let hour: GanZhi = bazi.hour;
|
||||
|
||||
println!("fixed: {:?}", fixed);
|
||||
println!("年: {} ({})", year.alphabet(), year.alphabet_ja());
|
||||
println!("月: {} ({})", month.alphabet(), month.alphabet_ja());
|
||||
println!("日: {} ({})", day.alphabet(), day.alphabet_ja());
|
||||
println!("時: {} ({})", hour.alphabet(), hour.alphabet_ja());
|
||||
println!(
|
||||
"年: {} ({})",
|
||||
year.alphabet(),
|
||||
year.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"月: {} ({})",
|
||||
month.alphabet(),
|
||||
month.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"日: {} ({})",
|
||||
day.alphabet(),
|
||||
day.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"時: {} ({})",
|
||||
hour.alphabet(),
|
||||
hour.alphabet_ja()
|
||||
);
|
||||
|
||||
assert_eq!(year.alphabet(), "辛丑");
|
||||
assert_eq!(month.alphabet(), "甲午");
|
||||
@@ -581,13 +652,13 @@ mod tests {
|
||||
fn test_bazi_from_utc() {
|
||||
let nanosecond: u32 = 275_570_000;
|
||||
let utc: DateTime<Utc> = build_utc(
|
||||
2021, 7, 6, 5, 54, 34, nanosecond
|
||||
2021, 7, 6, 5, 54, 34, nanosecond,
|
||||
);
|
||||
|
||||
// Local Time
|
||||
let nanosecond: u32 = 137_790_000;
|
||||
let t = NaiveTime::from_hms_nano(
|
||||
14, 57, 17, nanosecond
|
||||
14, 57, 17, nanosecond,
|
||||
);
|
||||
|
||||
let bazi: Bazi = Bazi::from_utc(utc, t);
|
||||
@@ -600,10 +671,26 @@ mod tests {
|
||||
println!("utc: {:?}", utc);
|
||||
println!("t: {:?}", t);
|
||||
|
||||
println!("年: {} ({})", year.alphabet(), year.alphabet_ja());
|
||||
println!("月: {} ({})", month.alphabet(), month.alphabet_ja());
|
||||
println!("日: {} ({})", day.alphabet(), day.alphabet_ja());
|
||||
println!("時: {} ({})", hour.alphabet(), hour.alphabet_ja());
|
||||
println!(
|
||||
"年: {} ({})",
|
||||
year.alphabet(),
|
||||
year.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"月: {} ({})",
|
||||
month.alphabet(),
|
||||
month.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"日: {} ({})",
|
||||
day.alphabet(),
|
||||
day.alphabet_ja()
|
||||
);
|
||||
println!(
|
||||
"時: {} ({})",
|
||||
hour.alphabet(),
|
||||
hour.alphabet_ja()
|
||||
);
|
||||
|
||||
assert_eq!(year.alphabet(), "辛丑");
|
||||
assert_eq!(month.alphabet(), "甲午");
|
||||
|
||||
591
src/jiuxing.rs
591
src/jiuxing.rs
@@ -4,47 +4,53 @@
|
||||
//! The box in the middle represents where you are,
|
||||
//! and 8 boxes which surrounding the middle represent
|
||||
//! 8 compass directions. For these 9 boxes, plotted
|
||||
//! special symbols, each of which is called, a "Star" (星).
|
||||
//! When we say 九星 (Jiu-Xing) in Chinese, "Jiu" means "9",
|
||||
//! and "Xing" means a "Star". While 九星 (Jiu-Xing)
|
||||
//! has fixed positions (associated with 洛書 (Lo-Shu)),
|
||||
//! they change positions over time, and this movement
|
||||
//! is called 飞泊 (Fei-Po) or "flying" because of how it
|
||||
//! appears to our eyes when they move.
|
||||
//! special symbols, each of which is called, a "Star"
|
||||
//! (星). When we say 九星 (Jiu-Xing) in Chinese, "Jiu"
|
||||
//! means "9", and "Xing" means a "Star". While 九星
|
||||
//! (Jiu-Xing) has fixed positions (associated with
|
||||
//! 洛書 (Lo-Shu)), they change positions over time,
|
||||
//! and this movement is called 飞泊 (Fei-Po) or
|
||||
//! "flying" because of how it appears to our eyes when
|
||||
//! they move.
|
||||
//!
|
||||
//! As explained in 八卦 (Ba-Gua) (see: `src/bagua.rs`),
|
||||
//! there are 2 worldly systems concerned, namely,
|
||||
//! 先天八卦 (or "the Primordial Heaven") and
|
||||
//! 後天八卦 (or "the Manifested Heaven"), and we deal
|
||||
//! with the latter system when we talk about 風水 (Feng-Shui).
|
||||
//! with the latter system when we talk about 風水
|
||||
//! (Feng-Shui).
|
||||
//!
|
||||
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui), there is
|
||||
//! a special name given to the latter system, and is called,
|
||||
//! 地盤 (Di-Pan). "Di" means "earth", and "Pan" means "board".
|
||||
//! So, it is basically a board which is drawn at the bottom
|
||||
//! of any Feng-Shui charts. On 地盤 (Di-Pan), 九星 (Jiu-Xing)
|
||||
//! are plotted for which the order is fundamentally that of
|
||||
//! 洛書 (Lo-Shu) order in 八卦 (Ba-Gua). However, they move
|
||||
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
|
||||
//! there is a special name given to the latter system,
|
||||
//! and is called, 地盤 (Di-Pan). "Di" means "earth",
|
||||
//! and "Pan" means "board". So, it is basically a board
|
||||
//! which is drawn at the bottom of any Feng-Shui charts.
|
||||
//! On 地盤 (Di-Pan), 九星 (Jiu-Xing) are plotted for
|
||||
//! which the order is fundamentally that of 洛書
|
||||
//! (Lo-Shu) order in 八卦 (Ba-Gua). However, they move
|
||||
//! (or "fly") over 地盤 (Di-Pan) as time goes.
|
||||
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui), there are
|
||||
//! 3 other boards that are drawn on top of 地盤 (Di-Pan), namely:
|
||||
//!
|
||||
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
|
||||
//! there are 3 other boards that are drawn on top of
|
||||
//! 地盤 (Di-Pan), namely:
|
||||
//!
|
||||
//! - 運盤 (Un-Pan) or 天盤 (Tien-Pan)
|
||||
//! - 山星 (Shan-Xing)
|
||||
//! - 向星 (Xiang-Xing)
|
||||
//!
|
||||
//! For 運盤 (Un-Pan), positions of 九星 (Jiu-Xing) are determined
|
||||
//! by construction year for the building in concern which is
|
||||
//! calculated based on 三元九運 (Sang-Yuan Jiu-Yun),
|
||||
//! or "9 Yearly Cycles". We could say that 運盤 (Un-Pan)
|
||||
//! essentially describes the temporal aspect.
|
||||
//! 山星 (Shan-Xing) and 向星 (Xiang-Xing) are determined
|
||||
//! by spatial aspects of the building (however, in actual
|
||||
//! calculations, some temporal aspects comes in).
|
||||
//! For 運盤 (Un-Pan), positions of 九星 (Jiu-Xing) are
|
||||
//! determined by construction year for the building in
|
||||
//! concern which is calculated based on 三元九運
|
||||
//! (Sang-Yuan Jiu-Yun), or "9 Yearly Cycles". We could
|
||||
//! say that 運盤 (Un-Pan) essentially describes the
|
||||
//! temporal aspect. 山星 (Shan-Xing) and 向星
|
||||
//! (Xiang-Xing) are determined by spatial aspects of
|
||||
//! the building (however, in actual calculations, some
|
||||
//! temporal aspects comes in).
|
||||
//!
|
||||
//! When these 3 extra boards are placed on top of 地盤 (Di-Pan),
|
||||
//! the whole thing is called, 下卦図 (Xia-Gua-Tu), or simply
|
||||
//! referred as 飞星図 (Fei-Xing-Tu), or "The Flying Star Chart".
|
||||
//! When these 3 extra boards are placed on top of 地盤
|
||||
//! (Di-Pan), the whole thing is called, 下卦図
|
||||
//! (Xia-Gua-Tu), or simply referred as 飞星図
|
||||
//! (Fei-Xing-Tu), or "The Flying Star Chart".
|
||||
//!
|
||||
//! Jiu-Xing (九星):
|
||||
//!
|
||||
@@ -58,30 +64,24 @@
|
||||
//! [7] 八白土星 (8 White)
|
||||
//! [8] 九紫火星 (9 Purple)
|
||||
|
||||
use chrono::naive::NaiveDate;
|
||||
use chrono::Datelike;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sowngwala::time::julian_day_from_generic_date;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use chrono::Datelike;
|
||||
use chrono::naive::NaiveDate;
|
||||
use sowngwala::time::julian_day_from_generic_date;
|
||||
|
||||
use crate::compass::{
|
||||
get_opposite_direction,
|
||||
DIRECTIONS,
|
||||
get_opposite_direction, DIRECTIONS,
|
||||
DIRECTION_POSITIONS_IN_CHART,
|
||||
};
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
use crate::planet::{Planet, PLANETS};
|
||||
use crate::utils::{get_json, make_positive};
|
||||
use crate::wuxing::{WuXing, WU_XING};
|
||||
use crate::utils::{
|
||||
get_json,
|
||||
make_positive,
|
||||
};
|
||||
|
||||
pub const SAN_YUAN_JIU_YUN_START_YEAR: u16 = 1864;
|
||||
|
||||
@@ -96,7 +96,8 @@ pub struct JiuXing {
|
||||
pub planet: Planet,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining a static const `JIU_XING`.
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a static const `JIU_XING`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct JiuXingRawData {
|
||||
pub num: u8,
|
||||
@@ -119,10 +120,12 @@ impl NameDataTrait for JiuXingRawData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
|
||||
#[derive(
|
||||
Debug, Clone, Serialize, Deserialize, Copy,
|
||||
)]
|
||||
pub enum XiaGuaTuKind {
|
||||
UnPanXing, // 運盤
|
||||
ShanXing, // 山星
|
||||
ShanXing, // 山星
|
||||
XiangXing, // 向星
|
||||
}
|
||||
|
||||
@@ -137,19 +140,21 @@ pub struct XiaGuaTu<'a> {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A static vector with 9 items, each represents 九星 (Jiu-Xing).
|
||||
/// A static vector with 9 items, each represents
|
||||
/// 九星 (Jiu-Xing).
|
||||
///
|
||||
/// [0] 一白水星 (1 White)
|
||||
/// [1] 二黒土星 (2 Black)
|
||||
/// [2] 三碧木星 (3 Jade)
|
||||
/// [3] 四緑木星 (4 Green)
|
||||
/// [4] 五黄土星 (5 Yellow)
|
||||
/// [5] 六白金星 (6 White)
|
||||
/// [6] 七赤金星 (7 Red)
|
||||
/// [7] 八白土星 (8 White)
|
||||
/// [8] 九紫火星 (9 Purple)
|
||||
/// [0] 一白水星 (1 White)
|
||||
/// [1] 二黒土星 (2 Black)
|
||||
/// [2] 三碧木星 (3 Jade)
|
||||
/// [3] 四緑木星 (4 Green)
|
||||
/// [4] 五黄土星 (5 Yellow)
|
||||
/// [5] 六白金星 (6 White)
|
||||
/// [6] 七赤金星 (7 Red)
|
||||
/// [7] 八白土星 (8 White)
|
||||
/// [8] 九紫火星 (9 Purple)
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// For attributes details stored in the vector is
|
||||
/// found in JSON file:
|
||||
/// `src/json/jiuxing.json`
|
||||
pub static ref JIU_XING: [JiuXing; 9] = {
|
||||
let json = &include_str!("../json/jiuxing.json");
|
||||
@@ -184,22 +189,28 @@ lazy_static! {
|
||||
/// JsValue::from_serde(dir).unwrap()
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_jiuxing_from_index(index: usize) -> &'static JiuXing {
|
||||
pub fn get_jiuxing_from_index(
|
||||
index: usize,
|
||||
) -> &'static JiuXing {
|
||||
&JIU_XING[index]
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DIRECTION_TO_JIU_XING: HashMap<&'static str, usize> = JIU_XING
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, jiuxing)| {
|
||||
let dir = jiuxing.direction.as_str();
|
||||
match dir {
|
||||
"" => ("", index),
|
||||
_ => (jiuxing.direction.as_str(), index),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
pub static ref DIRECTION_TO_JIU_XING: HashMap<&'static str, usize> =
|
||||
JIU_XING
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, jiuxing)| {
|
||||
let dir = jiuxing.direction.as_str();
|
||||
match dir {
|
||||
"" => ("", index),
|
||||
_ => (
|
||||
jiuxing.direction.as_str(),
|
||||
index,
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
fn jiuxing_index_from_direction(dir: &str) -> usize {
|
||||
@@ -210,58 +221,60 @@ fn jiuxing_index_from_direction(dir: &str) -> usize {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Although 洛書 (Lo-Shu) order is fixed, when 地盤 (Di-Pan)
|
||||
/// is drawn on a device screen, the mapping for
|
||||
/// 九星 (Jiu-Xing) changes as the device rotates.
|
||||
/// For example, 一白水星 (1 White) usually comes to the top
|
||||
/// of the board when a device is pointing north. However,
|
||||
/// when pointing north east, 一白水星 (1 White) moves
|
||||
/// to the top left (which is north west).
|
||||
/// For 8 compass directions, this constant provides
|
||||
/// a mapping for the 洛書 (Lo-Shu) order.
|
||||
/// For "n", 一白水星 (1 White) is the 2nd in the array.
|
||||
/// For "ne", 一白水星 (1 White) is the 1st in the array.
|
||||
/// Although 洛書 (Lo-Shu) order is fixed, when
|
||||
/// 地盤 (Di-Pan) is drawn on a device screen,
|
||||
/// the mapping for 九星 (Jiu-Xing) changes as
|
||||
/// the device rotates.
|
||||
/// For example, 一白水星 (1 White) usually comes
|
||||
/// to the top of the board when a device is
|
||||
/// pointing north. However, when pointing north
|
||||
/// east, 一白水星 (1 White) moves to the top left
|
||||
/// (which is north west). For 8 compass directions,
|
||||
/// this constant provides a mapping for the 洛書
|
||||
/// (Lo-Shu) order. For "n", 一白水星 (1 White) is
|
||||
/// the 2nd in the array. For "ne", 一白水星
|
||||
/// (1 White) is the 1st in the array.
|
||||
///
|
||||
/// It would look like this:
|
||||
///
|
||||
/// [5] 六白 [0] 一白 [7] 八白
|
||||
/// [6] 七赤 [4] 五黄 [2] 三碧
|
||||
/// [1] 二黒 [8] 九紫 [3] 四緑
|
||||
/// [5] 六白 [0] 一白 [7] 八白
|
||||
/// [6] 七赤 [4] 五黄 [2] 三碧
|
||||
/// [1] 二黒 [8] 九紫 [3] 四緑
|
||||
/// n: [5, 0, 7, 6, 4, 2, 1, 8, 3]
|
||||
///
|
||||
/// [0] 一白 [7] 八白 [2] 三碧
|
||||
/// [5] 六白 [4] 五黄 [3] 四緑
|
||||
/// [6] 七赤 [1] 二黒 [8] 九紫
|
||||
/// [0] 一白 [7] 八白 [2] 三碧
|
||||
/// [5] 六白 [4] 五黄 [3] 四緑
|
||||
/// [6] 七赤 [1] 二黒 [8] 九紫
|
||||
/// ne: [0, 7, 2, 5, 4, 3, 6, 1, 8]
|
||||
///
|
||||
/// [7] 八白 [2] 三碧 [3] 四緑
|
||||
/// [0] 一白 [4] 五黄 [8] 九紫
|
||||
/// [5] 六白 [6] 七赤 [1] 二黒
|
||||
/// [7] 八白 [2] 三碧 [3] 四緑
|
||||
/// [0] 一白 [4] 五黄 [8] 九紫
|
||||
/// [5] 六白 [6] 七赤 [1] 二黒
|
||||
/// e: [7, 2, 3, 0, 4, 8, 5, 6, 1]
|
||||
///
|
||||
/// [2] 三碧 [3] 四緑 [8] 九紫
|
||||
/// [7] 八白 [4] 五黄 [1] 二黒
|
||||
/// [0] 一白 [5] 六白 [6] 七赤
|
||||
/// [2] 三碧 [3] 四緑 [8] 九紫
|
||||
/// [7] 八白 [4] 五黄 [1] 二黒
|
||||
/// [0] 一白 [5] 六白 [6] 七赤
|
||||
/// se: [2, 3, 8, 7, 4, 1, 0, 5, 6]
|
||||
///
|
||||
/// [3] 四緑 [8] 九紫 [1] 二黒
|
||||
/// [2] 三碧 [4] 五黄 [6] 七赤
|
||||
/// [7] 八白 [0] 一白 [5] 六白
|
||||
/// [3] 四緑 [8] 九紫 [1] 二黒
|
||||
/// [2] 三碧 [4] 五黄 [6] 七赤
|
||||
/// [7] 八白 [0] 一白 [5] 六白
|
||||
/// s: [3, 8, 1, 2, 4, 6, 7, 0, 5]
|
||||
///
|
||||
/// [8] 九紫 [1] 二黒 [6] 七赤
|
||||
/// [3] 四緑 [4] 五黄 [5] 六白
|
||||
/// [2] 三碧 [7] 八白 [0] 一白
|
||||
/// [8] 九紫 [1] 二黒 [6] 七赤
|
||||
/// [3] 四緑 [4] 五黄 [5] 六白
|
||||
/// [2] 三碧 [7] 八白 [0] 一白
|
||||
/// sw: [8, 1, 6, 3, 4, 5, 2, 7, 0]
|
||||
///
|
||||
/// [1] 二黒 [6] 七赤 [5] 六白
|
||||
/// [8] 九紫 [4] 五黄 [0] 一白
|
||||
/// [3] 四緑 [2] 三碧 [7] 八白
|
||||
/// [1] 二黒 [6] 七赤 [5] 六白
|
||||
/// [8] 九紫 [4] 五黄 [0] 一白
|
||||
/// [3] 四緑 [2] 三碧 [7] 八白
|
||||
/// w: [1, 6, 5, 8, 4, 0, 3, 2, 7]
|
||||
///
|
||||
/// [6] 七赤 [5] 六白 [0] 一白
|
||||
/// [1] 二黒 [4] 五黄 [7] 八白
|
||||
/// [8] 九紫 [3] 四緑 [2] 三碧
|
||||
/// [6] 七赤 [5] 六白 [0] 一白
|
||||
/// [1] 二黒 [4] 五黄 [7] 八白
|
||||
/// [8] 九紫 [3] 四緑 [2] 三碧
|
||||
/// nw: [6, 5, 0, 1, 4, 7, 8, 3, 2]
|
||||
pub static ref JIU_XING_DI_PAN_POSITIONS: HashMap<&'static str, [usize; 9]> = DIRECTIONS
|
||||
.iter()
|
||||
@@ -281,7 +294,9 @@ lazy_static! {
|
||||
}
|
||||
|
||||
/// A getter for `JIU_XING_DI_PAN_POSITIONS`.
|
||||
pub fn get_jiuxing_dipan_positions_from_direction(direction: &str) -> Option<&[usize; 9]> {
|
||||
pub fn get_jiuxing_dipan_positions_from_direction(
|
||||
direction: &str,
|
||||
) -> Option<&[usize; 9]> {
|
||||
JIU_XING_DI_PAN_POSITIONS.get(direction)
|
||||
}
|
||||
|
||||
@@ -318,8 +333,10 @@ lazy_static! {
|
||||
*/
|
||||
}
|
||||
|
||||
/// Given incorrect value for Jiu-Xing index, applies a modulo
|
||||
/// to normalize it to fit within the range of 0 to 8.
|
||||
/// Given incorrect value for Jiu-Xing index, applies
|
||||
/// a modulo to normalize it to fit within the range
|
||||
/// of 0 to 8.
|
||||
///
|
||||
/// Ex.
|
||||
/// 0 -> 0 ... Stays the same. "0" being 一白水星 (1 White).
|
||||
/// 8 -> 8 ... Stays the same. "8" being 九紫火星 (9 Purple).
|
||||
@@ -335,16 +352,18 @@ pub fn normalize_jiuxing(index: i32) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sang-Yuan 三元九運 (Jiu-Yun), or _"9 YEARLY CYCLES"_, is the core
|
||||
/// concept in 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
|
||||
/// and it tells how 九星 (Jiu-Xing) fly throughout 180 years.
|
||||
/// Sang-Yuan 三元九運 (Jiu-Yun), or _"9 YEARLY
|
||||
/// CYCLES"_, is the core concept in 玄空飞星風水
|
||||
/// (Xuan-Kong Fei-Xing Feng-Shui), and it tells how
|
||||
/// 九星 (Jiu-Xing) fly throughout 180 years.
|
||||
/// This function will calculate from the given:
|
||||
///
|
||||
/// 1. CURRENT LOCALTIME, and
|
||||
/// 2. LIU-CHUN (for the year)
|
||||
///
|
||||
/// for the corresponding Jiu-Xing, for which the generated board
|
||||
/// is usually referred as 運盤 (Un-Pan).
|
||||
/// for the corresponding Jiu-Xing, for which
|
||||
/// the generated board is usually referred as
|
||||
/// 運盤 (Un-Pan).
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -362,16 +381,21 @@ pub fn normalize_jiuxing(index: i32) -> usize {
|
||||
/// let index: usize = unpan_xing_index(current, lichun);
|
||||
/// JsValue::from_f64(index as f64)
|
||||
/// }
|
||||
pub fn unpan_xing_index(current: NaiveDate, lichun: NaiveDate) -> usize {
|
||||
let year: i32 = if (
|
||||
julian_day_from_generic_date(current)
|
||||
- julian_day_from_generic_date(lichun)
|
||||
) < 0_f64 {
|
||||
current.year() - 1
|
||||
} else {
|
||||
current.year()
|
||||
};
|
||||
let dt: i32 = year - SAN_YUAN_JIU_YUN_START_YEAR as i32;
|
||||
pub fn unpan_xing_index(
|
||||
current: NaiveDate,
|
||||
lichun: NaiveDate,
|
||||
) -> usize {
|
||||
let year: i32 =
|
||||
if (julian_day_from_generic_date(current)
|
||||
- julian_day_from_generic_date(lichun))
|
||||
< 0_f64
|
||||
{
|
||||
current.year() - 1
|
||||
} else {
|
||||
current.year()
|
||||
};
|
||||
let dt: i32 =
|
||||
year - SAN_YUAN_JIU_YUN_START_YEAR as i32;
|
||||
let norm: i32 = dt % 180;
|
||||
(norm / 20) as usize
|
||||
}
|
||||
@@ -386,15 +410,20 @@ pub fn unpan_xing_index(current: NaiveDate, lichun: NaiveDate) -> usize {
|
||||
/// the second argument `order` in array) of
|
||||
/// 九星 (Jiu-Xing) indexes, increments or decrements
|
||||
/// each in the array, and simply return the array.
|
||||
/// Depending on whichever currently resides in the center of
|
||||
/// the board (which is the first argument `center`),
|
||||
/// the value to increment or decrement changes.
|
||||
/// For `order` is fundamentally that of the Lo-Shu order
|
||||
/// (which is defined in `JIU_XING_DI_PAN_POSITIONS`),
|
||||
/// however, the layout is always different since
|
||||
/// the position changes depending on which direction
|
||||
/// the device is pointing as the device rotates.
|
||||
pub fn fly_flying_stars(center: usize, order: &[usize; 9], reverse: bool) -> [usize; 9] {
|
||||
/// Depending on whichever currently resides in the
|
||||
/// center of the board (which is the first argument
|
||||
/// `center`), the value to increment or decrement
|
||||
/// changes. For `order` is fundamentally that of the
|
||||
/// Lo-Shu order (which is defined in
|
||||
/// `JIU_XING_DI_PAN_POSITIONS`), however, the layout
|
||||
/// is always different since the position changes
|
||||
/// depending on which direction the device is
|
||||
/// pointing as the device rotates.
|
||||
pub fn fly_flying_stars(
|
||||
center: usize,
|
||||
order: &[usize; 9],
|
||||
reverse: bool,
|
||||
) -> [usize; 9] {
|
||||
let diff: usize = center - 4;
|
||||
order
|
||||
.iter()
|
||||
@@ -420,38 +449,48 @@ pub fn fly_flying_stars(center: usize, order: &[usize; 9], reverse: bool) -> [us
|
||||
// }
|
||||
|
||||
/// This is a useful well known formula for finding out
|
||||
/// whether 山星 (Shan-Xing) or 向星 (Xiang-Xing) is flying
|
||||
/// in normal order.
|
||||
/// whether 山星 (Shan-Xing) or 向星 (Xiang-Xing) is
|
||||
/// flying in normal order.
|
||||
///
|
||||
/// IMPORTANT:
|
||||
/// It does not work when 九星 (Jiu-Xing) is "5". If such the case,
|
||||
/// center index for Un-Pan must be fed.
|
||||
fn is_shan_xiang_flying_normal(index: usize, sector: usize) -> bool {
|
||||
/// It does not work when 九星 (Jiu-Xing) is "5".
|
||||
/// If such the case, center index for Un-Pan must
|
||||
/// be fed.
|
||||
fn is_shan_xiang_flying_normal(
|
||||
index: usize,
|
||||
sector: usize,
|
||||
) -> bool {
|
||||
let num: usize = index + 1;
|
||||
let rem = num % 2;
|
||||
(rem != 0 && sector == 1) || (rem == 0 && sector > 1)
|
||||
(rem != 0 && sector == 1)
|
||||
|| (rem == 0 && sector > 1)
|
||||
}
|
||||
|
||||
/// Looking at the 地盤 (Di-Pan) order, finds the current direction facing.
|
||||
fn direction_from_dipan_order(order: &[usize; 9]) -> &'static str {
|
||||
/// Looking at the 地盤 (Di-Pan) order, finds the
|
||||
/// current direction facing.
|
||||
fn direction_from_dipan_order(
|
||||
order: &[usize; 9],
|
||||
) -> &'static str {
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.iter()
|
||||
.find_map(
|
||||
|(dir, dipan_order)| match order.iter().eq(dipan_order.iter()) {
|
||||
.find_map(|(dir, dipan_order)| {
|
||||
match order.iter().eq(dipan_order.iter())
|
||||
{
|
||||
true => Some(*dir),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
.unwrap_or("")
|
||||
}
|
||||
|
||||
/// Calculates for 下卦図 (Xia-Gua-Tu). 1st and 2nd
|
||||
/// arguments (`unpan_xing_center` and `unpan_xing_order`)
|
||||
/// are required for all. For calculating a chart
|
||||
/// for 運盤星 (Un-Pan Xing), that is all we need.
|
||||
/// However, to calculate charts for 山星 (Shan-Xing)
|
||||
/// and 向星 (Xiang-Xing), requires 3rd and 4th arguments
|
||||
/// (`xiang_xing_direction` and `xiang_xing_sector`.
|
||||
/// arguments (`unpan_xing_center` and
|
||||
/// `unpan_xing_order`) are required for all.
|
||||
/// For calculating a chart for 運盤星 (Un-Pan Xing),
|
||||
/// that is all we need. However, to calculate charts
|
||||
/// for 山星 (Shan-Xing) and 向星 (Xiang-Xing), requires
|
||||
/// 3rd and 4th arguments (`xiang_xing_direction` and
|
||||
/// `xiang_xing_sector`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -488,9 +527,10 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
|
||||
) -> HashMap<&'a str, XiaGuaTu<'a>> {
|
||||
let mut xgtu = HashMap::new();
|
||||
|
||||
// `chart` for 運盤星 (Un-Pan Xing) is straight forward.
|
||||
// The center 九星 (Jiu-Xing) is already given,
|
||||
// and you simply have to fly the given chart.
|
||||
// `chart` for 運盤星 (Un-Pan Xing) is straight
|
||||
// forward. The center 九星 (Jiu-Xing) is already
|
||||
// given, and you simply have to fly the given
|
||||
// chart.
|
||||
xgtu.insert(
|
||||
"unpan_xing",
|
||||
XiaGuaTu {
|
||||
@@ -498,36 +538,32 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
|
||||
center: Some(unpan_xing_center),
|
||||
direction: None,
|
||||
sector: None,
|
||||
chart: Some(
|
||||
fly_flying_stars(
|
||||
unpan_xing_center,
|
||||
unpan_xing_order,
|
||||
false
|
||||
)
|
||||
),
|
||||
chart: Some(fly_flying_stars(
|
||||
unpan_xing_center,
|
||||
unpan_xing_order,
|
||||
false,
|
||||
)),
|
||||
},
|
||||
);
|
||||
|
||||
// `chart` for 山星 (Shan-Xing) to be later calculated.
|
||||
// `direction` for 山星 (Shan-Xing) is just the opposite
|
||||
// of 向星 (Xiang-Xing).
|
||||
// `chart` for 山星 (Shan-Xing) to be later
|
||||
// calculated. `direction` for 山星 (Shan-Xing)
|
||||
// is just the opposite of 向星 (Xiang-Xing).
|
||||
xgtu.insert(
|
||||
"shan_xing",
|
||||
XiaGuaTu {
|
||||
kind: XiaGuaTuKind::ShanXing,
|
||||
center: None,
|
||||
direction: Some(
|
||||
get_opposite_direction(
|
||||
xiang_xing_direction
|
||||
)
|
||||
),
|
||||
direction: Some(get_opposite_direction(
|
||||
xiang_xing_direction,
|
||||
)),
|
||||
sector: Some(xiang_xing_sector),
|
||||
chart: None,
|
||||
},
|
||||
);
|
||||
|
||||
// `chart` for 向星 (Xiang-Xing) to be later calculated.
|
||||
// `direction` is already given.
|
||||
// `chart` for 向星 (Xiang-Xing) to be later
|
||||
// calculated. `direction` is already given.
|
||||
xgtu.insert(
|
||||
"xiang_xing",
|
||||
XiaGuaTu {
|
||||
@@ -541,48 +577,72 @@ pub fn get_xiaguatu_from_unpan_index<'a>(
|
||||
|
||||
// First, we need to find out which direction
|
||||
// the device is currently pointing to.
|
||||
let curr_dir: &str = direction_from_dipan_order(unpan_xing_order);
|
||||
let curr_dir: &str =
|
||||
direction_from_dipan_order(unpan_xing_order);
|
||||
|
||||
// Once the direction is found, then we will obtain the compass direction mapping.
|
||||
let compass_positions: [&str; 9] = DIRECTION_POSITIONS_IN_CHART[curr_dir];
|
||||
// Once the direction is found, then we will
|
||||
// obtain the compass direction mapping.
|
||||
let compass_positions: [&str; 9] =
|
||||
DIRECTION_POSITIONS_IN_CHART[curr_dir];
|
||||
|
||||
// Find `center` and `chart` for both 山星 (Shan-Xing) and 向星 (Xiang-Xing).
|
||||
// Find `center` and `chart` for both 山星
|
||||
// (Shan-Xing) and 向星 (Xiang-Xing).
|
||||
for key in ["shan_xing", "xiang_xing"] {
|
||||
// Since we only know directions for 山星 (Shan-Xing)
|
||||
// and 向星 (Xiang-Xing), we will look into the Un-Pan chart,
|
||||
// and will find out what 九星 (Jiu-Xing) we have for the direction.
|
||||
// Since we only know directions for 山星
|
||||
// (Shan-Xing) and 向星 (Xiang-Xing), we will
|
||||
// look into the Un-Pan chart, and will find
|
||||
// out what 九星 (Jiu-Xing) we have for the
|
||||
// direction.
|
||||
|
||||
// Initially, we only know the direction.
|
||||
let dir: &str = xgtu.get(key).unwrap().direction.unwrap();
|
||||
let dir: &str =
|
||||
xgtu.get(key).unwrap().direction.unwrap();
|
||||
|
||||
// For the direction, find out its array index.
|
||||
let pos: usize = compass_positions.iter().position(|&d| d == dir).unwrap();
|
||||
let pos: usize = compass_positions
|
||||
.iter()
|
||||
.position(|&d| d == dir)
|
||||
.unwrap();
|
||||
|
||||
// Once the index is found, then find out its 九星 (Jiu-Xing).
|
||||
let center: usize = (xgtu.get("unpan_xing").unwrap().chart.unwrap())[pos];
|
||||
// Once the index is found, then find out its
|
||||
// 九星 (Jiu-Xing).
|
||||
let center: usize = (xgtu
|
||||
.get("unpan_xing")
|
||||
.unwrap()
|
||||
.chart
|
||||
.unwrap())[pos];
|
||||
|
||||
let prev: &XiaGuaTu = xgtu.get(key).unwrap();
|
||||
|
||||
// It is important to figure out whether it is flying
|
||||
// in normal or reverse order. To do so, we will
|
||||
// use a useful well known formula.
|
||||
let normal: bool = is_shan_xiang_flying_normal(
|
||||
// Having 五黄土星 (5 Yellow) is a special case,
|
||||
// and the formula does not work. Therefore,
|
||||
// replacing it with 運盤星 (Un-Pan Xing) index.
|
||||
if center == 4 {
|
||||
xgtu.get("unpan_xing").unwrap().center.unwrap()
|
||||
} else {
|
||||
center
|
||||
},
|
||||
xgtu.get(key).unwrap().sector.unwrap(),
|
||||
);
|
||||
// It is important to figure out whether it
|
||||
// is flying in normal or reverse order.
|
||||
// To do so, we will use a useful well known
|
||||
// formula.
|
||||
let normal: bool =
|
||||
is_shan_xiang_flying_normal(
|
||||
// Having 五黄土星 (5 Yellow) is a
|
||||
// special case, and the formula does
|
||||
// not work. Therefore, replacing it
|
||||
// with 運盤星 (Un-Pan Xing) index.
|
||||
if center == 4 {
|
||||
xgtu.get("unpan_xing")
|
||||
.unwrap()
|
||||
.center
|
||||
.unwrap()
|
||||
} else {
|
||||
center
|
||||
},
|
||||
xgtu.get(key)
|
||||
.unwrap()
|
||||
.sector
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Now, calculate for the flying chart.
|
||||
let chart: [usize; 9] = fly_flying_stars(
|
||||
center,
|
||||
unpan_xing_order,
|
||||
normal
|
||||
normal,
|
||||
);
|
||||
|
||||
*xgtu.get_mut(key).unwrap() = XiaGuaTu {
|
||||
@@ -611,14 +671,18 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_constant_direction_to_jiuxing() {
|
||||
assert_eq!(*DIRECTION_TO_JIU_XING.get("n").unwrap(), 0);
|
||||
assert_eq!(
|
||||
*DIRECTION_TO_JIU_XING.get("n").unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: jiuxing_index_from_direction
|
||||
// TODO: JIU_XING_DI_PAN_POSITIONS
|
||||
|
||||
#[test]
|
||||
fn test_get_jiuxing_dipan_positions_from_direction() {
|
||||
fn test_get_jiuxing_dipan_positions_from_direction(
|
||||
) {
|
||||
let exp = [5, 0, 7, 6, 4, 2, 1, 8, 3];
|
||||
assert_eq!(
|
||||
get_jiuxing_dipan_positions_from_direction("n").unwrap(),
|
||||
@@ -635,12 +699,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn normalize_jiuxing_all() {
|
||||
let arr: [usize; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let exp: [usize; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1];
|
||||
let arr: [usize; 11] =
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let exp: [usize; 11] =
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1];
|
||||
|
||||
let res: [usize; 11] = arr
|
||||
.iter()
|
||||
.map(|index: &usize| normalize_jiuxing(*index as i32))
|
||||
.map(|index: &usize| {
|
||||
normalize_jiuxing(*index as i32)
|
||||
})
|
||||
.collect::<Vec<usize>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@@ -654,89 +722,146 @@ mod tests {
|
||||
// TODO: is_shan_xiang_flying_normal
|
||||
// TODO: get_xiaguatu_from_unpan_index
|
||||
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
// LO-SHU ORDER - Normal Order
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
|
||||
// Fly *NORMAL* for Lo-Shu Order: [4] 五黄土星 (5 Green)
|
||||
/// Fly *NORMAL* for Lo-Shu Order:
|
||||
/// [4] 五黄土星 (5 Green)
|
||||
#[test]
|
||||
fn fly_stars_normal_lo_shu_5_green() {
|
||||
let center: usize = 4; // [4] 五黄土星 (5 Green)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [5, 0, 7, 6, 4, 2, 1, 8, 3];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[5, 0, 7, 6, 4, 2, 1, 8, 3];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, false), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, false),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// Fly *NORMAL* for Lo-Shu Order: [5] 六白金星 (6 White)
|
||||
/// Fly *NORMAL* for Lo-Shu Order:
|
||||
/// [5] 六白金星 (6 White)
|
||||
#[test]
|
||||
fn fly_stars_normal_lo_shu_6_white() {
|
||||
let center: usize = 5; // [5] 六白金星 (6 White)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [6, 1, 8, 7, 5, 3, 2, 0, 4];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[6, 1, 8, 7, 5, 3, 2, 0, 4];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, false), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, false),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// Fly *NORMAL* for Lo-Shu Order: [6] 七赤金星 (7 Red)
|
||||
/// Fly *NORMAL* for Lo-Shu Order:
|
||||
/// [6] 七赤金星 (7 Red)
|
||||
#[test]
|
||||
fn fly_stars_normal_lo_shu_7_red() {
|
||||
let center: usize = 6; // [6] 七赤金星 (7 Red)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [7, 2, 0, 8, 6, 4, 3, 1, 5];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[7, 2, 0, 8, 6, 4, 3, 1, 5];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, false), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, false),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// Fly *NORMAL* for Lo-Shu Order: [7] 八白土星 (8 White)
|
||||
/// Fly *NORMAL* for Lo-Shu Order:
|
||||
/// [7] 八白土星 (8 White)
|
||||
#[test]
|
||||
fn fly_stars_normal_lo_shu_8_white() {
|
||||
let center: usize = 7; // [7] 八白土星 (8 White)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [8, 3, 1, 0, 7, 5, 4, 2, 6];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[8, 3, 1, 0, 7, 5, 4, 2, 6];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, false), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, false),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// Fly *NORMAL* for Lo-Shu Order: [8] 九紫火星 (9 Purple)
|
||||
/// Fly *NORMAL* for Lo-Shu Order:
|
||||
/// [8] 九紫火星 (9 Purple)
|
||||
#[test]
|
||||
fn fly_stars_normal_lo_shu_9_purple() {
|
||||
let center: usize = 8; // [8] 九紫火星 (9 Purple)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [0, 4, 2, 1, 8, 6, 5, 3, 7];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[0, 4, 2, 1, 8, 6, 5, 3, 7];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, false), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, false),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
// LO-SHU ORDER - Reverse Order
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
|
||||
// Fly *REVERSE* for Lo-Shu Order (North): [4] 五黄土星 (5 Green)
|
||||
/// Fly *REVERSE* for Lo-Shu Order (North):
|
||||
/// [4] 五黄土星 (5 Green)
|
||||
#[test]
|
||||
fn fly_stars_reverse_5_green_north() {
|
||||
let center: usize = 4; // [4] 五黄土星 (5 Green)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("n").unwrap();
|
||||
let exp: [usize; 9] = [3, 8, 1, 2, 4, 6, 7, 0, 5];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("n")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[3, 8, 1, 2, 4, 6, 7, 0, 5];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order,true), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, true),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// Fly *REVERSE* for Lo-Shu Order (North-East): [4] 五黄土星 (5 Green)
|
||||
/// Fly *REVERSE* for Lo-Shu Order (North-East):
|
||||
/// [4] 五黄土星 (5 Green)
|
||||
#[test]
|
||||
fn fly_stars_reverse_lo_shu_5_green_north_east() {
|
||||
let center: usize = 4; // [4] 五黄土星 (5 Green)
|
||||
let order: &[usize; 9] = JIU_XING_DI_PAN_POSITIONS.get("ne").unwrap();
|
||||
let exp: [usize; 9] = [8, 1, 6, 3, 4, 5, 2, 7, 0];
|
||||
let order: &[usize; 9] =
|
||||
JIU_XING_DI_PAN_POSITIONS
|
||||
.get("ne")
|
||||
.unwrap();
|
||||
let exp: [usize; 9] =
|
||||
[8, 1, 6, 3, 4, 5, 2, 7, 0];
|
||||
|
||||
assert_eq!(fly_flying_stars(center, order, true), exp);
|
||||
assert_eq!(
|
||||
fly_flying_stars(center, order, true),
|
||||
exp
|
||||
);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
// COMPASS CLOCKWISE - Normal Order
|
||||
// ===================================================================
|
||||
// ===============================================
|
||||
|
||||
// Fly *NORMAL* for COMPASS CLOCKWISE: [4] 五黄土星 (5 Yellow)
|
||||
// Fly *NORMAL* for COMPASS CLOCKWISE:
|
||||
// [4] 五黄土星 (5 Yellow)
|
||||
// #[test]
|
||||
// fn fly_stars_normal_lo_shu_5_yellow() {
|
||||
// let center: usize = 4; // [4] 五黄土星 (5 Yellow)
|
||||
|
||||
@@ -25,7 +25,10 @@ pub struct LanguageData {
|
||||
}
|
||||
|
||||
impl LanguageDetails {
|
||||
pub fn new(alphabet: &str, phonetic: &str) -> Self {
|
||||
pub fn new(
|
||||
alphabet: &str,
|
||||
phonetic: &str,
|
||||
) -> Self {
|
||||
LanguageDetails {
|
||||
alphabet: alphabet.to_string(),
|
||||
phonetic: phonetic.to_string(),
|
||||
@@ -55,11 +58,16 @@ pub trait LanguageTrait {
|
||||
pub trait NameDataTrait {
|
||||
fn name(&self) -> Box<LanguageData>;
|
||||
|
||||
fn language_details(details: &[String]) -> LanguageDetails {
|
||||
fn language_details(
|
||||
details: &[String],
|
||||
) -> LanguageDetails {
|
||||
if details.is_empty() {
|
||||
LanguageDetails::new("", "")
|
||||
} else {
|
||||
LanguageDetails::new(&details[0], &details[1])
|
||||
LanguageDetails::new(
|
||||
&details[0],
|
||||
&details[1],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +77,12 @@ pub trait NameDataTrait {
|
||||
en: self.name().en,
|
||||
ja: Self::language_details(&name.ja),
|
||||
vi: Self::language_details(&name.vi),
|
||||
zh_cn: Self::language_details(&name.zh_cn),
|
||||
zh_tw: Self::language_details(&name.zh_tw),
|
||||
zh_cn: Self::language_details(
|
||||
&name.zh_cn,
|
||||
),
|
||||
zh_tw: Self::language_details(
|
||||
&name.zh_tw,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
//! Information about planets in our solar system.
|
||||
//! Notice the planets in `PLANETS` are stored in a special order
|
||||
//! known as _the Ptolemaic Order_. In many ancient traditions,
|
||||
//! when a man is deceased, he will depart the Earth,
|
||||
//! and head toward the Moon. Leaving the Moon behind,
|
||||
//! the Mercury, the Venus, and the Sun. He will continue
|
||||
//! his journey after the Sun, this time, to _the outer planets_,
|
||||
//! Notice the planets in `PLANETS` are stored in
|
||||
//! a special order known as _the Ptolemaic Order_.
|
||||
//! In many ancient traditions, when a man is deceased,
|
||||
//! he will depart the Earth, and head toward the Moon.
|
||||
//! Leaving the Moon behind, the Mercury, the Venus,
|
||||
//! and the Sun. He will continue his journey after
|
||||
//! the Sun, this time, to _the outer planets_,
|
||||
//! that are the Mars, the Jupiter, and the Saturn.
|
||||
//!
|
||||
//! After all, this library provides methodologies
|
||||
//! _NOT_ for _"astronomy"_, but for _"astrology"_, hence,
|
||||
//! follows the tradition which was common to the ancients.
|
||||
//! _NOT_ for _"astronomy"_, but for _"astrology"_,
|
||||
//! hence, follows the tradition which was common to
|
||||
//! the ancients.
|
||||
//!
|
||||
//! Also noteworthy that, according to Rudolf Steiner,
|
||||
//! "Mercury" was formerly known as "Venus" in ancient times.
|
||||
//! Yet, it is only so when we are talking about the order
|
||||
//! of the _physical_ planets, not in its _symbolical_ sense.
|
||||
//! For instance, when ancients mentioned of "Mercury",
|
||||
//! it was simply about "Mercury" and not "Venus".
|
||||
//! "Mercury" was formerly known as "Venus" in ancient
|
||||
//! times. Yet, it is only so when we are talking about
|
||||
//! the order of the _physical_ planets, not in its
|
||||
//! _symbolical_ sense. For instance, when ancients
|
||||
//! mentioned of "Mercury", it was simply about
|
||||
//! "Mercury" and not "Venus".
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
use crate::utils::get_json;
|
||||
|
||||
/// A struct representing a planet and stores its attributes.
|
||||
/// A struct representing a planet and stores its
|
||||
/// attributes.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Planet {
|
||||
pub name: Language,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining a static const `PLANETS`.
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a static const `PLANETS`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlanetRawData {
|
||||
pub name: LanguageData,
|
||||
@@ -52,22 +55,24 @@ impl NameDataTrait for PlanetRawData {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A static vector with 11 items, each represents a planet
|
||||
/// in our solar system. Planets are in Ptolemaic order.
|
||||
/// A static vector with 11 items, each represents
|
||||
/// a planet in our solar system. Planets are in
|
||||
/// Ptolemaic order.
|
||||
///
|
||||
/// [0] Earth
|
||||
/// [1] Moon
|
||||
/// [2] Mercury
|
||||
/// [3] Venus
|
||||
/// [4] Sun
|
||||
/// [5] Mars
|
||||
/// [6] Jupiter
|
||||
/// [7] Saturn
|
||||
/// [8] Uranus
|
||||
/// [9] Neptune
|
||||
/// [0] Earth
|
||||
/// [1] Moon
|
||||
/// [2] Mercury
|
||||
/// [3] Venus
|
||||
/// [4] Sun
|
||||
/// [5] Mars
|
||||
/// [6] Jupiter
|
||||
/// [7] Saturn
|
||||
/// [8] Uranus
|
||||
/// [9] Neptune
|
||||
/// [10] Pluto
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// For attributes details stored in the vector is
|
||||
/// found in JSON file:
|
||||
/// `src/json/planets.json`
|
||||
pub static ref PLANETS: Vec<Planet> = {
|
||||
let json = &include_str!("../json/planet.json");
|
||||
|
||||
159
src/shengsi.rs
159
src/shengsi.rs
@@ -1,34 +1,40 @@
|
||||
//! 生死衰旺 (Sheng-Si Shuai-Wang) is just a combination
|
||||
//! of 4 Chinese characters, each being:
|
||||
//! 生死衰旺 (Sheng-Si Shuai-Wang) is just a
|
||||
//! combination of 4 Chinese characters, each being:
|
||||
//!
|
||||
//! (1) Growing --> 生 (Sheng)
|
||||
//! (2) Deadly --> 死 (Si)
|
||||
//! (3) Perishing --> 衰 (Shuai)
|
||||
//! (4) Prosperous --> 旺 (Wang)
|
||||
//!
|
||||
//! They are often used in 四柱命理学 (The Four Pillars of Destiny),
|
||||
//! but used in Feng-Shui as well. It simply suggests
|
||||
//! that there are 4 states to the energy occupying the space.
|
||||
//! In 玄空飞星風水 (Xuan-Kong Fei-Xing Feng-Shui),
|
||||
//! it describes the state for the target year
|
||||
//! in 三元九運 (Sang-Yuan Jiu-Yun),
|
||||
//! especially, for its 向星 (Xiang-Xing).
|
||||
//! They are often used in 四柱命理学 (The Four Pillars
|
||||
//! of Destiny), but used in Feng-Shui as well.
|
||||
//! It simply suggests that there are 4 states to
|
||||
//! the energy occupying the space. In 玄空飞星風水
|
||||
//! (Xuan-Kong Fei-Xing Feng-Shui), it describes
|
||||
//! the state for the target year in 三元九運
|
||||
//! (Sang-Yuan Jiu-Yun), especially, for its 向星
|
||||
//! (Xiang-Xing).
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::jiuxing::normalize_jiuxing;
|
||||
|
||||
/// A struct representing 生死衰旺 (Sheng-Si Shuai-Wang).
|
||||
/// `key` would be: "sheng", "si", "shuai", or "wang".
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||
/// A struct representing 生死衰旺 (Sheng-Si
|
||||
/// Shuai-Wang). `key` would be: "sheng", "si",
|
||||
/// "shuai", or "wang".
|
||||
#[derive(
|
||||
Debug, Clone, Deserialize, Serialize, PartialEq,
|
||||
)]
|
||||
pub struct ShengSi<'a> {
|
||||
pub key: &'a str,
|
||||
pub kanji: &'a str,
|
||||
pub meaning: &'a str,
|
||||
}
|
||||
|
||||
/// A struct holding allocations of 生死衰旺 (Sheng-Si Shuai-Wang) for the given year.
|
||||
/// For `usize` (in `Vec<usize>`) is 九星 (Jiu-Xing) index.
|
||||
/// A struct holding allocations of 生死衰旺
|
||||
/// (Sheng-Si Shuai-Wang) for the given year.
|
||||
/// For `usize` (in `Vec<usize>`) is 九星
|
||||
/// (Jiu-Xing) index.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShengSiYearlyAlloc {
|
||||
pub wang: Vec<usize>,
|
||||
@@ -38,7 +44,10 @@ pub struct ShengSiYearlyAlloc {
|
||||
}
|
||||
|
||||
impl ShengSiYearlyAlloc {
|
||||
pub fn accessor(&self, name: &str) -> Option<&Vec<usize>> {
|
||||
pub fn accessor(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Option<&Vec<usize>> {
|
||||
match name {
|
||||
"wang" => Some(&self.wang),
|
||||
"sheng" => Some(&self.sheng),
|
||||
@@ -50,8 +59,8 @@ impl ShengSiYearlyAlloc {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A HashMap for 生死衰旺 (Sheng-Si Shuai-Wang) by key
|
||||
/// (for each holds `ShengSi`).
|
||||
/// A HashMap for 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
/// by key (for each holds `ShengSi`).
|
||||
pub static ref SHENG_SI: HashMap<&'static str, ShengSi<'static>> = HashMap::from([
|
||||
("sheng", ShengSi { key: "sheng", kanji: "生", meaning: "growth" }),
|
||||
("si", ShengSi { key: "si", kanji: "死", meaning: "death" }),
|
||||
@@ -59,18 +68,23 @@ lazy_static! {
|
||||
("wang", ShengSi { key: "wang", kanji: "旺", meaning: "prosperous" }),
|
||||
]);
|
||||
|
||||
/// For every year, some 九星 (Jiu-Xing) maybe in 旺 (Wang = Prospering)
|
||||
/// phase, but some maybe in 死 (Si = Dying). 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
/// for 九星 (Jiu-Xing) is no random, but has certain patterns,
|
||||
/// and is repeated every 9 years. This cycle is called
|
||||
/// 三元九運 (Sang-Yuan Jiu-Yun), and given the 運盤星 (Un-Pan Xing) index
|
||||
/// for the specific year, you can tell of 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
/// for all the other 九星 (Jiu-Xing). Here, it is constructing
|
||||
/// the patterns for 9 years, and making them into a static vector
|
||||
/// for which each index being the 運盤星 (Un-Pan Xing) index.
|
||||
/// If you know the 運盤星 (Un-Pan Xing) index for the year,
|
||||
/// this static vector will tell you 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
/// for all 九星 (Jiu-Xing).
|
||||
/// For every year, some 九星 (Jiu-Xing) maybe in
|
||||
/// 旺 (Wang = Prospering) phase, but some maybe
|
||||
/// in 死 (Si = Dying). 生死衰旺 (Sheng-Si
|
||||
/// Shuai-Wang) for 九星 (Jiu-Xing) is no random,
|
||||
/// but has certain patterns, and is repeated every
|
||||
/// 9 years. This cycle is called 三元九運
|
||||
/// (Sang-Yuan Jiu-Yun), and given the 運盤星
|
||||
/// (Un-Pan Xing) index for the specific year, you
|
||||
/// can tell of 生死衰旺 (Sheng-Si Shuai-Wang) for
|
||||
/// all the other 九星 (Jiu-Xing). Here, it is
|
||||
/// constructing the patterns for 9 years, and
|
||||
/// making them into a static vector for which each
|
||||
/// index being the 運盤星 (Un-Pan Xing) index.
|
||||
/// If you know the 運盤星 (Un-Pan Xing) index for
|
||||
/// the year, this static vector will tell you
|
||||
/// 生死衰旺 (Sheng-Si Shuai-Wang) for all 九星
|
||||
/// (Jiu-Xing).
|
||||
pub static ref SHENG_SI_ALLOC: Vec<ShengSiYearlyAlloc> = (0..9)
|
||||
.map(|i: i32| {
|
||||
// 旺 (Wang)
|
||||
@@ -80,7 +94,7 @@ lazy_static! {
|
||||
let sheng: Vec<usize> = [1, 2]
|
||||
.iter()
|
||||
.map(|num| {
|
||||
normalize_jiuxing((unpan_id + num) as i32)
|
||||
normalize_jiuxing(unpan_id + num)
|
||||
})
|
||||
.collect::<Vec<usize>>();
|
||||
|
||||
@@ -88,7 +102,7 @@ lazy_static! {
|
||||
let shuai: Vec<usize> = [1, 2]
|
||||
.iter()
|
||||
.map(|num| {
|
||||
normalize_jiuxing((unpan_id - num) as i32)
|
||||
normalize_jiuxing(unpan_id - num)
|
||||
})
|
||||
.collect::<Vec<usize>>();
|
||||
|
||||
@@ -101,25 +115,29 @@ lazy_static! {
|
||||
.collect::<Vec<usize>>();
|
||||
|
||||
ShengSiYearlyAlloc {
|
||||
// 運盤星 (Un-Pan Xing) is always the 旺 (wang) for the year.
|
||||
// 運盤星 (Un-Pan Xing) is always the
|
||||
// 旺 (wang) for the year.
|
||||
wang: vec!(unpan_id as usize),
|
||||
|
||||
// Two 九星 (Jiu-Xing) that *proceed* 運盤星 (Un-Pan Xing)
|
||||
// is always the 生 (Sheng).
|
||||
// Two 九星 (Jiu-Xing) that *proceed*
|
||||
// 運盤星 (Un-Pan Xing) is always the
|
||||
// 生 (Sheng).
|
||||
sheng,
|
||||
|
||||
// Two 九星 (Jiu-Xing) that *preceed* 運盤星 (Un-Pan Xing)
|
||||
// is always the 衰 (Shuai). However, there is
|
||||
// an exceptional case when 一白水星 (1 White) were
|
||||
// given for the 運盤星 (Un-Pan Xing) because
|
||||
// it should be converted to 九紫火星 (9 Purple).
|
||||
// Two 九星 (Jiu-Xing) that *preceed*
|
||||
// 運盤星 (Un-Pan Xing) is always the
|
||||
// 衰 (Shuai). However, there is
|
||||
// an exceptional case when 一白水星
|
||||
// (1 White) were given for the 運盤星
|
||||
// (Un-Pan Xing) because it should be
|
||||
// converted to 九紫火星 (9 Purple).
|
||||
shuai: if unpan_id == 0 {
|
||||
vec!(8)
|
||||
} else {
|
||||
shuai
|
||||
},
|
||||
|
||||
// Calculation for 死 (Si) is a bit tricky...
|
||||
// Calculation for 死 (Si) is tricky...
|
||||
si: si
|
||||
.iter()
|
||||
.filter_map(|&index| {
|
||||
@@ -139,9 +157,10 @@ lazy_static! {
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Given 運盤 (Un-Pan) index and a layout for the current
|
||||
/// 運盤 (Un-Pan) positions (`&[usize; 9]`), returns the corresponding
|
||||
/// 生死衰旺 (Sheng-Si Shuai-Wang) situation.
|
||||
/// Given 運盤 (Un-Pan) index and a layout for the
|
||||
/// current 運盤 (Un-Pan) positions (`&[usize; 9]`),
|
||||
/// returns the corresponding 生死衰旺 (Sheng-Si
|
||||
/// Shuai-Wang) situation.
|
||||
///
|
||||
/// Example:
|
||||
/// ```rust
|
||||
@@ -168,39 +187,45 @@ pub fn get_shengsi_mapping(
|
||||
unpan_id: usize,
|
||||
unpan_xing_chart: &[usize; 9],
|
||||
) -> Vec<Option<&ShengSi>> {
|
||||
// At first, we will get 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
// for the given 運盤星 (Un-Pan Xing).
|
||||
let yearly_allocs: &ShengSiYearlyAlloc = &SHENG_SI_ALLOC[unpan_id];
|
||||
// At first, we will get 生死衰旺 (Sheng-Si
|
||||
// Shuai-Wang) for the given 運盤星 (Un-Pan
|
||||
// Xing).
|
||||
let yearly_allocs: &ShengSiYearlyAlloc =
|
||||
&SHENG_SI_ALLOC[unpan_id];
|
||||
|
||||
// Now, 生死衰旺 (Sheng-Si Shuai-Wang) just obtained
|
||||
// is mapped by "sheng", "si", "shuai", and "wang".
|
||||
// However, we rather want to look up by 九星 (Jiu-Xing) index.
|
||||
// So, we are creating a temporary mapping here.
|
||||
// Though, in the next line, we are just initializing
|
||||
// each in the mapping with `None`.
|
||||
let mut lookup: HashMap<usize, Option<&ShengSi>> = (0..9)
|
||||
.map(|index: usize| (index, None))
|
||||
.into_iter()
|
||||
.collect();
|
||||
// However, we rather want to look up by 九星
|
||||
// (Jiu-Xing) index. So, we are creating a temporary
|
||||
// mapping here. Though, in the next line, we are
|
||||
// just initializing each in the mapping with `None`.
|
||||
let mut lookup: HashMap<usize, Option<&ShengSi>> =
|
||||
(0..9)
|
||||
.map(|index: usize| (index, None))
|
||||
.collect();
|
||||
|
||||
// Once the mapping being initialized, we are
|
||||
// creating the mapping.
|
||||
for key in ["sheng", "si", "shuai", "wang"] {
|
||||
let data: Option<&ShengSi> = SHENG_SI.get(key);
|
||||
let data: Option<&ShengSi> =
|
||||
SHENG_SI.get(key);
|
||||
|
||||
for index in yearly_allocs.accessor(key).unwrap() {
|
||||
for index in
|
||||
yearly_allocs.accessor(key).unwrap()
|
||||
{
|
||||
*lookup.get_mut(index).unwrap() = data;
|
||||
}
|
||||
}
|
||||
|
||||
// We have 運盤 (Un-Pan) chart given. All we want is
|
||||
// to find 生死衰旺 (Sheng-Si Shuai-Wang)
|
||||
// for each 九星 (Jiu-Xing) in the 運盤 (Un-Pan) chart
|
||||
// (using the temporary mapping just created).
|
||||
// We have 運盤 (Un-Pan) chart given. All we want
|
||||
// is to find 生死衰旺 (Sheng-Si Shuai-Wang) for
|
||||
// each 九星 (Jiu-Xing) in the 運盤 (Un-Pan)
|
||||
// chart (using the temporary mapping just created).
|
||||
unpan_xing_chart
|
||||
.iter()
|
||||
.map(|index: &usize| *lookup.get(index).unwrap())
|
||||
.into_iter()
|
||||
.map(|index: &usize| {
|
||||
*lookup.get(index).unwrap()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -210,7 +235,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_constant_sheng_si() {
|
||||
assert_eq!(SHENG_SI.get("sheng").unwrap().key, "sheng");
|
||||
assert_eq!(
|
||||
SHENG_SI.get("sheng").unwrap().key,
|
||||
"sheng"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -226,7 +254,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_shengsi_mapping() {
|
||||
let res = get_shengsi_mapping(6, &[2, 0, 4, 7, 6, 5, 8, 3, 1]);
|
||||
let res = get_shengsi_mapping(
|
||||
6,
|
||||
&[2, 0, 4, 7, 6, 5, 8, 3, 1],
|
||||
);
|
||||
assert_eq!(res[0].unwrap().key, "si"); // 2
|
||||
assert_eq!(res[1], None); // 0
|
||||
assert_eq!(res[2].unwrap().key, "shuai"); // 4
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
//! A module for 二十四节气 (Er-Shi-Si Jie-Qi).
|
||||
//! Or, for calculating 立春 (Li-Chun).
|
||||
|
||||
use chrono::Datelike;
|
||||
use chrono::naive::NaiveDate;
|
||||
use chrono::Datelike;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sowngwala::time::add_date;
|
||||
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
use crate::utils::{
|
||||
get_json,
|
||||
longitude_of_the_sun_from_generic_date,
|
||||
get_json, longitude_of_the_sun_from_generic_date,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -45,8 +42,10 @@ impl NameDataTrait for SolarTermRawData {
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SOLAR_TERMS: Vec<SolarTerm> = {
|
||||
let json = &include_str!("../json/solar_terms.json");
|
||||
let data: Vec<SolarTermRawData> = get_json::<SolarTermRawData>(json);
|
||||
let json =
|
||||
&include_str!("../json/solar_terms.json");
|
||||
let data: Vec<SolarTermRawData> =
|
||||
get_json::<SolarTermRawData>(json);
|
||||
data.iter()
|
||||
.map(|item| {
|
||||
let item = item.clone();
|
||||
@@ -61,8 +60,11 @@ lazy_static! {
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
pub fn get_last_term(date: NaiveDate) -> (f64, NaiveDate) {
|
||||
let lng_0: f64 = longitude_of_the_sun_from_generic_date(date);
|
||||
pub fn get_last_term(
|
||||
date: NaiveDate,
|
||||
) -> (f64, NaiveDate) {
|
||||
let lng_0: f64 =
|
||||
longitude_of_the_sun_from_generic_date(date);
|
||||
// For the unit of 15, we want the last term.
|
||||
// Ex.
|
||||
// 317.435511 --> 315.0
|
||||
@@ -79,7 +81,10 @@ pub fn get_last_term(date: NaiveDate) -> (f64, NaiveDate) {
|
||||
|
||||
// Go back by one day a time.
|
||||
while term.is_none() {
|
||||
let lng: f64 = longitude_of_the_sun_from_generic_date(next);
|
||||
let lng: f64 =
|
||||
longitude_of_the_sun_from_generic_date(
|
||||
next,
|
||||
);
|
||||
// See if the target falls in the current date.
|
||||
if lng <= target && lng > (target - 1.0) {
|
||||
term = prev;
|
||||
@@ -121,9 +126,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_last_term() {
|
||||
let (_lng, term): (f64, NaiveDate) = get_last_term(
|
||||
NaiveDate::from_ymd(2022, 2, 6)
|
||||
);
|
||||
let (_lng, term): (f64, NaiveDate) =
|
||||
get_last_term(NaiveDate::from_ymd(
|
||||
2022, 2, 6,
|
||||
));
|
||||
assert_eq!(term.year(), 2022);
|
||||
assert_eq!(term.month(), 2);
|
||||
assert_eq!(term.day(), 4);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
/**
|
||||
* Modules used ONLY from tests.
|
||||
*/
|
||||
use chrono::naive::{
|
||||
NaiveDate,
|
||||
NaiveDateTime,
|
||||
};
|
||||
use chrono::naive::{NaiveDate, NaiveDateTime};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::From;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Copy, Clone,
|
||||
)]
|
||||
pub struct DateParams {
|
||||
pub year: i32,
|
||||
pub month: u32,
|
||||
@@ -25,7 +24,9 @@ impl From<DateParams> for NaiveDate {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Copy, Clone,
|
||||
)]
|
||||
pub struct DateTimeParams {
|
||||
pub year: i32,
|
||||
pub month: u32,
|
||||
@@ -34,7 +35,7 @@ pub struct DateTimeParams {
|
||||
pub minute: u32,
|
||||
pub second: u32,
|
||||
pub nanosecond: u32,
|
||||
pub zone: i32
|
||||
pub zone: i32,
|
||||
}
|
||||
|
||||
impl From<DateTimeParams> for NaiveDateTime {
|
||||
@@ -43,7 +44,8 @@ impl From<DateTimeParams> for NaiveDateTime {
|
||||
params.year,
|
||||
params.month,
|
||||
params.day,
|
||||
).and_hms(
|
||||
)
|
||||
.and_hms(
|
||||
params.hour,
|
||||
params.minute,
|
||||
params.second,
|
||||
|
||||
39
src/utils.rs
39
src/utils.rs
@@ -6,7 +6,9 @@ use serde::Deserialize;
|
||||
|
||||
use sowngwala::sun::ecliptic_position_of_the_sun_from_generic_date;
|
||||
|
||||
pub fn get_json<'a, T: Deserialize<'a>>(json: &'a str) -> Vec<T> {
|
||||
pub fn get_json<'a, T: Deserialize<'a>>(
|
||||
json: &'a str,
|
||||
) -> Vec<T> {
|
||||
match serde_json::from_str(json) {
|
||||
Ok(json) => json,
|
||||
Err(err) => panic!("Error: {}", err),
|
||||
@@ -14,24 +16,33 @@ pub fn get_json<'a, T: Deserialize<'a>>(json: &'a str) -> Vec<T> {
|
||||
}
|
||||
|
||||
/// For the given Vec, sorts by given order.
|
||||
pub fn make_sort<T: Clone>(order: Vec<u8>) -> Box<dyn Fn(Vec<T>) -> Vec<T>> {
|
||||
pub fn make_sort<T: Clone>(
|
||||
order: Vec<u8>,
|
||||
) -> Box<dyn Fn(Vec<T>) -> Vec<T>> {
|
||||
Box::new(move |source: Vec<T>| -> Vec<T> {
|
||||
order
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|index| source[index as usize].clone())
|
||||
.map(|index| {
|
||||
source[index as usize].clone()
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Increments by the given step until it becomes more than 0.
|
||||
pub fn make_positive(step: u32) -> Box<dyn Fn(i32) -> u32> {
|
||||
pub fn make_positive(
|
||||
step: u32,
|
||||
) -> Box<dyn Fn(i32) -> u32> {
|
||||
Box::new(move |mut num: i32| -> u32 {
|
||||
let limit = 10000;
|
||||
let mut cnt = 0;
|
||||
while num < 0 {
|
||||
if cnt > limit {
|
||||
panic!("Iteration reached: {}", limit);
|
||||
panic!(
|
||||
"Iteration reached: {}",
|
||||
limit
|
||||
);
|
||||
}
|
||||
num += step as i32;
|
||||
cnt += 1;
|
||||
@@ -40,11 +51,17 @@ pub fn make_positive(step: u32) -> Box<dyn Fn(i32) -> u32> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn longitude_of_the_sun_from_generic_date<T>(date: T) -> f64
|
||||
where T: Datelike,
|
||||
T: std::marker::Copy,
|
||||
T: std::fmt::Debug,
|
||||
T: std::fmt::Display
|
||||
pub fn longitude_of_the_sun_from_generic_date<T>(
|
||||
date: T,
|
||||
) -> f64
|
||||
where
|
||||
T: Datelike,
|
||||
T: std::marker::Copy,
|
||||
T: std::fmt::Debug,
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
ecliptic_position_of_the_sun_from_generic_date(date).lng
|
||||
ecliptic_position_of_the_sun_from_generic_date(
|
||||
date,
|
||||
)
|
||||
.lng
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::language::{
|
||||
Language,
|
||||
LanguageData,
|
||||
LanguageTrait,
|
||||
Language, LanguageData, LanguageTrait,
|
||||
NameDataTrait,
|
||||
};
|
||||
use crate::utils::get_json;
|
||||
@@ -15,7 +13,8 @@ pub struct WuXing {
|
||||
pub name: Language,
|
||||
}
|
||||
|
||||
/// A temporary struct for loading JSON data when defining a static const `WU_XING`.
|
||||
/// A temporary struct for loading JSON data when
|
||||
/// defining a static const `WU_XING`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WuXingRawData {
|
||||
pub name: LanguageData,
|
||||
@@ -34,9 +33,11 @@ impl NameDataTrait for WuXingRawData {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// A static vector with 5 items, each represents 五行 (Wu-Xing).
|
||||
/// A static vector with 5 items, each represents
|
||||
/// 五行 (Wu-Xing).
|
||||
///
|
||||
/// For attributes details stored in the vector is found in JSON file:
|
||||
/// For attributes details stored in the vector is
|
||||
/// found in JSON file:
|
||||
/// `src/json/wuxing.json`
|
||||
pub static ref WU_XING: Vec<WuXing> = {
|
||||
let json = &include_str!("../json/wuxing.json");
|
||||
|
||||
Reference in New Issue
Block a user