iching-shifa 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,6 +8,8 @@
8
8
  - **时间起卦** - 按年月日时四柱起卦
9
9
  - **手动输入起卦** - 输入6位爻值字符串(6/7/8/9)
10
10
  - **纳甲排盘** - 完整的六爻排盘(本卦/之卦/互卦、六亲、六兽、世应、伏神等)
11
+ - **神煞排盘** - 按日支/月令/季节/日干计算神煞,并输出独立 JSON 字段
12
+ - **纳音信息** - 本卦和之卦六爻输出 60 甲子纳音
11
13
 
12
14
  ## 安装
13
15
 
@@ -82,6 +84,7 @@ interface PanResult {
82
84
  dayKong: string; // 日空
83
85
  hourKong: string; // 时空
84
86
  monthJian: string; // 月建
87
+ shenSha: ShenShaMap; // 神煞(独立 map)
85
88
  benGua: GuaPan; // 本卦
86
89
  zhiGua: GuaPan; // 之卦
87
90
  huGua: GuaPan; // 互卦
@@ -90,6 +93,16 @@ interface PanResult {
90
93
  explanation: string; // 断卦说明
91
94
  }
92
95
 
96
+ type ShenShaMap = Record<string, {
97
+ targetDiZhi: string[];
98
+ matches: {
99
+ guaKey: 'benGua' | 'zhiGua' | 'huGua';
100
+ position: number;
101
+ diZhi: string;
102
+ naJia: string;
103
+ }[];
104
+ }>;
105
+
93
106
  interface GuaPan {
94
107
  guaName: string; // 卦名
95
108
  palace: string; // 所属宫
@@ -101,6 +114,7 @@ interface GuaPan {
101
114
  tuanCi: string; // 彖辞
102
115
  shenYao?: number; // 身爻
103
116
  fuShen?: FuShenData[];// 伏神
117
+ pangFuShen?: FuShenData[];// 旁伏神
104
118
  }
105
119
 
106
120
  interface YaoData {
@@ -110,6 +124,7 @@ interface YaoData {
110
124
  tianGan: string; // 天干
111
125
  diZhi: string; // 地支
112
126
  naJia: string; // 纳甲
127
+ naYin?: string; // 纳音(本卦、之卦)
113
128
  wuXing: string; // 五行
114
129
  liuQin: string; // 六亲
115
130
  liuShou: string; // 六兽
@@ -138,10 +153,10 @@ bun test --watch
138
153
  ```bash
139
154
  $ bun test
140
155
 
141
- 12 pass
156
+ 19 pass
142
157
  0 fail
143
- 67 expect() calls
144
- Ran 12 tests across 1 file. [33.00ms]
158
+ 127 expect() calls
159
+ Ran 19 tests across 1 file. [28.00ms]
145
160
  ```
146
161
 
147
162
  ## 许可
package/dist/index.cjs CHANGED
@@ -5407,6 +5407,71 @@ const WU_XING_STARS = [
5407
5407
  "岁星",
5408
5408
  "熒惑"
5409
5409
  ];
5410
+ const NAYIN_60 = {
5411
+ "甲子": "海中金",
5412
+ "乙丑": "海中金",
5413
+ "丙寅": "炉中火",
5414
+ "丁卯": "炉中火",
5415
+ "戊辰": "大林木",
5416
+ "己巳": "大林木",
5417
+ "庚午": "路旁土",
5418
+ "辛未": "路旁土",
5419
+ "壬申": "剑锋金",
5420
+ "癸酉": "剑锋金",
5421
+ "甲戌": "山头火",
5422
+ "乙亥": "山头火",
5423
+ "丙子": "涧下水",
5424
+ "丁丑": "涧下水",
5425
+ "戊寅": "城头土",
5426
+ "己卯": "城头土",
5427
+ "庚辰": "白蜡金",
5428
+ "辛巳": "白蜡金",
5429
+ "壬午": "杨柳木",
5430
+ "癸未": "杨柳木",
5431
+ "甲申": "泉中水",
5432
+ "乙酉": "泉中水",
5433
+ "丙戌": "屋上土",
5434
+ "丁亥": "屋上土",
5435
+ "戊子": "霹雳火",
5436
+ "己丑": "霹雳火",
5437
+ "庚寅": "松柏木",
5438
+ "辛卯": "松柏木",
5439
+ "壬辰": "长流水",
5440
+ "癸巳": "长流水",
5441
+ "甲午": "沙中金",
5442
+ "乙未": "沙中金",
5443
+ "丙申": "山下火",
5444
+ "丁酉": "山下火",
5445
+ "戊戌": "平地木",
5446
+ "己亥": "平地木",
5447
+ "庚子": "壁上土",
5448
+ "辛丑": "壁上土",
5449
+ "壬寅": "金箔金",
5450
+ "癸卯": "金箔金",
5451
+ "甲辰": "覆灯火",
5452
+ "乙巳": "覆灯火",
5453
+ "丙午": "天河水",
5454
+ "丁未": "天河水",
5455
+ "戊申": "大驿土",
5456
+ "己酉": "大驿土",
5457
+ "庚戌": "钗钏金",
5458
+ "辛亥": "钗钏金",
5459
+ "壬子": "桑柘木",
5460
+ "癸丑": "桑柘木",
5461
+ "甲寅": "大溪水",
5462
+ "乙卯": "大溪水",
5463
+ "丙辰": "沙中土",
5464
+ "丁巳": "沙中土",
5465
+ "戊午": "天上火",
5466
+ "己未": "天上火",
5467
+ "庚申": "石榴木",
5468
+ "辛酉": "石榴木",
5469
+ "壬戌": "大海水",
5470
+ "癸亥": "大海水"
5471
+ };
5472
+ function getNaYin(ganZhi) {
5473
+ return NAYIN_60[ganZhi];
5474
+ }
5410
5475
  const GAN_ZHI_WUXING = {
5411
5476
  // 天干
5412
5477
  "甲": "木",
@@ -5594,6 +5659,146 @@ function getCurrentSolarTerm(year, month, day) {
5594
5659
  return "";
5595
5660
  }
5596
5661
  }
5662
+ const SHENSHA_ORDER = [
5663
+ "驿马",
5664
+ "桃花",
5665
+ "华盖",
5666
+ "天医",
5667
+ "天喜",
5668
+ "天马",
5669
+ "天乙贵人",
5670
+ "禄神",
5671
+ "文昌"
5672
+ ];
5673
+ function getDayBranchShenSha(dayZhi) {
5674
+ if (["申", "子", "辰"].includes(dayZhi)) {
5675
+ return { 驿马: ["寅"], 桃花: ["酉"], 华盖: ["辰"] };
5676
+ }
5677
+ if (["寅", "午", "戌"].includes(dayZhi)) {
5678
+ return { 驿马: ["申"], 桃花: ["卯"], 华盖: ["戌"] };
5679
+ }
5680
+ if (["巳", "酉", "丑"].includes(dayZhi)) {
5681
+ return { 驿马: ["亥"], 桃花: ["午"], 华盖: ["丑"] };
5682
+ }
5683
+ if (["亥", "卯", "未"].includes(dayZhi)) {
5684
+ return { 驿马: ["巳"], 桃花: ["子"], 华盖: ["未"] };
5685
+ }
5686
+ return { 驿马: [], 桃花: [], 华盖: [] };
5687
+ }
5688
+ function getTianYi(monthZhi) {
5689
+ const index = DI_ZHI.indexOf(monthZhi);
5690
+ if (index === -1) {
5691
+ return [];
5692
+ }
5693
+ return [DI_ZHI[(index + DI_ZHI.length - 1) % DI_ZHI.length]];
5694
+ }
5695
+ function getTianMa(monthZhi) {
5696
+ if (["寅", "申"].includes(monthZhi)) return ["午"];
5697
+ if (["卯", "酉"].includes(monthZhi)) return ["申"];
5698
+ if (["辰", "戌"].includes(monthZhi)) return ["戌"];
5699
+ if (["巳", "亥"].includes(monthZhi)) return ["子"];
5700
+ if (["子", "午"].includes(monthZhi)) return ["寅"];
5701
+ if (["丑", "未"].includes(monthZhi)) return ["辰"];
5702
+ return [];
5703
+ }
5704
+ function getSeasonByMonthZhi(monthZhi) {
5705
+ if (["寅", "卯", "辰"].includes(monthZhi)) return "春";
5706
+ if (["巳", "午", "未"].includes(monthZhi)) return "夏";
5707
+ if (["申", "酉", "戌"].includes(monthZhi)) return "秋";
5708
+ if (["亥", "子", "丑"].includes(monthZhi)) return "冬";
5709
+ return void 0;
5710
+ }
5711
+ function getTianXi(monthZhi) {
5712
+ const season = getSeasonByMonthZhi(monthZhi);
5713
+ if (season === "春") return ["戌"];
5714
+ if (season === "夏") return ["丑"];
5715
+ if (season === "秋") return ["辰"];
5716
+ if (season === "冬") return ["未"];
5717
+ return [];
5718
+ }
5719
+ function getTianYiGuiRen(dayGan) {
5720
+ if (["甲", "戊"].includes(dayGan)) return ["丑", "未"];
5721
+ if (["乙", "己"].includes(dayGan)) return ["子", "申"];
5722
+ if (["丙", "丁"].includes(dayGan)) return ["亥", "酉"];
5723
+ if (["庚", "辛"].includes(dayGan)) return ["午", "寅"];
5724
+ if (["壬", "癸"].includes(dayGan)) return ["卯", "巳"];
5725
+ return [];
5726
+ }
5727
+ function getLuShen(dayGan) {
5728
+ if (dayGan === "甲") return ["寅"];
5729
+ if (dayGan === "乙") return ["卯"];
5730
+ if (dayGan === "丙") return ["巳"];
5731
+ if (dayGan === "丁") return ["午"];
5732
+ if (dayGan === "戊") return ["巳"];
5733
+ if (dayGan === "己") return ["午"];
5734
+ if (dayGan === "庚") return ["申"];
5735
+ if (dayGan === "辛") return ["酉"];
5736
+ if (dayGan === "壬") return ["亥"];
5737
+ if (dayGan === "癸") return ["子"];
5738
+ return [];
5739
+ }
5740
+ function getWenChang(dayGan) {
5741
+ if (dayGan === "甲") return ["巳"];
5742
+ if (dayGan === "乙") return ["午"];
5743
+ if (dayGan === "丙") return ["申"];
5744
+ if (dayGan === "丁") return ["酉"];
5745
+ if (dayGan === "戊") return ["申"];
5746
+ if (dayGan === "己") return ["酉"];
5747
+ if (dayGan === "庚") return ["亥"];
5748
+ if (dayGan === "辛") return ["子"];
5749
+ if (dayGan === "壬") return ["寅"];
5750
+ if (dayGan === "癸") return ["卯"];
5751
+ return [];
5752
+ }
5753
+ function getShenShaTargets(dayGan, dayZhi, monthZhi) {
5754
+ const dayBranchShenSha = getDayBranchShenSha(dayZhi);
5755
+ return {
5756
+ 驿马: dayBranchShenSha.驿马,
5757
+ 桃花: dayBranchShenSha.桃花,
5758
+ 华盖: dayBranchShenSha.华盖,
5759
+ 天医: getTianYi(monthZhi),
5760
+ 天喜: getTianXi(monthZhi),
5761
+ 天马: getTianMa(monthZhi),
5762
+ 天乙贵人: getTianYiGuiRen(dayGan),
5763
+ 禄神: getLuShen(dayGan),
5764
+ 文昌: getWenChang(dayGan)
5765
+ };
5766
+ }
5767
+ function buildShenShaMap(dayGan, dayZhi, monthZhi, guaList) {
5768
+ const targets = getShenShaTargets(dayGan, dayZhi, monthZhi);
5769
+ const result = {};
5770
+ for (const name of SHENSHA_ORDER) {
5771
+ const targetDiZhi = targets[name];
5772
+ const matches = [];
5773
+ for (const gua of guaList) {
5774
+ for (const yao of gua.yaoList) {
5775
+ if (targetDiZhi.includes(yao.diZhi)) {
5776
+ matches.push({
5777
+ guaKey: gua.guaKey,
5778
+ position: yao.position,
5779
+ diZhi: yao.diZhi,
5780
+ naJia: yao.naJia
5781
+ });
5782
+ }
5783
+ }
5784
+ }
5785
+ result[name] = {
5786
+ targetDiZhi: [...targetDiZhi],
5787
+ matches
5788
+ };
5789
+ }
5790
+ return result;
5791
+ }
5792
+ const OPPOSITE_PALACE = {
5793
+ "乾": "坤",
5794
+ "坤": "乾",
5795
+ "坎": "离",
5796
+ "离": "坎",
5797
+ "震": "巽",
5798
+ "巽": "震",
5799
+ "艮": "兑",
5800
+ "兑": "艮"
5801
+ };
5597
5802
  function getGuaName(yaoString) {
5598
5803
  if (YAO_STRING_TO_GUA[yaoString]) {
5599
5804
  return YAO_STRING_TO_GUA[yaoString];
@@ -5638,7 +5843,7 @@ function getLiuShou(dayGan) {
5638
5843
  }
5639
5844
  return rotateList(shouList, startShou);
5640
5845
  }
5641
- function decodeGua(yaoString, dayGanZhi, isZhiGua = false) {
5846
+ function decodeGua(yaoString, dayGanZhi, isZhiGua = false, includeNaYin = true) {
5642
5847
  const guaName = getGuaName(yaoString);
5643
5848
  const palace = GUA_PALACE[guaName] || "乾";
5644
5849
  const palaceLevel = GUA_PALACE_LEVEL[guaName] || "本宮";
@@ -5683,7 +5888,7 @@ function decodeGua(yaoString, dayGanZhi, isZhiGua = false) {
5683
5888
  shenYaoIndex = shenYaoZhi;
5684
5889
  }
5685
5890
  }
5686
- yaoList.push({
5891
+ const yaoData = {
5687
5892
  position: i + 1,
5688
5893
  yaoValue,
5689
5894
  isMoving,
@@ -5694,7 +5899,11 @@ function decodeGua(yaoString, dayGanZhi, isZhiGua = false) {
5694
5899
  liuQin,
5695
5900
  liuShou,
5696
5901
  shiYing
5697
- });
5902
+ };
5903
+ if (includeNaYin) {
5904
+ yaoData.naYin = getNaYin(naJia);
5905
+ }
5906
+ yaoList.push(yaoData);
5698
5907
  }
5699
5908
  const desc = GUA_DESCRIPTIONS[guaName] || {};
5700
5909
  const guaCi = desc[0] || "";
@@ -5706,8 +5915,10 @@ function decodeGua(yaoString, dayGanZhi, isZhiGua = false) {
5706
5915
  const wuXingStarIndex = Math.floor(Math.random() * 5);
5707
5916
  const wuXingStar = WU_XING_STARS[wuXingStarIndex] || "鎮星";
5708
5917
  let fuShen;
5918
+ let pangFuShen;
5709
5919
  if (!isZhiGua) {
5710
5920
  fuShen = findFuShen(yaoList, palace, palaceWuXing);
5921
+ pangFuShen = findPangFuShen(yaoList, palace);
5711
5922
  }
5712
5923
  return {
5713
5924
  guaName,
@@ -5720,17 +5931,20 @@ function decodeGua(yaoString, dayGanZhi, isZhiGua = false) {
5720
5931
  yaoCi,
5721
5932
  tuanCi,
5722
5933
  shenYao: shenYaoIndex,
5723
- fuShen
5934
+ fuShen,
5935
+ pangFuShen
5724
5936
  };
5725
5937
  }
5726
5938
  function findFuShen(yaoList, palace, palaceWuXing) {
5727
- const existingLiuQin = new Set(yaoList.map((y) => y.liuQin));
5728
- const allLiuQin = ["父母", "兄弟", "官鬼", "妻财", "子孙"];
5729
- const missingLiuQin = allLiuQin.filter((lq) => !existingLiuQin.has(lq));
5730
- if (missingLiuQin.length === 0) {
5731
- return void 0;
5732
- }
5733
- const pureCode = PALACE_PURE_CODE[palace] || "777777";
5939
+ return buildFuShenFromPalace(yaoList, palace, palaceWuXing);
5940
+ }
5941
+ function findPangFuShen(yaoList, palace) {
5942
+ const oppositePalace = OPPOSITE_PALACE[palace] || "坤";
5943
+ const oppositeWuXing = PALACE_WUXING[oppositePalace] || "土";
5944
+ return buildFuShenFromPalace(yaoList, oppositePalace, oppositeWuXing);
5945
+ }
5946
+ function buildFuShenFromPalace(yaoList, sourcePalace, sourcePalaceWuXing) {
5947
+ const pureCode = PALACE_PURE_CODE[sourcePalace] || "777777";
5734
5948
  const pureLowerTrigram = CODE_TO_BAGUA[pureCode.slice(0, 3)] || "乾";
5735
5949
  const pureUpperTrigram = CODE_TO_BAGUA[pureCode.slice(3, 6)] || "乾";
5736
5950
  const pureLowerNajiaRaw = NAJIA_LOWER[pureLowerTrigram] || [];
@@ -5756,25 +5970,19 @@ function findFuShen(yaoList, palace, palaceWuXing) {
5756
5970
  const diZhi = DI_ZHI[najiaData[1]] || "子";
5757
5971
  const wuXing = WU_XING[najiaData[2]] || "金";
5758
5972
  const naJia = tianGan + diZhi;
5759
- const liuQin = wuXingToLiuQin(wuXing, palaceWuXing);
5760
- if (missingLiuQin.includes(liuQin)) {
5761
- const hostYao = yaoList[i];
5762
- fuShenList.push({
5763
- fuLiuQin: liuQin,
5764
- fuNaJia: naJia,
5765
- fuWuXing: wuXing,
5766
- hostYaoIndex: i,
5767
- hostNaJia: hostYao.naJia,
5768
- feiWuXing: hostYao.wuXing,
5769
- relation: getWuXingRelation(wuXing, hostYao.wuXing)
5770
- });
5771
- const idx = missingLiuQin.indexOf(liuQin);
5772
- if (idx > -1) {
5773
- missingLiuQin.splice(idx, 1);
5774
- }
5775
- }
5973
+ const liuQin = wuXingToLiuQin(wuXing, sourcePalaceWuXing);
5974
+ const hostYao = yaoList[i];
5975
+ fuShenList.push({
5976
+ fuLiuQin: liuQin,
5977
+ fuNaJia: naJia,
5978
+ fuWuXing: wuXing,
5979
+ hostYaoIndex: i,
5980
+ hostNaJia: hostYao.naJia,
5981
+ feiWuXing: hostYao.wuXing,
5982
+ relation: getWuXingRelation(wuXing, hostYao.wuXing)
5983
+ });
5776
5984
  }
5777
- return fuShenList.length > 0 ? fuShenList : void 0;
5985
+ return fuShenList;
5778
5986
  }
5779
5987
  function buildExplanation(yaoString, benGuaName, zhiGuaName, benGuaCi, zhiGuaCi, yaoCi) {
5780
5988
  const dongCount = countMovingYao(yaoString);
@@ -5821,7 +6029,17 @@ function decodePan(yaoString, options) {
5821
6029
  const zhiYaoString = getZhiGua(yaoString);
5822
6030
  const zhiGua = decodeGua(zhiYaoString, dayGZ, true);
5823
6031
  const huYaoString = getHuGua(yaoString);
5824
- const huGua = decodeGua(huYaoString, dayGZ, true);
6032
+ const huGua = decodeGua(huYaoString, dayGZ, true, false);
6033
+ const shenSha = buildShenShaMap(
6034
+ lunar.dayGanZhi.tian,
6035
+ lunar.dayGanZhi.di,
6036
+ lunar.monthGanZhi.di,
6037
+ [
6038
+ { guaKey: "benGua", yaoList: benGua.yaoList },
6039
+ { guaKey: "zhiGua", yaoList: zhiGua.yaoList },
6040
+ { guaKey: "huGua", yaoList: huGua.yaoList }
6041
+ ]
6042
+ );
5825
6043
  const dongYaoCount = countMovingYao(yaoString);
5826
6044
  const explanation = buildExplanation(
5827
6045
  yaoString,
@@ -5847,6 +6065,7 @@ function decodePan(yaoString, options) {
5847
6065
  dayKong,
5848
6066
  hourKong,
5849
6067
  monthJian,
6068
+ shenSha,
5850
6069
  benGua,
5851
6070
  zhiGua,
5852
6071
  huGua,
@@ -5896,6 +6115,7 @@ exports.JIAZI_60 = JIAZI_60;
5896
6115
  exports.JIEQI_NAMES = JIEQI_NAMES;
5897
6116
  exports.LIU_QIN = LIU_QIN;
5898
6117
  exports.LIU_SHOU = LIU_SHOU;
6118
+ exports.NAYIN_60 = NAYIN_60;
5899
6119
  exports.TIAN_GAN = TIAN_GAN;
5900
6120
  exports.WU_XING = WU_XING;
5901
6121
  exports.WU_XING_STARS = WU_XING_STARS;
@@ -5911,6 +6131,7 @@ exports.getGuaName = getGuaName;
5911
6131
  exports.getHourGanZhi = getHourGanZhi;
5912
6132
  exports.getHuGua = getHuGua;
5913
6133
  exports.getMovingYaoPositions = getMovingYaoPositions;
6134
+ exports.getNaYin = getNaYin;
5914
6135
  exports.getWuXingRelation = getWuXingRelation;
5915
6136
  exports.getZhiGua = getZhiGua;
5916
6137
  exports.isMovingYao = isMovingYao;