mingyu-core 0.1.7 → 0.1.9

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.
Files changed (200) hide show
  1. package/README.md +11 -3
  2. package/dist/bazi/baziAnalysis.d.ts.map +1 -1
  3. package/dist/bazi/baziAnalysis.js +0 -2
  4. package/dist/bazi/baziAnalysis.js.map +1 -1
  5. package/dist/bazi/baziAnalysisFormatter.d.ts.map +1 -1
  6. package/dist/bazi/baziAnalysisFormatter.js +9 -0
  7. package/dist/bazi/baziAnalysisFormatter.js.map +1 -1
  8. package/dist/bazi/baziCalculator.d.ts.map +1 -1
  9. package/dist/bazi/baziCalculator.js +61 -3
  10. package/dist/bazi/baziCalculator.js.map +1 -1
  11. package/dist/bazi/baziConditionMatchers/branchMatchers.d.ts +1 -0
  12. package/dist/bazi/baziConditionMatchers/branchMatchers.d.ts.map +1 -1
  13. package/dist/bazi/baziConditionMatchers/branchMatchers.js +13 -1
  14. package/dist/bazi/baziConditionMatchers/branchMatchers.js.map +1 -1
  15. package/dist/bazi/baziConditionMatchers/index.d.ts.map +1 -1
  16. package/dist/bazi/baziConditionMatchers/index.js +4 -2
  17. package/dist/bazi/baziConditionMatchers/index.js.map +1 -1
  18. package/dist/bazi/baziConditionMatchers/stemMatchers.d.ts +1 -0
  19. package/dist/bazi/baziConditionMatchers/stemMatchers.d.ts.map +1 -1
  20. package/dist/bazi/baziConditionMatchers/stemMatchers.js +7 -3
  21. package/dist/bazi/baziConditionMatchers/stemMatchers.js.map +1 -1
  22. package/dist/bazi/baziEnhancement/classicPatterns.d.ts.map +1 -1
  23. package/dist/bazi/baziEnhancement/classicPatterns.js +31 -11
  24. package/dist/bazi/baziEnhancement/classicPatterns.js.map +1 -1
  25. package/dist/bazi/baziPromptEnhancement.d.ts.map +1 -1
  26. package/dist/bazi/baziPromptEnhancement.js +49 -0
  27. package/dist/bazi/baziPromptEnhancement.js.map +1 -1
  28. package/dist/bazi/baziShenSha/helpers/dayRules.d.ts +0 -3
  29. package/dist/bazi/baziShenSha/helpers/dayRules.d.ts.map +1 -1
  30. package/dist/bazi/baziShenSha/helpers/dayRules.js +101 -56
  31. package/dist/bazi/baziShenSha/helpers/dayRules.js.map +1 -1
  32. package/dist/bazi/baziShenSha/helpers/disasterRules.d.ts +0 -3
  33. package/dist/bazi/baziShenSha/helpers/disasterRules.d.ts.map +1 -1
  34. package/dist/bazi/baziShenSha/helpers/disasterRules.js +745 -23
  35. package/dist/bazi/baziShenSha/helpers/disasterRules.js.map +1 -1
  36. package/dist/bazi/baziShenSha/helpers/globalRules.d.ts +0 -6
  37. package/dist/bazi/baziShenSha/helpers/globalRules.d.ts.map +1 -1
  38. package/dist/bazi/baziShenSha/helpers/globalRules.js +48 -16
  39. package/dist/bazi/baziShenSha/helpers/globalRules.js.map +1 -1
  40. package/dist/bazi/baziShenSha/helpers/luRules.d.ts +0 -3
  41. package/dist/bazi/baziShenSha/helpers/luRules.d.ts.map +1 -1
  42. package/dist/bazi/baziShenSha/helpers/luRules.js +266 -37
  43. package/dist/bazi/baziShenSha/helpers/luRules.js.map +1 -1
  44. package/dist/bazi/baziShenSha/helpers/marriageRules.d.ts +0 -3
  45. package/dist/bazi/baziShenSha/helpers/marriageRules.d.ts.map +1 -1
  46. package/dist/bazi/baziShenSha/helpers/marriageRules.js +5 -7
  47. package/dist/bazi/baziShenSha/helpers/marriageRules.js.map +1 -1
  48. package/dist/bazi/baziShenSha/helpers/nobleRules.d.ts +0 -3
  49. package/dist/bazi/baziShenSha/helpers/nobleRules.d.ts.map +1 -1
  50. package/dist/bazi/baziShenSha/helpers/nobleRules.js +208 -41
  51. package/dist/bazi/baziShenSha/helpers/nobleRules.js.map +1 -1
  52. package/dist/bazi/baziShenSha/helpers/tenGodAnalysis.d.ts +0 -4
  53. package/dist/bazi/baziShenSha/helpers/tenGodAnalysis.d.ts.map +1 -1
  54. package/dist/bazi/baziShenSha/helpers/tenGodAnalysis.js +0 -8
  55. package/dist/bazi/baziShenSha/helpers/tenGodAnalysis.js.map +1 -1
  56. package/dist/bazi/baziShenSha/index.d.ts +0 -20
  57. package/dist/bazi/baziShenSha/index.d.ts.map +1 -1
  58. package/dist/bazi/baziShenSha/index.js +0 -20
  59. package/dist/bazi/baziShenSha/index.js.map +1 -1
  60. package/dist/bazi/baziShenSha/variants.d.ts +0 -3
  61. package/dist/bazi/baziShenSha/variants.d.ts.map +1 -1
  62. package/dist/bazi/baziShenSha/variants.js.map +1 -1
  63. package/dist/bazi/baziShenShaData.d.ts +0 -20
  64. package/dist/bazi/baziShenShaData.d.ts.map +1 -1
  65. package/dist/bazi/baziShenShaData.js +286 -34
  66. package/dist/bazi/baziShenShaData.js.map +1 -1
  67. package/dist/bazi/baziStrengthAnalyzer.d.ts.map +1 -1
  68. package/dist/bazi/baziStrengthAnalyzer.js +8 -9
  69. package/dist/bazi/baziStrengthAnalyzer.js.map +1 -1
  70. package/dist/bazi/baziTypes.d.ts +16 -0
  71. package/dist/bazi/baziTypes.d.ts.map +1 -1
  72. package/dist/bazi/baziTypes.js.map +1 -1
  73. package/dist/bazi/chinaDst.d.ts +36 -0
  74. package/dist/bazi/chinaDst.d.ts.map +1 -0
  75. package/dist/bazi/chinaDst.js +86 -0
  76. package/dist/bazi/chinaDst.js.map +1 -0
  77. package/dist/bazi/harmonyTransform.d.ts +16 -0
  78. package/dist/bazi/harmonyTransform.d.ts.map +1 -0
  79. package/dist/bazi/harmonyTransform.js +285 -0
  80. package/dist/bazi/harmonyTransform.js.map +1 -0
  81. package/dist/bazi/index.d.ts +6 -0
  82. package/dist/bazi/index.d.ts.map +1 -1
  83. package/dist/bazi/index.js +3 -1
  84. package/dist/bazi/index.js.map +1 -1
  85. package/dist/bazi/lifeStageAnalysis.d.ts.map +1 -1
  86. package/dist/bazi/lifeStageAnalysis.js +0 -3
  87. package/dist/bazi/lifeStageAnalysis.js.map +1 -1
  88. package/dist/bazi/nayinAnalysis.d.ts.map +1 -1
  89. package/dist/bazi/nayinAnalysis.js +0 -1
  90. package/dist/bazi/nayinAnalysis.js.map +1 -1
  91. package/dist/bazi/paipanWarnings.d.ts +25 -0
  92. package/dist/bazi/paipanWarnings.d.ts.map +1 -0
  93. package/dist/bazi/paipanWarnings.js +124 -0
  94. package/dist/bazi/paipanWarnings.js.map +1 -0
  95. package/dist/bazi/relationStructure.d.ts.map +1 -1
  96. package/dist/bazi/relationStructure.js +0 -4
  97. package/dist/bazi/relationStructure.js.map +1 -1
  98. package/dist/bazi/stemRootAnalysis.d.ts.map +1 -1
  99. package/dist/bazi/stemRootAnalysis.js +26 -16
  100. package/dist/bazi/stemRootAnalysis.js.map +1 -1
  101. package/dist/bazi/usefulGodPlacement.d.ts.map +1 -1
  102. package/dist/bazi/usefulGodPlacement.js +0 -2
  103. package/dist/bazi/usefulGodPlacement.js.map +1 -1
  104. package/dist/divination/algorithms/_shared/index.d.ts +1 -1
  105. package/dist/divination/algorithms/_shared/index.d.ts.map +1 -1
  106. package/dist/divination/algorithms/_shared/index.js +1 -1
  107. package/dist/divination/algorithms/_shared/index.js.map +1 -1
  108. package/dist/divination/algorithms/_shared/wuxing.d.ts +9 -8
  109. package/dist/divination/algorithms/_shared/wuxing.d.ts.map +1 -1
  110. package/dist/divination/algorithms/_shared/wuxing.js +40 -18
  111. package/dist/divination/algorithms/_shared/wuxing.js.map +1 -1
  112. package/dist/divination/algorithms/almanac.d.ts +2 -2
  113. package/dist/divination/algorithms/almanac.d.ts.map +1 -1
  114. package/dist/divination/algorithms/almanac.js +197 -32
  115. package/dist/divination/algorithms/almanac.js.map +1 -1
  116. package/dist/divination/algorithms/lenormand.js +2 -2
  117. package/dist/divination/algorithms/liuren/helpers/lessons.d.ts.map +1 -1
  118. package/dist/divination/algorithms/liuren/helpers/lessons.js +11 -7
  119. package/dist/divination/algorithms/liuren/helpers/lessons.js.map +1 -1
  120. package/dist/divination/algorithms/liuren/helpers/transmission.d.ts +6 -0
  121. package/dist/divination/algorithms/liuren/helpers/transmission.d.ts.map +1 -1
  122. package/dist/divination/algorithms/liuren/helpers/transmission.js +38 -0
  123. package/dist/divination/algorithms/liuren/helpers/transmission.js.map +1 -1
  124. package/dist/divination/algorithms/liuren/index.d.ts.map +1 -1
  125. package/dist/divination/algorithms/liuren/index.js +17 -14
  126. package/dist/divination/algorithms/liuren/index.js.map +1 -1
  127. package/dist/divination/algorithms/liuyao.d.ts +57 -0
  128. package/dist/divination/algorithms/liuyao.d.ts.map +1 -1
  129. package/dist/divination/algorithms/liuyao.js +221 -50
  130. package/dist/divination/algorithms/liuyao.js.map +1 -1
  131. package/dist/divination/algorithms/meihua/helpers/methods.d.ts +2 -2
  132. package/dist/divination/algorithms/meihua/helpers/methods.d.ts.map +1 -1
  133. package/dist/divination/algorithms/meihua/helpers/methods.js +47 -7
  134. package/dist/divination/algorithms/meihua/helpers/methods.js.map +1 -1
  135. package/dist/divination/algorithms/meihua/index.d.ts.map +1 -1
  136. package/dist/divination/algorithms/meihua/index.js +22 -15
  137. package/dist/divination/algorithms/meihua/index.js.map +1 -1
  138. package/dist/divination/algorithms/qimen/helpers/_constants.d.ts +2 -4
  139. package/dist/divination/algorithms/qimen/helpers/_constants.d.ts.map +1 -1
  140. package/dist/divination/algorithms/qimen/helpers/_constants.js +3 -5
  141. package/dist/divination/algorithms/qimen/helpers/_constants.js.map +1 -1
  142. package/dist/divination/algorithms/qimen/helpers/classic-patterns.d.ts +15 -7
  143. package/dist/divination/algorithms/qimen/helpers/classic-patterns.d.ts.map +1 -1
  144. package/dist/divination/algorithms/qimen/helpers/classic-patterns.js +814 -127
  145. package/dist/divination/algorithms/qimen/helpers/classic-patterns.js.map +1 -1
  146. package/dist/divination/algorithms/qimen/helpers/directions.d.ts +4 -3
  147. package/dist/divination/algorithms/qimen/helpers/directions.d.ts.map +1 -1
  148. package/dist/divination/algorithms/qimen/helpers/directions.js +16 -9
  149. package/dist/divination/algorithms/qimen/helpers/directions.js.map +1 -1
  150. package/dist/divination/algorithms/qimen/helpers/jushu-extended.d.ts +7 -6
  151. package/dist/divination/algorithms/qimen/helpers/jushu-extended.d.ts.map +1 -1
  152. package/dist/divination/algorithms/qimen/helpers/jushu-extended.js +55 -24
  153. package/dist/divination/algorithms/qimen/helpers/jushu-extended.js.map +1 -1
  154. package/dist/divination/algorithms/qimen/helpers/jushu.d.ts +20 -13
  155. package/dist/divination/algorithms/qimen/helpers/jushu.d.ts.map +1 -1
  156. package/dist/divination/algorithms/qimen/helpers/jushu.js +96 -61
  157. package/dist/divination/algorithms/qimen/helpers/jushu.js.map +1 -1
  158. package/dist/divination/algorithms/qimen/helpers/layout.d.ts +1 -1
  159. package/dist/divination/algorithms/qimen/helpers/layout.d.ts.map +1 -1
  160. package/dist/divination/algorithms/qimen/helpers/layout.js +18 -24
  161. package/dist/divination/algorithms/qimen/helpers/layout.js.map +1 -1
  162. package/dist/divination/algorithms/qimen/helpers/pattern-combos.d.ts +40 -0
  163. package/dist/divination/algorithms/qimen/helpers/pattern-combos.d.ts.map +1 -0
  164. package/dist/divination/algorithms/qimen/helpers/pattern-combos.js +1799 -0
  165. package/dist/divination/algorithms/qimen/helpers/pattern-combos.js.map +1 -0
  166. package/dist/divination/algorithms/qimen/helpers/patterns.d.ts +6 -5
  167. package/dist/divination/algorithms/qimen/helpers/patterns.d.ts.map +1 -1
  168. package/dist/divination/algorithms/qimen/helpers/patterns.js +74 -22
  169. package/dist/divination/algorithms/qimen/helpers/patterns.js.map +1 -1
  170. package/dist/divination/algorithms/qimen/helpers/seasonality.d.ts +1 -1
  171. package/dist/divination/algorithms/qimen/helpers/seasonality.d.ts.map +1 -1
  172. package/dist/divination/algorithms/qimen/helpers/stem-pair-patterns.d.ts +8 -1
  173. package/dist/divination/algorithms/qimen/helpers/stem-pair-patterns.d.ts.map +1 -1
  174. package/dist/divination/algorithms/qimen/helpers/stem-pair-patterns.js +731 -67
  175. package/dist/divination/algorithms/qimen/helpers/stem-pair-patterns.js.map +1 -1
  176. package/dist/divination/algorithms/qimen/helpers/ying-qi.d.ts +10 -6
  177. package/dist/divination/algorithms/qimen/helpers/ying-qi.d.ts.map +1 -1
  178. package/dist/divination/algorithms/qimen/helpers/ying-qi.js +58 -25
  179. package/dist/divination/algorithms/qimen/helpers/ying-qi.js.map +1 -1
  180. package/dist/divination/algorithms/qimen/index.d.ts.map +1 -1
  181. package/dist/divination/algorithms/qimen/index.js +112 -21
  182. package/dist/divination/algorithms/qimen/index.js.map +1 -1
  183. package/dist/divination/algorithms/xiaoliuren.d.ts +1 -1
  184. package/dist/divination/algorithms/xiaoliuren.js +12 -12
  185. package/dist/divination/algorithms/xiaoliuren.js.map +1 -1
  186. package/dist/divination/divination-data.d.ts.map +1 -1
  187. package/dist/divination/divination-data.js +2 -4
  188. package/dist/divination/divination-data.js.map +1 -1
  189. package/dist/types/analysis.d.ts +21 -0
  190. package/dist/types/analysis.d.ts.map +1 -1
  191. package/dist/types/divination.d.ts +84 -2
  192. package/dist/types/divination.d.ts.map +1 -1
  193. package/dist/ziwei/iztro/build-analysis-payload/index.d.ts.map +1 -1
  194. package/dist/ziwei/iztro/build-analysis-payload/index.js +7 -1
  195. package/dist/ziwei/iztro/build-analysis-payload/index.js.map +1 -1
  196. package/dist/ziwei/iztro/pattern-detection.d.ts +4 -2
  197. package/dist/ziwei/iztro/pattern-detection.d.ts.map +1 -1
  198. package/dist/ziwei/iztro/pattern-detection.js +1300 -184
  199. package/dist/ziwei/iztro/pattern-detection.js.map +1 -1
  200. package/package.json +1 -1
@@ -9,8 +9,8 @@
9
9
  * - 优先级评分越高(0-100),格局越典型
10
10
  *
11
11
  * 格局体系:
12
- * - 吉格:紫府同宫/日月并明/科权禄拱命/月朗天门/日照雷门/禄马交驰/武贪同行/火贪/铃贪/阳梁昌禄等
13
- * - 凶格:羊陀夹忌/火铃夹命/刑囚夹印/巨火擎羊/马头带箭/空劫夹命/铃昌陀武等
12
+ * - 吉格:紫府同宫/紫府夹命/日月并明/日月夹命/日月夹财/日月照璧/辅弼拱主/左右夹命/左右朝垣/魁钺同行/昌曲夹命/文星朝命/玉袖天香/蟾宫折桂/左辅文昌/坐贵向贵/金舆扶驾/科权禄拱命/仰面朝斗/月朗天门/水澄桂萼/日照雷门/日出扶桑/皇殿朝班/天梁居午/对面朝斗/兼文武/文昌武曲/荫印拱身/禄马交驰/禄马佩印/财禄夹马/财印夹禄/财居财位/紫禄同宫/巨机居卯/雄宿朝元/机梁加吉/梁昌庙旺/曲遇梁星/廉杀庙旺/紫破加吉/破军子午/武曲守垣/武贪同行/火贪/贪火相逢/铃贪/权禄生逢/羊刃入庙/阳梁昌禄等
13
+ * - 凶格:羊陀夹忌/火铃夹命/刑囚夹印/财与囚仇/泛水桃花/廉杀巳亥/一生孤贫/君子在野/生不逢时/禄逢两杀/马落空亡/日月藏辉/巨火擎羊/马头带箭/空劫夹命/两重华盖/铃昌陀武等
14
14
  * - 平格:杀破狼/日月反背/天罗地网/巨日同宫/武贪同行等
15
15
  */
16
16
  function normalizePalaceName(name) {
@@ -25,6 +25,9 @@ function hasStar(palace, starName) {
25
25
  function hasAllStars(palace, names) {
26
26
  return names.every((name) => hasStar(palace, name));
27
27
  }
28
+ function hasSingleMajorStar(palace, starName) {
29
+ return palace.major_stars.length === 1 && palace.major_stars[0]?.name === starName;
30
+ }
28
31
  /** 检查宫位中是否存在某生年星(scope 为 origin) */
29
32
  function hasOriginStar(palace, starName) {
30
33
  return getAllStars(palace).some((star) => star.name === starName && star.scope === 'origin');
@@ -41,6 +44,10 @@ function getSurroundedStars(context, palace) {
41
44
  });
42
45
  return Array.from(seen);
43
46
  }
47
+ function getSurroundedMatchedStarNames(context, palace, starNames) {
48
+ const present = new Set(getSurroundedStars(context, palace));
49
+ return starNames.filter((starName) => present.has(starName));
50
+ }
44
51
  function getSurroundedMutagens(context, palace, key) {
45
52
  const seen = new Set();
46
53
  getSurroundedPalaces(context, palace).forEach((target) => {
@@ -63,6 +70,9 @@ function surroundedHasOneOf(context, palace, stars) {
63
70
  function getPalaceByName(context, name) {
64
71
  return context.palaceByName.get(normalizePalaceName(name));
65
72
  }
73
+ function palaceInBranch(palace, branches) {
74
+ return branches.includes(palace.earthly_branch);
75
+ }
66
76
  function getOppositePalace(context, palace) {
67
77
  return context.palaceByIndex.get(palace.opposite_palace_index);
68
78
  }
@@ -74,6 +84,72 @@ function getNeighborPalaces(context, palace) {
74
84
  next: context.palaceByIndex.get(nextIndex),
75
85
  };
76
86
  }
87
+ const BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
88
+ const DAYTIME_BRANCHES = new Set(['卯', '辰', '巳', '午', '未', '申']);
89
+ const FOUR_MALEFICS = ['擎羊', '陀罗', '火星', '铃星'];
90
+ const VOID_STARS = ['空亡', '旬空', '天空', '截空', '截路', '截路空亡'];
91
+ const KONG_JIE_STARS = ['地空', '地劫'];
92
+ const AUSPICIOUS_SUPPORT_STARS = ['左辅', '右弼', '文昌', '文曲', '天魁', '天钺', '禄存'];
93
+ const TEMPLE_OR_PROSPEROUS_BRIGHTNESS = ['庙', '旺'];
94
+ function getMatchedStarNames(palace, starNames) {
95
+ const present = new Set(getAllStars(palace).map((star) => star.name));
96
+ return starNames.filter((starName) => present.has(starName));
97
+ }
98
+ function getVoidStars(palace) {
99
+ return getMatchedStarNames(palace, VOID_STARS);
100
+ }
101
+ function hasVoidStar(palace) {
102
+ return getVoidStars(palace).length > 0;
103
+ }
104
+ function getStarFact(palace, starName) {
105
+ return getAllStars(palace).find((star) => star.name === starName);
106
+ }
107
+ function isTempleOrProsperous(star) {
108
+ return !!star?.brightness && TEMPLE_OR_PROSPEROUS_BRIGHTNESS.includes(star.brightness);
109
+ }
110
+ function getTempleOrProsperousBirthMutagenStars(palace, mutagen) {
111
+ return getAllStars(palace).filter((star) => star.birth_mutagen === mutagen && isTempleOrProsperous(star));
112
+ }
113
+ function getKongJieStars(palace) {
114
+ return getMatchedStarNames(palace, KONG_JIE_STARS);
115
+ }
116
+ function getAuspiciousSupportStars(palace) {
117
+ const supportStars = getMatchedStarNames(palace, AUSPICIOUS_SUPPORT_STARS);
118
+ const mutagens = getAllStars(palace)
119
+ .map((star) => star.birth_mutagen)
120
+ .filter((mutagen) => !!mutagen && mutagen !== '忌')
121
+ .map((mutagen) => `化${mutagen}`);
122
+ return Array.from(new Set([...supportStars, ...mutagens]));
123
+ }
124
+ function hasBirthJiOrTianXing(palace) {
125
+ return hasStar(palace, '天刑') || getAllStars(palace).some((star) => star.birth_mutagen === '忌');
126
+ }
127
+ function extractBranchFromText(value) {
128
+ if (!value)
129
+ return undefined;
130
+ return BRANCHES.find((branch) => value.includes(branch));
131
+ }
132
+ function extractStartHour(value) {
133
+ if (!value)
134
+ return undefined;
135
+ const match = /(\d{1,2}):\d{2}/.exec(value);
136
+ if (!match)
137
+ return undefined;
138
+ const hour = Number(match[1]);
139
+ return Number.isInteger(hour) && hour >= 0 && hour <= 23 ? hour : undefined;
140
+ }
141
+ function isDaytimeBirth(context) {
142
+ const branch = extractBranchFromText(context.birthTimeLabel);
143
+ if (branch) {
144
+ return DAYTIME_BRANCHES.has(branch);
145
+ }
146
+ const startHour = extractStartHour(context.birthTimeRange);
147
+ return startHour !== undefined && startHour >= 5 && startHour < 17;
148
+ }
149
+ function isRiYueFanBei(palace) {
150
+ return ((palaceInBranch(palace, ['戌']) && hasStar(palace, '太阳')) ||
151
+ (palaceInBranch(palace, ['辰']) && hasStar(palace, '太阴')));
152
+ }
77
153
  const PATTERN_RULES = [
78
154
  {
79
155
  id: 'ziwei-tianfu-tonggong',
@@ -91,6 +167,27 @@ const PATTERN_RULES = [
91
167
  return null;
92
168
  },
93
169
  },
170
+ {
171
+ id: 'zi-fu-jia-ming',
172
+ name: '紫府夹命',
173
+ kind: 'auspicious',
174
+ description: '命宫被紫微与天府一前一后夹拱,主贵气扶持、格局厚重。',
175
+ priority: 88,
176
+ detect(context) {
177
+ const ming = getPalaceByName(context, '命宫');
178
+ if (!ming)
179
+ return null;
180
+ const { prev, next } = getNeighborPalaces(context, ming);
181
+ if (!prev || !next)
182
+ return null;
183
+ const isFlanked = (hasStar(prev, '紫微') && hasStar(next, '天府')) ||
184
+ (hasStar(prev, '天府') && hasStar(next, '紫微'));
185
+ if (isFlanked) {
186
+ return { palaces: [ming, prev, next], stars: ['紫微', '天府'] };
187
+ }
188
+ return null;
189
+ },
190
+ },
94
191
  {
95
192
  id: 'sha-po-lang',
96
193
  name: '杀破狼',
@@ -112,12 +209,14 @@ const PATTERN_RULES = [
112
209
  id: 'ji-yue-tong-liang',
113
210
  name: '机月同梁',
114
211
  kind: 'auspicious',
115
- description: '命宫三方四正见天机、太阴、天同、天梁,主温和稳健、适合稳定型职业。',
212
+ description: '寅申命宫三方四正见天机、太阴、天同、天梁,主温和稳健、适合稳定型职业。',
116
213
  priority: 86,
117
214
  detect(context) {
118
215
  const ming = getPalaceByName(context, '命宫');
119
216
  if (!ming)
120
217
  return null;
218
+ if (!palaceInBranch(ming, ['寅', '申']))
219
+ return null;
121
220
  const required = ['天机', '太阴', '天同', '天梁'];
122
221
  if (surroundedHasAll(context, ming, required)) {
123
222
  return { palaces: [ming], stars: required };
@@ -141,6 +240,165 @@ const PATTERN_RULES = [
141
240
  return null;
142
241
  },
143
242
  },
243
+ {
244
+ id: 'fu-bi-gong-zhu',
245
+ name: '辅弼拱主',
246
+ kind: 'auspicious',
247
+ description: '紫微守命,左辅右弼三方来拱或左右夹命,主得助力、贵人扶持。',
248
+ priority: 87,
249
+ detect(context) {
250
+ const ming = getPalaceByName(context, '命宫');
251
+ if (!ming || !hasStar(ming, '紫微'))
252
+ return null;
253
+ const { prev, next } = getNeighborPalaces(context, ming);
254
+ const isJiaMing = !!prev &&
255
+ !!next &&
256
+ ((hasStar(prev, '左辅') && hasStar(next, '右弼')) ||
257
+ (hasStar(prev, '右弼') && hasStar(next, '左辅')));
258
+ if (isJiaMing) {
259
+ return { palaces: [ming, prev, next], stars: ['紫微', '左辅', '右弼'] };
260
+ }
261
+ const gongPalaces = getSurroundedPalaces(context, ming).filter((palace) => palace.index !== ming.index);
262
+ const hasZuoFu = gongPalaces.some((palace) => hasStar(palace, '左辅'));
263
+ const hasYouBi = gongPalaces.some((palace) => hasStar(palace, '右弼'));
264
+ if (hasZuoFu && hasYouBi) {
265
+ const palaces = [
266
+ ming,
267
+ ...gongPalaces.filter((palace) => hasStar(palace, '左辅') || hasStar(palace, '右弼')),
268
+ ];
269
+ return { palaces, stars: ['紫微', '左辅', '右弼'] };
270
+ }
271
+ return null;
272
+ },
273
+ },
274
+ {
275
+ id: 'zuo-fu-wen-chang',
276
+ name: '左辅文昌',
277
+ kind: 'auspicious',
278
+ description: '左辅、文昌同守命宫,主才名得助、台辅相扶。',
279
+ priority: 87,
280
+ detect(context) {
281
+ const ming = getPalaceByName(context, '命宫');
282
+ if (!ming)
283
+ return null;
284
+ if (hasAllStars(ming, ['左辅', '文昌'])) {
285
+ return { palaces: [ming], stars: ['左辅', '文昌'] };
286
+ }
287
+ return null;
288
+ },
289
+ },
290
+ {
291
+ id: 'kui-yue-tong-xing',
292
+ name: '魁钺同行',
293
+ kind: 'auspicious',
294
+ description: '天魁、天钺同守命宫,主得贵人台辅、科名助力。',
295
+ priority: 88,
296
+ detect(context) {
297
+ const ming = getPalaceByName(context, '命宫');
298
+ if (!ming)
299
+ return null;
300
+ if (hasAllStars(ming, ['天魁', '天钺'])) {
301
+ return { palaces: [ming], stars: ['天魁', '天钺'] };
302
+ }
303
+ return null;
304
+ },
305
+ },
306
+ {
307
+ id: 'kui-yue-jia-ming',
308
+ name: '魁钺夹命',
309
+ kind: 'auspicious',
310
+ description: '命宫被天魁与天钺一前一后夹拱,主得贵人扶助、科名机缘。',
311
+ priority: 86,
312
+ detect(context) {
313
+ const ming = getPalaceByName(context, '命宫');
314
+ if (!ming)
315
+ return null;
316
+ const { prev, next } = getNeighborPalaces(context, ming);
317
+ if (!prev || !next)
318
+ return null;
319
+ const isFlanked = (hasStar(prev, '天魁') && hasStar(next, '天钺')) ||
320
+ (hasStar(prev, '天钺') && hasStar(next, '天魁'));
321
+ if (isFlanked) {
322
+ return { palaces: [ming, prev, next], stars: ['天魁', '天钺'] };
323
+ }
324
+ return null;
325
+ },
326
+ },
327
+ {
328
+ id: 'chang-qu-jia-ming',
329
+ name: '昌曲夹命',
330
+ kind: 'auspicious',
331
+ description: '命宫被文昌与文曲一前一后夹拱,主文名才学、不贵即富。',
332
+ priority: 86,
333
+ detect(context) {
334
+ const ming = getPalaceByName(context, '命宫');
335
+ if (!ming)
336
+ return null;
337
+ const { prev, next } = getNeighborPalaces(context, ming);
338
+ if (!prev || !next)
339
+ return null;
340
+ const isFlanked = (hasStar(prev, '文昌') && hasStar(next, '文曲')) ||
341
+ (hasStar(prev, '文曲') && hasStar(next, '文昌'));
342
+ if (isFlanked) {
343
+ return { palaces: [ming, prev, next], stars: ['文昌', '文曲'] };
344
+ }
345
+ return null;
346
+ },
347
+ },
348
+ {
349
+ id: 'yu-xiu-tian-xiang',
350
+ name: '玉袖天香',
351
+ kind: 'auspicious',
352
+ description: '文昌、文曲同居福德宫,主福德文曜相扶、才名清雅。',
353
+ priority: 86,
354
+ detect(context) {
355
+ const fuDe = getPalaceByName(context, '福德');
356
+ if (!fuDe)
357
+ return null;
358
+ if (hasAllStars(fuDe, ['文昌', '文曲'])) {
359
+ return { palaces: [fuDe], stars: ['文昌', '文曲'] };
360
+ }
361
+ return null;
362
+ },
363
+ },
364
+ {
365
+ id: 'chan-gong-zhe-gui',
366
+ name: '蟾宫折桂',
367
+ kind: 'auspicious',
368
+ description: '太阴同文昌或文曲居夫妻宫,主因配偶宫得文曜月华相扶。',
369
+ priority: 86,
370
+ detect(context) {
371
+ const spouse = getPalaceByName(context, '夫妻');
372
+ if (!spouse || !hasStar(spouse, '太阴'))
373
+ return null;
374
+ const literaryStars = getMatchedStarNames(spouse, ['文昌', '文曲']);
375
+ if (literaryStars.length > 0) {
376
+ return { palaces: [spouse], stars: ['太阴', ...literaryStars] };
377
+ }
378
+ return null;
379
+ },
380
+ },
381
+ {
382
+ id: 'zuo-gui-xiang-gui',
383
+ name: '坐贵向贵',
384
+ kind: 'auspicious',
385
+ description: '天魁或天钺坐命,另一贵星在对宫拱照,主贵人扶助、声名科第。',
386
+ priority: 85,
387
+ detect(context) {
388
+ const ming = getPalaceByName(context, '命宫');
389
+ if (!ming)
390
+ return null;
391
+ const opposite = getOppositePalace(context, ming);
392
+ if (!opposite)
393
+ return null;
394
+ const isZuoXiang = (hasStar(ming, '天魁') && hasStar(opposite, '天钺')) ||
395
+ (hasStar(ming, '天钺') && hasStar(opposite, '天魁'));
396
+ if (isZuoXiang) {
397
+ return { palaces: [ming, opposite], stars: ['天魁', '天钺'] };
398
+ }
399
+ return null;
400
+ },
401
+ },
144
402
  {
145
403
  id: 'ri-yue-bing-ming',
146
404
  name: '日月并明',
@@ -157,6 +415,30 @@ const PATTERN_RULES = [
157
415
  return null;
158
416
  },
159
417
  },
418
+ {
419
+ id: 'ri-yue-jia-ming',
420
+ name: '日月夹命',
421
+ kind: 'auspicious',
422
+ description: '命宫不坐空亡,有吉曜坐守,前后由太阳、太阴夹命,主不权则富。',
423
+ priority: 87,
424
+ detect(context) {
425
+ const ming = getPalaceByName(context, '命宫');
426
+ if (!ming || hasVoidStar(ming))
427
+ return null;
428
+ const supportStars = getAuspiciousSupportStars(ming);
429
+ if (supportStars.length === 0)
430
+ return null;
431
+ const { prev, next } = getNeighborPalaces(context, ming);
432
+ if (!prev || !next)
433
+ return null;
434
+ const isFlanked = (hasStar(prev, '太阳') && hasStar(next, '太阴')) ||
435
+ (hasStar(prev, '太阴') && hasStar(next, '太阳'));
436
+ if (isFlanked) {
437
+ return { palaces: [ming, prev, next], stars: ['太阳', '太阴', ...supportStars] };
438
+ }
439
+ return null;
440
+ },
441
+ },
160
442
  {
161
443
  id: 'ke-quan-lu-gong-ming',
162
444
  name: '科权禄拱命',
@@ -211,8 +493,7 @@ const PATTERN_RULES = [
211
493
  return null;
212
494
  // 明禄暗禄:传统指禄存或生年化禄在命宫(明)和对宫(暗)对应,
213
495
  // 不含运限化禄——本命格局不应随大限/流年变化
214
- const mingHasLu = hasStar(ming, '禄存') ||
215
- getAllStars(ming).some((star) => star.birth_mutagen === '禄');
496
+ const mingHasLu = hasStar(ming, '禄存') || getAllStars(ming).some((star) => star.birth_mutagen === '禄');
216
497
  const oppositeHasLu = hasStar(opposite, '禄存') ||
217
498
  getAllStars(opposite).some((star) => star.birth_mutagen === '禄');
218
499
  if (mingHasLu && oppositeHasLu) {
@@ -282,256 +563,981 @@ const PATTERN_RULES = [
282
563
  const ming = getPalaceByName(context, '命宫');
283
564
  if (!ming)
284
565
  return null;
285
- if (ming.index === 11 && hasStar(ming, '太阴')) {
566
+ if (palaceInBranch(ming, ['亥']) && hasStar(ming, '太阴')) {
286
567
  return { palaces: [ming], stars: ['太阴'] };
287
568
  }
288
569
  return null;
289
570
  },
290
571
  },
291
572
  {
292
- id: 'ri-zhao-lei-men',
293
- name: '日照雷门',
573
+ id: 'shui-cheng-gui-e',
574
+ name: '水澄桂萼',
294
575
  kind: 'auspicious',
295
- description: '太阳坐命卯宫(震位/雷门),主少年得志、声名早显、富贵可期。卯为震卦日出之方,日居卯为旭日初升。',
576
+ description: '太阴守命子宫,主清要忠良、月华得位。',
296
577
  priority: 93,
297
578
  detect(context) {
298
579
  const ming = getPalaceByName(context, '命宫');
299
580
  if (!ming)
300
581
  return null;
301
- if (ming.index === 3 && hasStar(ming, '太阳')) {
302
- return { palaces: [ming], stars: ['太阳'] };
582
+ if (palaceInBranch(ming, ['子']) && hasStar(ming, '太阴')) {
583
+ return { palaces: [ming], stars: ['太阴'] };
303
584
  }
304
585
  return null;
305
586
  },
306
587
  },
307
588
  {
308
- id: 'lu-ma-jiao-chi',
309
- name: '禄马交驰',
589
+ id: 'yue-sheng-cang-hai',
590
+ name: '月生沧海',
310
591
  kind: 'auspicious',
311
- description: '命宫三方四正同时见禄存(或化禄)与天马,主财禄双美、动中得财。',
312
- priority: 90,
592
+ description: '太阴守田宅子宫,主田宅财资有根基。月在子宫守田宅是也。',
593
+ priority: 88,
313
594
  detect(context) {
314
- const ming = getPalaceByName(context, '命宫');
315
- if (!ming)
595
+ const tianZhai = getPalaceByName(context, '田宅');
596
+ if (!tianZhai)
316
597
  return null;
317
- const hasLu = surroundedHasOneOf(context, ming, ['禄存']);
318
- const luMutagen = getSurroundedMutagens(context, ming, 'birth_mutagen').includes('禄');
319
- const hasMa = surroundedHasOneOf(context, ming, ['天马']);
320
- if ((hasLu || luMutagen) && hasMa) {
321
- return { palaces: [ming], stars: ['禄存', '天马'] };
598
+ if (palaceInBranch(tianZhai, ['']) && hasStar(tianZhai, '太阴')) {
599
+ return { palaces: [tianZhai], stars: ['太阴'] };
322
600
  }
323
601
  return null;
324
602
  },
325
603
  },
326
604
  {
327
- id: 'cai-yin-jia-yin',
328
- name: '财荫夹印',
605
+ id: 'ri-zhao-lei-men',
606
+ name: '日照雷门',
329
607
  kind: 'auspicious',
330
- description: '天相(印)坐命宫或财帛宫,被天府(财星)与天梁(荫星)邻宫夹拱,主因财得官、富贵绵延。',
331
- priority: 88,
608
+ description: '太阳坐命子、辰、卯且昼生,主少年得志、声名早显、富贵可期。卯为震卦日出之方,日居雷门尤典型。',
609
+ priority: 93,
332
610
  detect(context) {
333
611
  const ming = getPalaceByName(context, '命宫');
334
612
  if (!ming)
335
613
  return null;
336
- const { prev, next } = getNeighborPalaces(context, ming);
337
- if (!prev || !next)
338
- return null;
339
- // 传统财荫夹印:天相(印)被天府(财星)与天梁(荫星)邻宫夹拱
340
- // 天府和天梁分居天相两侧,而非一则为天相、另一则为天府
341
- const hasXiang = hasStar(ming, '天相');
342
- const hasCaiOnLeft = hasStar(prev, '天府');
343
- const hasYinOnRight = hasStar(next, '天梁');
344
- const hasCaiOnRight = hasStar(next, '天府');
345
- const hasYinOnLeft = hasStar(prev, '天梁');
346
- const bothSides = (hasCaiOnLeft && hasYinOnRight) || (hasCaiOnRight && hasYinOnLeft);
347
- if (hasXiang && bothSides) {
348
- return { palaces: [ming, prev, next], stars: ['天相', '天府', '天梁'] };
614
+ if (palaceInBranch(ming, ['子', '辰', '卯']) &&
615
+ hasStar(ming, '太阳') &&
616
+ isDaytimeBirth(context)) {
617
+ return { palaces: [ming], stars: ['太阳'] };
349
618
  }
350
619
  return null;
351
620
  },
352
621
  },
353
622
  {
354
- id: 'ming-zhu-chu-hai',
355
- name: '明珠出海',
623
+ id: 'jin-can-guang-hui',
624
+ name: '金灿光辉',
356
625
  kind: 'auspicious',
357
- description: '命宫在未(命宫无主星借对宫天同巨门),三合方见日卯月亥,主光耀门楣、中年大展。',
358
- priority: 87,
626
+ description: '太阳单守午宫命宫,主光明显达。太阳单守,命在午宫是也。',
627
+ priority: 93,
359
628
  detect(context) {
360
629
  const ming = getPalaceByName(context, '命宫');
361
- const qian = getPalaceByName(context, '迁移');
362
- if (!ming || !qian)
363
- return null;
364
- if (ming.index !== 7)
630
+ if (!ming)
365
631
  return null;
366
- const mStars = getAllStars(ming);
367
- const hasSunMoonSurrounded = surroundedHasOneOf(context, ming, ['太阳']) && surroundedHasOneOf(context, ming, ['太阴']);
368
- if (mStars.length === 0 && hasSunMoonSurrounded) {
369
- return { palaces: [ming], stars: ['太阳', '太阴'] };
632
+ if (palaceInBranch(ming, ['午']) && hasSingleMajorStar(ming, '太阳')) {
633
+ return { palaces: [ming], stars: ['太阳'] };
370
634
  }
371
635
  return null;
372
636
  },
373
637
  },
374
638
  {
375
- id: 'xiong-su-qian-yuan',
376
- name: '雄宿乾元',
639
+ id: 'ri-chu-fu-sang',
640
+ name: '日出扶桑',
377
641
  kind: 'auspicious',
378
- description: '廉贞坐命亥宫(乾位),主刚毅果断、智勇双全。廉贞为雄宿,亥为乾元。',
379
- priority: 91,
642
+ description: '太阳在卯守命宫或官禄宫,主名誉显达。日在卯守命是也,守官禄宫亦然。',
643
+ priority: 92,
380
644
  detect(context) {
381
- const ming = getPalaceByName(context, '命宫');
382
- if (!ming)
383
- return null;
384
- if (ming.index === 11 && hasStar(ming, '廉贞')) {
385
- return { palaces: [ming], stars: ['廉贞'] };
645
+ const targets = [];
646
+ const addTarget = (palace) => {
647
+ if (palace &&
648
+ palaceInBranch(palace, ['']) &&
649
+ hasStar(palace, '太阳') &&
650
+ !targets.some((item) => item.index === palace.index)) {
651
+ targets.push(palace);
652
+ }
653
+ };
654
+ addTarget(getPalaceByName(context, '命宫'));
655
+ addTarget(getPalaceByName(context, '官禄'));
656
+ if (targets.length > 0) {
657
+ return { palaces: targets, stars: ['太阳'] };
386
658
  }
387
659
  return null;
388
660
  },
389
661
  },
390
662
  {
391
- id: 'qi-sha-chao-dou',
392
- name: '七杀朝斗',
663
+ id: 'huang-dian-chao-ban',
664
+ name: '皇殿朝班',
393
665
  kind: 'auspicious',
394
- description: '七杀坐命寅或申宫,三方四正见紫微拱照,主刚毅果敢、将帅之才。',
395
- priority: 89,
666
+ description: '太阳、文昌同居官禄宫,主文章声名入仕、官禄清贵。',
667
+ priority: 88,
396
668
  detect(context) {
397
- const ming = getPalaceByName(context, '命宫');
398
- if (!ming)
669
+ const guanLu = getPalaceByName(context, '官禄');
670
+ if (!guanLu)
399
671
  return null;
400
- if ((ming.index === 2 || ming.index === 8) && hasStar(ming, '七杀')) {
401
- return { palaces: [ming], stars: ['七杀'] };
672
+ if (hasAllStars(guanLu, ['太阳', '文昌'])) {
673
+ return { palaces: [guanLu], stars: ['太阳', '文昌'] };
402
674
  }
403
675
  return null;
404
676
  },
405
677
  },
406
678
  {
407
- id: 'shi-zhong-yin-yu',
408
- name: '石中隐玉',
679
+ id: 'tian-liang-ju-wu',
680
+ name: '天梁居午',
409
681
  kind: 'auspicious',
410
- description: '巨门坐命子宫,三方四正见化禄/化权/化科之一,主才华内敛、晚发。',
411
- priority: 85,
682
+ description: '天梁守命午宫,主官资清显、声望端正。',
683
+ priority: 88,
412
684
  detect(context) {
413
685
  const ming = getPalaceByName(context, '命宫');
414
686
  if (!ming)
415
687
  return null;
416
- if (ming.index === 0 && hasStar(ming, '巨门')) {
417
- const mutagens = getSurroundedMutagens(context, ming, 'birth_mutagen');
418
- if (mutagens.some((m) => ['禄', '权', '科'].includes(m))) {
419
- return { palaces: [ming], stars: ['巨门'] };
420
- }
688
+ if (palaceInBranch(ming, ['午']) && hasStar(ming, '天梁')) {
689
+ return { palaces: [ming], stars: ['天梁'] };
421
690
  }
422
691
  return null;
423
692
  },
424
693
  },
425
694
  {
426
- id: 'jun-chen-qing-hui',
427
- name: '君臣庆会',
695
+ id: 'lu-ma-jiao-chi',
696
+ name: '禄马交驰',
428
697
  kind: 'auspicious',
429
- description: '紫微坐命,三方四正见天府、天相、左辅、右弼等辅星拱照,主贵气凝聚。',
698
+ description: '命宫三方四正同时见禄存与天马,主财禄双美、动中得财。',
430
699
  priority: 90,
431
700
  detect(context) {
432
701
  const ming = getPalaceByName(context, '命宫');
433
702
  if (!ming)
434
703
  return null;
435
- if (hasStar(ming, '紫微')) {
436
- const aux = ['左辅', '右弼', '天魁', '天钺', '文昌', '文曲'];
437
- const count = aux.filter((s) => surroundedHasOneOf(context, ming, [s])).length;
438
- if (count >= 2) {
439
- return { palaces: [ming], stars: ['紫微'] };
440
- }
441
- }
442
- return null;
443
- },
444
- },
445
- // ── 凶格 ──
446
- {
447
- id: 'xing-qiu-jia-yin',
448
- name: '刑囚夹印',
449
- kind: 'inauspicious',
450
- description: '天相(印)被廉贞(囚)与擎羊/巨门(刑)前后夹制,主官非、刑伤。天相所在宫被廉贞与擎羊夹。',
451
- priority: 90,
452
- detect(context) {
453
- for (const palace of context.palaces) {
454
- if (!hasStar(palace, '天相'))
455
- continue;
456
- const { prev, next } = getNeighborPalaces(context, palace);
457
- if (!prev || !next)
458
- continue;
459
- const lz = hasStar(prev, '廉贞') || hasStar(next, '廉贞');
460
- const qyOrJm = hasStar(prev, '擎羊') ||
461
- hasStar(next, '擎羊') ||
462
- hasStar(prev, '巨门') ||
463
- hasStar(next, '巨门');
464
- if (lz && qyOrJm) {
465
- return { palaces: [palace, prev, next], stars: ['廉贞', '天相'] };
466
- }
704
+ const hasLu = surroundedHasOneOf(context, ming, ['禄存']);
705
+ const hasMa = surroundedHasOneOf(context, ming, ['天马']);
706
+ if (hasLu && hasMa) {
707
+ return { palaces: [ming], stars: ['禄存', '天马'] };
467
708
  }
468
709
  return null;
469
710
  },
470
711
  },
471
712
  {
472
- id: 'huo-ling-jia-ming',
473
- name: '火铃夹命',
474
- kind: 'inauspicious',
475
- description: '命宫被火星与铃星一前一后夹拱,主中年灾厄、突发波折。',
476
- priority: 88,
713
+ id: 'cai-lu-jia-ma',
714
+ name: '财禄夹马',
715
+ kind: 'auspicious',
716
+ description: '天马守命,命宫前后由武曲与禄存夹拱,主财禄动中得发。',
717
+ priority: 86,
477
718
  detect(context) {
478
719
  const ming = getPalaceByName(context, '命宫');
479
- if (!ming)
720
+ if (!ming || !hasStar(ming, '天马'))
480
721
  return null;
481
722
  const { prev, next } = getNeighborPalaces(context, ming);
482
723
  if (!prev || !next)
483
724
  return null;
484
- const huo = hasStar(prev, '火星') || hasStar(next, '火星');
485
- const ling = hasStar(prev, '铃星') || hasStar(next, '铃星');
486
- if (huo && ling) {
487
- return { palaces: [ming, prev, next], stars: ['火星', '铃星'] };
725
+ const isFlanked = (hasStar(prev, '武曲') && hasStar(next, '禄存')) ||
726
+ (hasStar(prev, '禄存') && hasStar(next, '武曲'));
727
+ if (isFlanked) {
728
+ return { palaces: [ming, prev, next], stars: ['天马', '武曲', '禄存'] };
488
729
  }
489
730
  return null;
490
731
  },
491
732
  },
492
733
  {
493
- id: 'ju-huo-qing-yang',
494
- name: '巨火擎羊',
495
- kind: 'inauspicious',
496
- description: '巨门坐命且三方四正见火星与擎羊,主口舌是非、刑伤暴躁。',
497
- priority: 87,
734
+ id: 'wu-qu-shou-yuan',
735
+ name: '武曲守垣',
736
+ kind: 'auspicious',
737
+ description: '武曲守命卯宫为贵局;原文限定“余不是”,不扩大到其他宫位。',
738
+ priority: 89,
498
739
  detect(context) {
499
740
  const ming = getPalaceByName(context, '命宫');
500
741
  if (!ming)
501
742
  return null;
502
- if (hasStar(ming, '巨门')) {
503
- if (surroundedHasOneOf(context, ming, ['火星']) &&
504
- surroundedHasOneOf(context, ming, ['擎羊'])) {
505
- return { palaces: [ming], stars: ['巨门', '火星', '擎羊'] };
506
- }
743
+ if (palaceInBranch(ming, ['卯']) && hasStar(ming, '武曲')) {
744
+ return { palaces: [ming], stars: ['武曲'] };
507
745
  }
508
746
  return null;
509
747
  },
510
748
  },
511
749
  {
512
- id: 'ma-tou-dai-jian',
513
- name: '马头带箭',
514
- kind: 'inauspicious',
515
- description: '天同坐命午宫(马头),三方四正见擎羊(箭),主中年奔波劳苦、孤克。',
516
- priority: 86,
750
+ id: 'cai-yin-jia-yin',
751
+ name: '财荫夹印',
752
+ kind: 'auspicious',
753
+ description: '天相(印)坐命宫或田宅宫,被武曲(财星)与天梁(荫星)邻宫夹拱,主因财得官、富贵绵延。',
754
+ priority: 88,
517
755
  detect(context) {
518
- const ming = getPalaceByName(context, '命宫');
519
- if (!ming)
520
- return null;
521
- if (ming.index === 6 && hasStar(ming, '天同')) {
522
- if (surroundedHasOneOf(context, ming, ['擎羊'])) {
523
- return { palaces: [ming], stars: ['天同', '擎羊'] };
756
+ for (const targetName of ['命宫', '田宅']) {
757
+ const target = getPalaceByName(context, targetName);
758
+ if (!target || !hasStar(target, '天相'))
759
+ continue;
760
+ const { prev, next } = getNeighborPalaces(context, target);
761
+ if (!prev || !next)
762
+ continue;
763
+ const hasCaiOnLeft = hasStar(prev, '武曲');
764
+ const hasYinOnRight = hasStar(next, '天梁');
765
+ const hasCaiOnRight = hasStar(next, '武曲');
766
+ const hasYinOnLeft = hasStar(prev, '天梁');
767
+ const bothSides = (hasCaiOnLeft && hasYinOnRight) || (hasCaiOnRight && hasYinOnLeft);
768
+ if (bothSides) {
769
+ return { palaces: [target, prev, next], stars: ['天相', '武曲', '天梁'] };
524
770
  }
525
771
  }
526
772
  return null;
527
773
  },
528
774
  },
529
775
  {
530
- id: 'kong-jie-jia-ming',
531
- name: '空劫夹命',
532
- kind: 'inauspicious',
533
- description: '命宫被地空与地劫前后夹拱,主一生起伏不定、际遇多舛。',
534
- priority: 85,
776
+ id: 'ri-yue-jia-cai',
777
+ name: '日月夹财',
778
+ kind: 'auspicious',
779
+ description: '命宫武曲,或财帛宫见武曲、天府,前后由太阳、太阴夹拱,主财气丰厚。',
780
+ priority: 87,
781
+ detect(context) {
782
+ const ming = getPalaceByName(context, '命宫');
783
+ const caiBo = getPalaceByName(context, '财帛');
784
+ const targets = [];
785
+ if (ming && hasStar(ming, '武曲')) {
786
+ targets.push({ palace: ming, centerStar: '武曲' });
787
+ }
788
+ if (caiBo && hasStar(caiBo, '武曲')) {
789
+ targets.push({ palace: caiBo, centerStar: '武曲' });
790
+ }
791
+ else if (caiBo && hasStar(caiBo, '天府')) {
792
+ targets.push({ palace: caiBo, centerStar: '天府' });
793
+ }
794
+ for (const { palace, centerStar } of targets) {
795
+ const { prev, next } = getNeighborPalaces(context, palace);
796
+ if (!prev || !next)
797
+ continue;
798
+ const isFlanked = (hasStar(prev, '太阳') && hasStar(next, '太阴')) ||
799
+ (hasStar(prev, '太阴') && hasStar(next, '太阳'));
800
+ if (isFlanked) {
801
+ return { palaces: [palace, prev, next], stars: [centerStar, '太阳', '太阴'] };
802
+ }
803
+ }
804
+ return null;
805
+ },
806
+ },
807
+ {
808
+ id: 'cai-ju-cai-wei',
809
+ name: '财居财位',
810
+ kind: 'auspicious',
811
+ description: '武曲守财帛宫且不坐空亡,主财星入财位、财库有根。',
812
+ priority: 87,
813
+ detect(context) {
814
+ const caiBo = getPalaceByName(context, '财帛');
815
+ if (!caiBo || hasVoidStar(caiBo))
816
+ return null;
817
+ if (hasStar(caiBo, '武曲')) {
818
+ return { palaces: [caiBo], stars: ['武曲'] };
819
+ }
820
+ return null;
821
+ },
822
+ },
823
+ {
824
+ id: 'ri-yue-zhao-bi',
825
+ name: '日月照璧',
826
+ kind: 'auspicious',
827
+ description: '太阳、太阴同临田宅宫,主田宅资产得日月照临;田宅居辰戌丑未更典型。',
828
+ priority: 85,
829
+ detect(context) {
830
+ const tianZhai = getPalaceByName(context, '田宅');
831
+ if (!tianZhai)
832
+ return null;
833
+ if (hasAllStars(tianZhai, ['太阳', '太阴'])) {
834
+ return { palaces: [tianZhai], stars: ['太阳', '太阴'] };
835
+ }
836
+ return null;
837
+ },
838
+ },
839
+ {
840
+ id: 'cai-yin-jia-lu',
841
+ name: '财印夹禄',
842
+ kind: 'auspicious',
843
+ description: '禄存守命宫或财帛宫,前后由天梁、天相夹拱,主财禄与声望相辅。',
844
+ priority: 86,
845
+ detect(context) {
846
+ const targets = [getPalaceByName(context, '命宫'), getPalaceByName(context, '财帛')].filter((palace) => !!palace && hasStar(palace, '禄存'));
847
+ for (const target of targets) {
848
+ const { prev, next } = getNeighborPalaces(context, target);
849
+ if (!prev || !next)
850
+ continue;
851
+ const isFlanked = (hasStar(prev, '天梁') && hasStar(next, '天相')) ||
852
+ (hasStar(prev, '天相') && hasStar(next, '天梁'));
853
+ if (isFlanked) {
854
+ return { palaces: [target, prev, next], stars: ['禄存', '天梁', '天相'] };
855
+ }
856
+ }
857
+ return null;
858
+ },
859
+ },
860
+ {
861
+ id: 'dui-mian-chao-dou',
862
+ name: '对面朝斗',
863
+ kind: 'auspicious',
864
+ description: '命宫在子午宫且逢禄存,主得禄朝垣、财禄有根。',
865
+ priority: 87,
866
+ detect(context) {
867
+ const ming = getPalaceByName(context, '命宫');
868
+ if (!ming)
869
+ return null;
870
+ if (palaceInBranch(ming, ['子', '午']) && hasStar(ming, '禄存')) {
871
+ return { palaces: [ming], stars: ['禄存'] };
872
+ }
873
+ return null;
874
+ },
875
+ },
876
+ {
877
+ id: 'jian-wen-wu',
878
+ name: '兼文武',
879
+ kind: 'auspicious',
880
+ description: '文曲、武曲同在命宫或身宫,主文武兼备、才艺与执行力并见。',
881
+ priority: 86,
882
+ detect(context) {
883
+ const candidates = [];
884
+ const addCandidate = (palace) => {
885
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
886
+ candidates.push(palace);
887
+ }
888
+ };
889
+ addCandidate(getPalaceByName(context, '命宫'));
890
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
891
+ const target = candidates.find((palace) => hasAllStars(palace, ['文曲', '武曲']));
892
+ if (target) {
893
+ return { palaces: [target], stars: ['文曲', '武曲'] };
894
+ }
895
+ return null;
896
+ },
897
+ },
898
+ {
899
+ id: 'wen-chang-wu-qu',
900
+ name: '文昌武曲',
901
+ kind: 'auspicious',
902
+ description: '文昌、武曲同守命宫或身宫,主文正兼备、多学多能。',
903
+ priority: 86,
904
+ detect(context) {
905
+ const candidates = [];
906
+ const ming = getPalaceByName(context, '命宫');
907
+ if (ming)
908
+ candidates.push(ming);
909
+ context.palaces
910
+ .filter((palace) => palace.is_body_palace && !candidates.some((item) => item.index === palace.index))
911
+ .forEach((palace) => candidates.push(palace));
912
+ const target = candidates.find((palace) => hasAllStars(palace, ['文昌', '武曲']));
913
+ if (target) {
914
+ return { palaces: [target], stars: ['文昌', '武曲'] };
915
+ }
916
+ return null;
917
+ },
918
+ },
919
+ {
920
+ id: 'lu-ma-pei-yin',
921
+ name: '禄马佩印',
922
+ kind: 'auspicious',
923
+ description: '命宫三方四正内见天马,马前一宫禄存与天相同宫,主禄马带印、动中得贵。',
924
+ priority: 86,
925
+ detect(context) {
926
+ const ming = getPalaceByName(context, '命宫');
927
+ if (!ming)
928
+ return null;
929
+ const maPalace = getSurroundedPalaces(context, ming).find((palace) => hasStar(palace, '天马'));
930
+ if (!maPalace)
931
+ return null;
932
+ const frontPalace = context.palaceByIndex.get((maPalace.index + 1) % 12);
933
+ if (frontPalace && hasAllStars(frontPalace, ['禄存', '天相'])) {
934
+ return { palaces: [maPalace, frontPalace], stars: ['天马', '禄存', '天相'] };
935
+ }
936
+ return null;
937
+ },
938
+ },
939
+ {
940
+ id: 'tan-huo-xiang-feng',
941
+ name: '贪火相逢',
942
+ kind: 'auspicious',
943
+ description: '贪狼与火星同守命宫且同居庙旺,主突发显达;落陷不按此格输出。',
944
+ priority: 90,
945
+ detect(context) {
946
+ const ming = getPalaceByName(context, '命宫');
947
+ if (!ming)
948
+ return null;
949
+ const tanLang = getStarFact(ming, '贪狼');
950
+ const huoXing = getStarFact(ming, '火星');
951
+ if (isTempleOrProsperous(tanLang) && isTempleOrProsperous(huoXing)) {
952
+ return { palaces: [ming], stars: ['贪狼', '火星'] };
953
+ }
954
+ return null;
955
+ },
956
+ },
957
+ {
958
+ id: 'quan-lu-sheng-feng',
959
+ name: '权禄生逢',
960
+ kind: 'auspicious',
961
+ description: '生年化权、化禄同守命宫且星曜庙旺,主财官双美;落陷不按此格输出。',
962
+ priority: 89,
963
+ detect(context) {
964
+ const ming = getPalaceByName(context, '命宫');
965
+ if (!ming)
966
+ return null;
967
+ const huaLuStars = getTempleOrProsperousBirthMutagenStars(ming, '禄');
968
+ const huaQuanStars = getTempleOrProsperousBirthMutagenStars(ming, '权');
969
+ if (huaLuStars.length > 0 && huaQuanStars.length > 0) {
970
+ const starNames = Array.from(new Set([
971
+ ...huaLuStars.map((star) => star.name),
972
+ ...huaQuanStars.map((star) => star.name),
973
+ '化禄',
974
+ '化权',
975
+ ]));
976
+ return { palaces: [ming], stars: starNames };
977
+ }
978
+ return null;
979
+ },
980
+ },
981
+ {
982
+ id: 'yang-ren-ru-miao',
983
+ name: '羊刃入庙',
984
+ kind: 'auspicious',
985
+ description: '擎羊守命辰戌丑未入庙,又遇吉曜扶助,主刚勇有为、凶曜转用。',
986
+ priority: 86,
987
+ detect(context) {
988
+ const ming = getPalaceByName(context, '命宫');
989
+ if (!ming)
990
+ return null;
991
+ if (!palaceInBranch(ming, ['辰', '戌', '丑', '未']) || !hasStar(ming, '擎羊')) {
992
+ return null;
993
+ }
994
+ const supportStars = getAuspiciousSupportStars(ming);
995
+ if (supportStars.length > 0) {
996
+ return { palaces: [ming], stars: ['擎羊', ...supportStars] };
997
+ }
998
+ return null;
999
+ },
1000
+ },
1001
+ {
1002
+ id: 'zuo-you-jia-ming',
1003
+ name: '左右夹命',
1004
+ kind: 'auspicious',
1005
+ description: '命宫被左辅、右弼一前一后夹拱,主得辅佐助力,不贵则大富。',
1006
+ priority: 86,
1007
+ detect(context) {
1008
+ const ming = getPalaceByName(context, '命宫');
1009
+ if (!ming)
1010
+ return null;
1011
+ const { prev, next } = getNeighborPalaces(context, ming);
1012
+ if (!prev || !next)
1013
+ return null;
1014
+ const isFlanked = (hasStar(prev, '左辅') && hasStar(next, '右弼')) ||
1015
+ (hasStar(prev, '右弼') && hasStar(next, '左辅'));
1016
+ if (isFlanked) {
1017
+ return { palaces: [ming, prev, next], stars: ['左辅', '右弼'] };
1018
+ }
1019
+ return null;
1020
+ },
1021
+ },
1022
+ {
1023
+ id: 'yang-mian-chao-dou',
1024
+ name: '仰面朝斗',
1025
+ kind: 'auspicious',
1026
+ description: '紫微守命子午宫,三方四正见生年科权禄齐照,主贵气显达。',
1027
+ priority: 91,
1028
+ detect(context) {
1029
+ const ming = getPalaceByName(context, '命宫');
1030
+ if (!ming || !palaceInBranch(ming, ['子', '午']) || !hasStar(ming, '紫微'))
1031
+ return null;
1032
+ const mutagens = new Set(getSurroundedMutagens(context, ming, 'birth_mutagen'));
1033
+ if (['科', '权', '禄'].every((mutagen) => mutagens.has(mutagen))) {
1034
+ return { palaces: [ming], stars: ['紫微', '化科', '化权', '化禄'] };
1035
+ }
1036
+ return null;
1037
+ },
1038
+ },
1039
+ {
1040
+ id: 'zi-lu-tong-gong',
1041
+ name: '紫禄同宫',
1042
+ kind: 'auspicious',
1043
+ description: '紫微与禄存同守命宫,太阳、太阴三方拱照,主贵不可言。',
1044
+ priority: 89,
1045
+ detect(context) {
1046
+ const ming = getPalaceByName(context, '命宫');
1047
+ if (!ming || !hasAllStars(ming, ['紫微', '禄存']))
1048
+ return null;
1049
+ const shiningPalaces = getSurroundedPalaces(context, ming).filter((palace) => palace.index !== ming.index);
1050
+ const hasSun = shiningPalaces.some((palace) => hasStar(palace, '太阳'));
1051
+ const hasMoon = shiningPalaces.some((palace) => hasStar(palace, '太阴'));
1052
+ if (hasSun && hasMoon) {
1053
+ return { palaces: [ming], stars: ['紫微', '禄存', '太阳', '太阴'] };
1054
+ }
1055
+ return null;
1056
+ },
1057
+ },
1058
+ {
1059
+ id: 'ju-ji-ju-mao',
1060
+ name: '巨机居卯',
1061
+ kind: 'auspicious',
1062
+ description: '天机、巨门同守卯宫命宫,主不贵即富;同宫见擎羊则按破格处理。',
1063
+ priority: 87,
1064
+ detect(context) {
1065
+ const ming = getPalaceByName(context, '命宫');
1066
+ if (!ming)
1067
+ return null;
1068
+ if (palaceInBranch(ming, ['卯']) && hasAllStars(ming, ['天机', '巨门']) && !hasStar(ming, '擎羊')) {
1069
+ return { palaces: [ming], stars: ['天机', '巨门'] };
1070
+ }
1071
+ return null;
1072
+ },
1073
+ },
1074
+ {
1075
+ id: 'zuo-you-chao-yuan',
1076
+ name: '左右朝垣',
1077
+ kind: 'auspicious',
1078
+ description: '命宫三方四正见左辅、右弼朝拱,主左右扶助、文武显佐。',
1079
+ priority: 86,
1080
+ detect(context) {
1081
+ const ming = getPalaceByName(context, '命宫');
1082
+ if (!ming)
1083
+ return null;
1084
+ if (surroundedHasAll(context, ming, ['左辅', '右弼'])) {
1085
+ return { palaces: [ming], stars: ['左辅', '右弼'] };
1086
+ }
1087
+ return null;
1088
+ },
1089
+ },
1090
+ {
1091
+ id: 'wen-xing-chao-ming',
1092
+ name: '文星朝命',
1093
+ kind: 'auspicious',
1094
+ description: '命宫三方四正见文昌、文曲朝拱,主文名才学、科名文章。',
1095
+ priority: 86,
1096
+ detect(context) {
1097
+ const ming = getPalaceByName(context, '命宫');
1098
+ if (!ming)
1099
+ return null;
1100
+ if (surroundedHasAll(context, ming, ['文昌', '文曲'])) {
1101
+ return { palaces: [ming], stars: ['文昌', '文曲'] };
1102
+ }
1103
+ return null;
1104
+ },
1105
+ },
1106
+ {
1107
+ id: 'zi-po-jia-ji',
1108
+ name: '紫破加吉',
1109
+ kind: 'auspicious',
1110
+ description: '紫微、破军同守四墓命宫并同宫加吉曜,主富贵可期;无吉不按此格输出。',
1111
+ priority: 86,
1112
+ detect(context) {
1113
+ const ming = getPalaceByName(context, '命宫');
1114
+ if (!ming || !palaceInBranch(ming, ['辰', '戌', '丑', '未']))
1115
+ return null;
1116
+ if (!hasAllStars(ming, ['紫微', '破军']))
1117
+ return null;
1118
+ const supportStars = getAuspiciousSupportStars(ming);
1119
+ if (supportStars.length > 0) {
1120
+ return { palaces: [ming], stars: ['紫微', '破军', ...supportStars] };
1121
+ }
1122
+ return null;
1123
+ },
1124
+ },
1125
+ {
1126
+ id: 'po-jun-zi-wu',
1127
+ name: '破军子午',
1128
+ kind: 'auspicious',
1129
+ description: '破军守命子午宫,三方四正不见羊陀火铃,主官资清显。',
1130
+ priority: 86,
1131
+ detect(context) {
1132
+ const ming = getPalaceByName(context, '命宫');
1133
+ if (!ming || !palaceInBranch(ming, ['子', '午']) || !hasStar(ming, '破军'))
1134
+ return null;
1135
+ const maleficStars = getSurroundedMatchedStarNames(context, ming, FOUR_MALEFICS);
1136
+ if (maleficStars.length === 0) {
1137
+ return { palaces: [ming], stars: ['破军'] };
1138
+ }
1139
+ return null;
1140
+ },
1141
+ },
1142
+ {
1143
+ id: 'yin-yin-gong-shen',
1144
+ name: '荫印拱身',
1145
+ kind: 'auspicious',
1146
+ description: '身宫临田宅且不坐空亡,三方四正见天梁、天相拱冲,主田宅根基与声望相辅。',
1147
+ priority: 86,
1148
+ detect(context) {
1149
+ const targets = context.palaces.filter((palace) => palace.is_body_palace && normalizePalaceName(palace.name) === '田宅');
1150
+ const target = targets.find((palace) => !hasVoidStar(palace) && surroundedHasAll(context, palace, ['天梁', '天相']));
1151
+ if (target) {
1152
+ return { palaces: [target], stars: ['天梁', '天相'] };
1153
+ }
1154
+ return null;
1155
+ },
1156
+ },
1157
+ {
1158
+ id: 'jin-yu-fu-jia',
1159
+ name: '金舆扶驾',
1160
+ kind: 'auspicious',
1161
+ description: '紫微守命,命宫前后由太阳、太阴夹辅,主得日月扶助。',
1162
+ priority: 89,
1163
+ detect(context) {
1164
+ const ming = getPalaceByName(context, '命宫');
1165
+ if (!ming || !hasStar(ming, '紫微'))
1166
+ return null;
1167
+ const { prev, next } = getNeighborPalaces(context, ming);
1168
+ if (!prev || !next)
1169
+ return null;
1170
+ const sunMoonJia = (hasStar(prev, '太阳') && hasStar(next, '太阴')) ||
1171
+ (hasStar(prev, '太阴') && hasStar(next, '太阳'));
1172
+ if (sunMoonJia) {
1173
+ return { palaces: [ming, prev, next], stars: ['紫微', '太阳', '太阴'] };
1174
+ }
1175
+ return null;
1176
+ },
1177
+ },
1178
+ {
1179
+ id: 'ming-zhu-chu-hai',
1180
+ name: '明珠出海',
1181
+ kind: 'auspicious',
1182
+ description: '命宫在未且无主星,太阳在卯、太阴在亥三方拱照,主光耀门楣、中年大展。',
1183
+ priority: 87,
1184
+ detect(context) {
1185
+ const ming = getPalaceByName(context, '命宫');
1186
+ if (!ming)
1187
+ return null;
1188
+ if (!palaceInBranch(ming, ['未']))
1189
+ return null;
1190
+ const surrounded = getSurroundedPalaces(context, ming);
1191
+ const hasSunAtMao = surrounded.some((palace) => palaceInBranch(palace, ['卯']) && hasStar(palace, '太阳'));
1192
+ const hasMoonAtHai = surrounded.some((palace) => palaceInBranch(palace, ['亥']) && hasStar(palace, '太阴'));
1193
+ if (ming.empty_state && hasSunAtMao && hasMoonAtHai) {
1194
+ return { palaces: [ming], stars: ['太阳', '太阴'] };
1195
+ }
1196
+ return null;
1197
+ },
1198
+ },
1199
+ {
1200
+ id: 'xiong-su-chao-yuan',
1201
+ name: '雄宿朝元',
1202
+ kind: 'auspicious',
1203
+ description: '廉贞守命申、未宫,且同宫不见四杀,主富贵声扬、刚毅有成。',
1204
+ priority: 91,
1205
+ detect(context) {
1206
+ const ming = getPalaceByName(context, '命宫');
1207
+ if (!ming)
1208
+ return null;
1209
+ if (palaceInBranch(ming, ['申', '未']) &&
1210
+ hasStar(ming, '廉贞') &&
1211
+ getMatchedStarNames(ming, FOUR_MALEFICS).length === 0) {
1212
+ return { palaces: [ming], stars: ['廉贞'] };
1213
+ }
1214
+ return null;
1215
+ },
1216
+ },
1217
+ {
1218
+ id: 'ji-liang-jia-ji',
1219
+ name: '机梁加吉',
1220
+ kind: 'auspicious',
1221
+ description: '天机、天梁同守命宫,同宫见辅弼昌曲魁钺禄存或生年化禄权科,且不见刑忌。',
1222
+ priority: 88,
1223
+ detect(context) {
1224
+ const ming = getPalaceByName(context, '命宫');
1225
+ if (!ming)
1226
+ return null;
1227
+ if (hasAllStars(ming, ['天机', '天梁']) &&
1228
+ getAuspiciousSupportStars(ming).length > 0 &&
1229
+ !hasBirthJiOrTianXing(ming)) {
1230
+ return { palaces: [ming], stars: ['天机', '天梁', ...getAuspiciousSupportStars(ming)] };
1231
+ }
1232
+ return null;
1233
+ },
1234
+ },
1235
+ {
1236
+ id: 'liang-chang-miao-wang',
1237
+ name: '梁昌庙旺',
1238
+ kind: 'auspicious',
1239
+ description: '天梁、文昌同守命宫,二星同居庙旺,主台纲声望、文职清贵。',
1240
+ priority: 88,
1241
+ detect(context) {
1242
+ const ming = getPalaceByName(context, '命宫');
1243
+ if (!ming)
1244
+ return null;
1245
+ const tianLiang = getStarFact(ming, '天梁');
1246
+ const wenChang = getStarFact(ming, '文昌');
1247
+ if (isTempleOrProsperous(tianLiang) && isTempleOrProsperous(wenChang)) {
1248
+ return { palaces: [ming], stars: ['天梁', '文昌'] };
1249
+ }
1250
+ return null;
1251
+ },
1252
+ },
1253
+ {
1254
+ id: 'qu-yu-liang-xing',
1255
+ name: '曲遇梁星',
1256
+ kind: 'auspicious',
1257
+ description: '天梁、文曲同守命宫,二星同居庙旺,主文名清贵、台纲声望。',
1258
+ priority: 87,
1259
+ detect(context) {
1260
+ const ming = getPalaceByName(context, '命宫');
1261
+ if (!ming)
1262
+ return null;
1263
+ const tianLiang = getStarFact(ming, '天梁');
1264
+ const wenQu = getStarFact(ming, '文曲');
1265
+ if (isTempleOrProsperous(tianLiang) && isTempleOrProsperous(wenQu)) {
1266
+ return { palaces: [ming], stars: ['天梁', '文曲'] };
1267
+ }
1268
+ return null;
1269
+ },
1270
+ },
1271
+ {
1272
+ id: 'lian-sha-miao-wang',
1273
+ name: '廉杀庙旺',
1274
+ kind: 'auspicious',
1275
+ description: '廉贞、七杀同守命宫,二星同居庙旺且不见生年化忌,主反为积富。',
1276
+ priority: 88,
1277
+ detect(context) {
1278
+ const ming = getPalaceByName(context, '命宫');
1279
+ if (!ming)
1280
+ return null;
1281
+ const lianZhen = getStarFact(ming, '廉贞');
1282
+ const qiSha = getStarFact(ming, '七杀');
1283
+ if (isTempleOrProsperous(lianZhen) &&
1284
+ isTempleOrProsperous(qiSha) &&
1285
+ !getAllStars(ming).some((star) => star.birth_mutagen === '忌')) {
1286
+ return { palaces: [ming], stars: ['廉贞', '七杀'] };
1287
+ }
1288
+ return null;
1289
+ },
1290
+ },
1291
+ {
1292
+ id: 'lian-sha-si-hai',
1293
+ name: '廉杀巳亥',
1294
+ kind: 'inauspicious',
1295
+ description: '廉贞、七杀同守巳亥命宫,且不按二星同居庙旺论吉,主漂荡波折。',
1296
+ priority: 84,
1297
+ detect(context) {
1298
+ const ming = getPalaceByName(context, '命宫');
1299
+ if (!ming || !palaceInBranch(ming, ['巳', '亥']))
1300
+ return null;
1301
+ const lianZhen = getStarFact(ming, '廉贞');
1302
+ const qiSha = getStarFact(ming, '七杀');
1303
+ if (!lianZhen || !qiSha)
1304
+ return null;
1305
+ if (isTempleOrProsperous(lianZhen) && isTempleOrProsperous(qiSha))
1306
+ return null;
1307
+ return { palaces: [ming], stars: ['廉贞', '七杀'] };
1308
+ },
1309
+ },
1310
+ {
1311
+ id: 'qi-sha-chao-dou',
1312
+ name: '七杀朝斗',
1313
+ kind: 'auspicious',
1314
+ description: '七杀坐命寅、申、子、午宫,主刚毅果敢、将帅之才;会吉曜则爵禄荣昌。',
1315
+ priority: 89,
1316
+ detect(context) {
1317
+ const ming = getPalaceByName(context, '命宫');
1318
+ if (!ming)
1319
+ return null;
1320
+ if (palaceInBranch(ming, ['寅', '申', '子', '午']) && hasStar(ming, '七杀')) {
1321
+ return { palaces: [ming], stars: ['七杀'] };
1322
+ }
1323
+ return null;
1324
+ },
1325
+ },
1326
+ {
1327
+ id: 'shi-zhong-yin-yu',
1328
+ name: '石中隐玉',
1329
+ kind: 'auspicious',
1330
+ description: '巨门坐命子午宫,三方四正见化禄/化权/化科之一,主才华内敛、晚发。',
1331
+ priority: 85,
1332
+ detect(context) {
1333
+ const candidates = [];
1334
+ const addCandidate = (palace) => {
1335
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1336
+ candidates.push(palace);
1337
+ }
1338
+ };
1339
+ addCandidate(getPalaceByName(context, '命宫'));
1340
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
1341
+ for (const target of candidates) {
1342
+ if (!palaceInBranch(target, ['子', '午']) || !hasStar(target, '巨门'))
1343
+ continue;
1344
+ const mutagens = getSurroundedMutagens(context, target, 'birth_mutagen');
1345
+ if (mutagens.some((m) => ['禄', '权', '科'].includes(m))) {
1346
+ return { palaces: [target], stars: ['巨门'] };
1347
+ }
1348
+ }
1349
+ return null;
1350
+ },
1351
+ },
1352
+ {
1353
+ id: 'jun-chen-qing-hui',
1354
+ name: '君臣庆会',
1355
+ kind: 'auspicious',
1356
+ description: '紫微与左辅、右弼同守命宫,更会天相、武曲、太阴尤佳,主贵气凝聚。',
1357
+ priority: 90,
1358
+ detect(context) {
1359
+ const ming = getPalaceByName(context, '命宫');
1360
+ if (!ming)
1361
+ return null;
1362
+ if (hasAllStars(ming, ['紫微', '左辅', '右弼'])) {
1363
+ const enhancers = ['天相', '武曲', '太阴'].filter((starName) => surroundedHasOneOf(context, ming, [starName]));
1364
+ return { palaces: [ming], stars: ['紫微', '左辅', '右弼', ...enhancers] };
1365
+ }
1366
+ return null;
1367
+ },
1368
+ },
1369
+ // ── 凶格 ──
1370
+ {
1371
+ id: 'xing-qiu-jia-yin',
1372
+ name: '刑囚夹印',
1373
+ kind: 'inauspicious',
1374
+ description: '天刑与廉贞同临命宫或身宫,主武勇刚烈,也需留意刑伤是非。',
1375
+ priority: 90,
1376
+ detect(context) {
1377
+ const candidates = [];
1378
+ const addCandidate = (palace) => {
1379
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1380
+ candidates.push(palace);
1381
+ }
1382
+ };
1383
+ addCandidate(getPalaceByName(context, '命宫'));
1384
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
1385
+ const target = candidates.find((palace) => hasAllStars(palace, ['天刑', '廉贞']));
1386
+ if (target) {
1387
+ return { palaces: [target], stars: ['天刑', '廉贞'] };
1388
+ }
1389
+ return null;
1390
+ },
1391
+ },
1392
+ {
1393
+ id: 'cai-yu-qiu-chou',
1394
+ name: '财与囚仇',
1395
+ kind: 'inauspicious',
1396
+ description: '武曲与廉贞同临命宫或身宫,财星遇囚曜,主因财招扰、是非牵缠。',
1397
+ priority: 86,
1398
+ detect(context) {
1399
+ const candidates = [];
1400
+ const addCandidate = (palace) => {
1401
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1402
+ candidates.push(palace);
1403
+ }
1404
+ };
1405
+ addCandidate(getPalaceByName(context, '命宫'));
1406
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
1407
+ const target = candidates.find((palace) => hasAllStars(palace, ['武曲', '廉贞']));
1408
+ if (target) {
1409
+ return { palaces: [target], stars: ['武曲', '廉贞'] };
1410
+ }
1411
+ return null;
1412
+ },
1413
+ },
1414
+ {
1415
+ id: 'fan-shui-tao-hua',
1416
+ name: '泛水桃花',
1417
+ kind: 'inauspicious',
1418
+ description: '贪狼守亥子命宫,又遇擎羊或陀罗,主桃花酒色与刑耗牵缠。',
1419
+ priority: 85,
1420
+ detect(context) {
1421
+ const ming = getPalaceByName(context, '命宫');
1422
+ if (!ming || !palaceInBranch(ming, ['亥', '子']) || !hasStar(ming, '贪狼'))
1423
+ return null;
1424
+ const shaStars = getMatchedStarNames(ming, ['擎羊', '陀罗']);
1425
+ if (shaStars.length > 0) {
1426
+ return { palaces: [ming], stars: ['贪狼', ...shaStars] };
1427
+ }
1428
+ return null;
1429
+ },
1430
+ },
1431
+ {
1432
+ id: 'yi-sheng-gu-pin',
1433
+ name: '一生孤贫',
1434
+ kind: 'inauspicious',
1435
+ description: '破军陷地守命,主格局孤贫辛劳;只按命宫破军落陷判断。',
1436
+ priority: 84,
1437
+ detect(context) {
1438
+ const ming = getPalaceByName(context, '命宫');
1439
+ if (!ming)
1440
+ return null;
1441
+ const poJunXian = getAllStars(ming).find((star) => star.name === '破军' && star.brightness === '陷');
1442
+ if (poJunXian) {
1443
+ return { palaces: [ming], stars: ['破军'] };
1444
+ }
1445
+ return null;
1446
+ },
1447
+ },
1448
+ {
1449
+ id: 'jun-zi-zai-ye',
1450
+ name: '君子在野',
1451
+ kind: 'inauspicious',
1452
+ description: '羊陀火铃四杀之一落陷守命宫或身宫,主才志受抑、格局难伸。',
1453
+ priority: 83,
1454
+ detect(context) {
1455
+ const candidates = [];
1456
+ const addCandidate = (palace) => {
1457
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1458
+ candidates.push(palace);
1459
+ }
1460
+ };
1461
+ addCandidate(getPalaceByName(context, '命宫'));
1462
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
1463
+ const target = candidates.find((palace) => getAllStars(palace).some((star) => FOUR_MALEFICS.includes(star.name) && star.brightness === '陷'));
1464
+ if (target) {
1465
+ const matchedStars = Array.from(new Set(getAllStars(target)
1466
+ .filter((star) => FOUR_MALEFICS.includes(star.name) && star.brightness === '陷')
1467
+ .map((star) => star.name)));
1468
+ return { palaces: [target], stars: matchedStars };
1469
+ }
1470
+ return null;
1471
+ },
1472
+ },
1473
+ {
1474
+ id: 'huo-ling-jia-ming',
1475
+ name: '火铃夹命',
1476
+ kind: 'inauspicious',
1477
+ description: '命宫被火星与铃星一前一后夹拱,主中年灾厄、突发波折。',
1478
+ priority: 88,
1479
+ detect(context) {
1480
+ const ming = getPalaceByName(context, '命宫');
1481
+ if (!ming)
1482
+ return null;
1483
+ const { prev, next } = getNeighborPalaces(context, ming);
1484
+ if (!prev || !next)
1485
+ return null;
1486
+ const isFlanked = (hasStar(prev, '火星') && hasStar(next, '铃星')) ||
1487
+ (hasStar(prev, '铃星') && hasStar(next, '火星'));
1488
+ if (isFlanked) {
1489
+ return { palaces: [ming, prev, next], stars: ['火星', '铃星'] };
1490
+ }
1491
+ return null;
1492
+ },
1493
+ },
1494
+ {
1495
+ id: 'ju-huo-qing-yang',
1496
+ name: '巨火擎羊',
1497
+ kind: 'inauspicious',
1498
+ description: '巨门坐命且三方四正见火星与擎羊,主口舌是非、刑伤暴躁。',
1499
+ priority: 87,
1500
+ detect(context) {
1501
+ const ming = getPalaceByName(context, '命宫');
1502
+ if (!ming)
1503
+ return null;
1504
+ if (hasStar(ming, '巨门')) {
1505
+ if (surroundedHasOneOf(context, ming, ['火星']) &&
1506
+ surroundedHasOneOf(context, ming, ['擎羊'])) {
1507
+ return { palaces: [ming], stars: ['巨门', '火星', '擎羊'] };
1508
+ }
1509
+ }
1510
+ return null;
1511
+ },
1512
+ },
1513
+ {
1514
+ id: 'ma-tou-dai-jian',
1515
+ name: '马头带箭',
1516
+ kind: 'inauspicious',
1517
+ description: '命宫或身宫天马与擎羊同宫(马有刃),主奔波刑伤;不是单凭午宫论格。',
1518
+ priority: 86,
1519
+ detect(context) {
1520
+ const candidates = [];
1521
+ const addCandidate = (palace) => {
1522
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1523
+ candidates.push(palace);
1524
+ }
1525
+ };
1526
+ addCandidate(getPalaceByName(context, '命宫'));
1527
+ context.palaces.filter((palace) => palace.is_body_palace).forEach(addCandidate);
1528
+ const target = candidates.find((palace) => hasOriginStar(palace, '天马') && hasOriginStar(palace, '擎羊'));
1529
+ if (target) {
1530
+ return { palaces: [target], stars: ['天马', '擎羊'] };
1531
+ }
1532
+ return null;
1533
+ },
1534
+ },
1535
+ {
1536
+ id: 'kong-jie-jia-ming',
1537
+ name: '空劫夹命',
1538
+ kind: 'inauspicious',
1539
+ description: '命宫被地空与地劫前后夹拱,主一生起伏不定、际遇多舛。',
1540
+ priority: 85,
535
1541
  detect(context) {
536
1542
  const ming = getPalaceByName(context, '命宫');
537
1543
  if (!ming)
@@ -539,14 +1545,108 @@ const PATTERN_RULES = [
539
1545
  const { prev, next } = getNeighborPalaces(context, ming);
540
1546
  if (!prev || !next)
541
1547
  return null;
542
- const kong = hasStar(prev, '地空') || hasStar(next, '地空');
543
- const jie = hasStar(prev, '地劫') || hasStar(next, '地劫');
544
- if (kong && jie) {
1548
+ const isFlanked = (hasStar(prev, '地空') && hasStar(next, '地劫')) ||
1549
+ (hasStar(prev, '地劫') && hasStar(next, '地空'));
1550
+ if (isFlanked) {
545
1551
  return { palaces: [ming, prev, next], stars: ['地空', '地劫'] };
546
1552
  }
547
1553
  return null;
548
1554
  },
549
1555
  },
1556
+ {
1557
+ id: 'liang-chong-hua-gai',
1558
+ name: '两重华盖',
1559
+ kind: 'inauspicious',
1560
+ description: '禄存与生年化禄同坐命宫,又逢地空或地劫,主双禄被空劫折损。',
1561
+ priority: 84,
1562
+ detect(context) {
1563
+ const ming = getPalaceByName(context, '命宫');
1564
+ if (!ming)
1565
+ return null;
1566
+ const hasLuCun = hasStar(ming, '禄存');
1567
+ const hasBirthHuaLu = getAllStars(ming).some((star) => star.birth_mutagen === '禄');
1568
+ const kongJieStars = ['地空', '地劫'].filter((starName) => hasStar(ming, starName));
1569
+ if (hasLuCun && hasBirthHuaLu && kongJieStars.length > 0) {
1570
+ return { palaces: [ming], stars: ['禄存', '化禄', ...kongJieStars] };
1571
+ }
1572
+ return null;
1573
+ },
1574
+ },
1575
+ {
1576
+ id: 'sheng-bu-feng-shi',
1577
+ name: '生不逢时',
1578
+ kind: 'inauspicious',
1579
+ description: '廉贞守命又坐空亡类星曜,主时运不偶、发展多受阻。',
1580
+ priority: 84,
1581
+ detect(context) {
1582
+ const ming = getPalaceByName(context, '命宫');
1583
+ if (!ming || !hasStar(ming, '廉贞'))
1584
+ return null;
1585
+ const voidStars = getVoidStars(ming);
1586
+ if (voidStars.length > 0) {
1587
+ return { palaces: [ming], stars: ['廉贞', ...voidStars] };
1588
+ }
1589
+ return null;
1590
+ },
1591
+ },
1592
+ {
1593
+ id: 'lu-feng-liang-sha',
1594
+ name: '禄逢两杀',
1595
+ kind: 'inauspicious',
1596
+ description: '命宫三方四正内禄存坐空亡,又同逢地空或地劫,主财禄受损、得而难守。',
1597
+ priority: 84,
1598
+ detect(context) {
1599
+ const ming = getPalaceByName(context, '命宫');
1600
+ if (!ming)
1601
+ return null;
1602
+ const target = getSurroundedPalaces(context, ming).find((palace) => {
1603
+ if (!hasStar(palace, '禄存') || !hasVoidStar(palace))
1604
+ return false;
1605
+ return getKongJieStars(palace).length > 0;
1606
+ });
1607
+ if (target) {
1608
+ return {
1609
+ palaces: [target],
1610
+ stars: ['禄存', ...getVoidStars(target), ...getKongJieStars(target)],
1611
+ };
1612
+ }
1613
+ return null;
1614
+ },
1615
+ },
1616
+ {
1617
+ id: 'ma-luo-kong-wang',
1618
+ name: '马落空亡',
1619
+ kind: 'inauspicious',
1620
+ description: '命宫三方四正内天马落空亡类星曜,主奔波劳碌、动而难成。',
1621
+ priority: 83,
1622
+ detect(context) {
1623
+ const ming = getPalaceByName(context, '命宫');
1624
+ if (!ming)
1625
+ return null;
1626
+ const target = getSurroundedPalaces(context, ming).find((palace) => hasStar(palace, '天马') && hasVoidStar(palace));
1627
+ if (target) {
1628
+ return { palaces: [target], stars: ['天马', ...getVoidStars(target)] };
1629
+ }
1630
+ return null;
1631
+ },
1632
+ },
1633
+ {
1634
+ id: 'ri-yue-cang-hui',
1635
+ name: '日月藏辉',
1636
+ kind: 'inauspicious',
1637
+ description: '日月反背又逢巨门暗曜,主光辉受蔽、劳碌是非加重。',
1638
+ priority: 83,
1639
+ detect(context) {
1640
+ const ming = getPalaceByName(context, '命宫');
1641
+ if (!ming || !isRiYueFanBei(ming))
1642
+ return null;
1643
+ if (surroundedHasOneOf(context, ming, ['巨门'])) {
1644
+ const luminary = hasStar(ming, '太阳') ? '太阳' : '太阴';
1645
+ return { palaces: [ming], stars: [luminary, '巨门'] };
1646
+ }
1647
+ return null;
1648
+ },
1649
+ },
550
1650
  {
551
1651
  id: 'ri-yue-fan-bei',
552
1652
  name: '日月反背',
@@ -557,11 +1657,9 @@ const PATTERN_RULES = [
557
1657
  const ming = getPalaceByName(context, '命宫');
558
1658
  if (!ming)
559
1659
  return null;
560
- if (ming.index === 10 && hasStar(ming, '太阳')) {
561
- return { palaces: [ming], stars: ['太阳'] };
562
- }
563
- if (ming.index === 4 && hasStar(ming, '太阴')) {
564
- return { palaces: [ming], stars: ['太阴'] };
1660
+ if (isRiYueFanBei(ming)) {
1661
+ const luminaries = ['太阳', '太阴'].filter((name) => hasStar(ming, name));
1662
+ return { palaces: [ming], stars: luminaries };
565
1663
  }
566
1664
  return null;
567
1665
  },
@@ -577,13 +1675,15 @@ const PATTERN_RULES = [
577
1675
  const ming = getPalaceByName(context, '命宫');
578
1676
  if (!ming)
579
1677
  return null;
580
- // (4)为天罗,戌(10)为地网
581
- if (ming.index !== 4 && ming.index !== 10)
1678
+ if (!palaceInBranch(ming, ['辰', '戌']))
582
1679
  return null;
583
1680
  // 判断是否有吉星解网:紫微、天府坐罗网可解,天同、天梁亦能缓解
584
1681
  const jieWangStars = ['紫微', '天府', '天同', '天梁', '太阳', '贪狼'];
585
1682
  const hasJieWang = jieWangStars.some((n) => hasStar(ming, n));
586
- return { palaces: [ming], stars: hasJieWang ? jieWangStars.filter((n) => hasStar(ming, n)) : [] };
1683
+ return {
1684
+ palaces: [ming],
1685
+ stars: hasJieWang ? jieWangStars.filter((n) => hasStar(ming, n)) : [],
1686
+ };
587
1687
  },
588
1688
  },
589
1689
  // ═══════ 以下为新增补全格局 ═══════
@@ -591,16 +1691,27 @@ const PATTERN_RULES = [
591
1691
  id: 'wu-tan-tong-xing',
592
1692
  name: '武贪同行',
593
1693
  kind: 'neutral',
594
- description: '武曲与贪狼同坐命宫或财帛宫,主少年艰难、三十后发越。武贪不发少年人。发福在晚。',
1694
+ description: '命宫三方四正或身宫、财帛、田宅见武曲与贪狼同宫,主少年艰难、三十后发越。武贪不发少年人。发福在晚。',
595
1695
  priority: 88,
596
1696
  detect(context) {
597
- for (const targetName of ['命宫', '财帛']) {
598
- const target = getPalaceByName(context, targetName);
599
- if (!target)
600
- continue;
601
- if (hasAllStars(target, ['武曲', '贪狼'])) {
602
- return { palaces: [target], stars: ['武曲', '贪狼'] };
1697
+ const candidates = [];
1698
+ const addCandidate = (palace) => {
1699
+ if (palace && !candidates.some((item) => item.index === palace.index)) {
1700
+ candidates.push(palace);
603
1701
  }
1702
+ };
1703
+ const ming = getPalaceByName(context, '命宫');
1704
+ if (ming) {
1705
+ getSurroundedPalaces(context, ming).forEach(addCandidate);
1706
+ }
1707
+ addCandidate(context.palaces.find((palace) => palace.is_body_palace));
1708
+ for (const targetName of ['财帛', '田宅']) {
1709
+ const target = getPalaceByName(context, targetName);
1710
+ addCandidate(target);
1711
+ }
1712
+ const target = candidates.find((palace) => hasAllStars(palace, ['武曲', '贪狼']));
1713
+ if (target) {
1714
+ return { palaces: [target], stars: ['武曲', '贪狼'] };
604
1715
  }
605
1716
  return null;
606
1717
  },
@@ -609,14 +1720,15 @@ const PATTERN_RULES = [
609
1720
  id: 'huo-tan-ge',
610
1721
  name: '火贪格',
611
1722
  kind: 'auspicious',
612
- description: '火星与贪狼同坐命宫,主暴发、突发之财,横发横破。限运逢之亦然。',
1723
+ description: '火星与贪狼同宫照命,主暴发、突发之财,横发横破。限运逢之亦然。',
613
1724
  priority: 92,
614
1725
  detect(context) {
615
1726
  const ming = getPalaceByName(context, '命宫');
616
1727
  if (!ming)
617
1728
  return null;
618
- if (hasStar(ming, '火星') && hasStar(ming, '贪狼')) {
619
- return { palaces: [ming], stars: ['火星', '贪狼'] };
1729
+ const target = getSurroundedPalaces(context, ming).find((palace) => hasAllStars(palace, ['火星', '贪狼']));
1730
+ if (target) {
1731
+ return { palaces: [target], stars: ['火星', '贪狼'] };
620
1732
  }
621
1733
  return null;
622
1734
  },
@@ -625,14 +1737,15 @@ const PATTERN_RULES = [
625
1737
  id: 'ling-tan-ge',
626
1738
  name: '铃贪格',
627
1739
  kind: 'auspicious',
628
- description: '铃星与贪狼同坐命宫,主异路功名、偏财爆发,限运逢之亦然。',
1740
+ description: '铃星与贪狼同宫照命,主异路功名、偏财爆发,限运逢之亦然。',
629
1741
  priority: 90,
630
1742
  detect(context) {
631
1743
  const ming = getPalaceByName(context, '命宫');
632
1744
  if (!ming)
633
1745
  return null;
634
- if (hasStar(ming, '铃星') && hasStar(ming, '贪狼')) {
635
- return { palaces: [ming], stars: ['铃星', '贪狼'] };
1746
+ const target = getSurroundedPalaces(context, ming).find((palace) => hasAllStars(palace, ['铃星', '贪狼']));
1747
+ if (target) {
1748
+ return { palaces: [target], stars: ['铃星', '贪狼'] };
636
1749
  }
637
1750
  return null;
638
1751
  },
@@ -651,8 +1764,7 @@ const PATTERN_RULES = [
651
1764
  const hasLiang = surroundedHasOneOf(context, ming, ['天梁']);
652
1765
  const hasChang = surroundedHasOneOf(context, ming, ['文昌']);
653
1766
  const hasLu = surroundedHasOneOf(context, ming, ['禄存']);
654
- const hasHuaLu = getSurroundedMutagens(context, ming, 'birth_mutagen').includes('禄');
655
- if (hasYang && hasLiang && hasChang && (hasLu || hasHuaLu)) {
1767
+ if (hasYang && hasLiang && hasChang && hasLu) {
656
1768
  return { palaces: [ming], stars: ['太阳', '天梁', '文昌', '禄存'] };
657
1769
  }
658
1770
  return null;
@@ -662,23 +1774,21 @@ const PATTERN_RULES = [
662
1774
  id: 'ju-ri-tong-gong',
663
1775
  name: '巨日同宫',
664
1776
  kind: 'neutral',
665
- description: '巨门与太阳同坐命宫或迁移宫,主口才辩给、靠嘴谋生。日蔽则减力。',
1777
+ description: '命宫三方四正见巨门与太阳同宫或拱照,主口才辩给、靠嘴谋生。日蔽则减力。',
666
1778
  priority: 85,
667
1779
  detect(context) {
668
- for (const targetName of ['命宫', '迁移']) {
669
- const target = getPalaceByName(context, targetName);
670
- if (!target)
671
- continue;
672
- if (hasAllStars(target, ['巨门', '太阳'])) {
673
- return { palaces: [target], stars: ['巨门', '太阳'] };
674
- }
1780
+ const ming = getPalaceByName(context, '命宫');
1781
+ if (!ming)
1782
+ return null;
1783
+ if (surroundedHasAll(context, ming, ['巨门', '太阳'])) {
1784
+ return { palaces: [ming], stars: ['巨门', '太阳'] };
675
1785
  }
676
1786
  return null;
677
1787
  },
678
1788
  },
679
1789
  ];
680
1790
  export function detectPatterns(params) {
681
- const { palaces } = params;
1791
+ const { palaces, birthTimeLabel, birthTimeRange } = params;
682
1792
  if (!palaces.length)
683
1793
  return [];
684
1794
  const palaceByName = new Map();
@@ -687,7 +1797,13 @@ export function detectPatterns(params) {
687
1797
  palaceByName.set(normalizePalaceName(palace.name), palace);
688
1798
  palaceByIndex.set(palace.index, palace);
689
1799
  });
690
- const context = { palaces, palaceByName, palaceByIndex };
1800
+ const context = {
1801
+ palaces,
1802
+ palaceByName,
1803
+ palaceByIndex,
1804
+ birthTimeLabel,
1805
+ birthTimeRange,
1806
+ };
691
1807
  const patterns = [];
692
1808
  PATTERN_RULES.forEach((rule, index) => {
693
1809
  const matched = rule.detect(context);