mingpan 0.1.1

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 (231) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +118 -0
  3. package/dist/core/bazi/BaziCore.d.ts +112 -0
  4. package/dist/core/bazi/BaziCore.d.ts.map +1 -0
  5. package/dist/core/bazi/BaziCore.js +606 -0
  6. package/dist/core/bazi/BaziCore.js.map +1 -0
  7. package/dist/core/bazi/SolarTermCalculator.d.ts +46 -0
  8. package/dist/core/bazi/SolarTermCalculator.d.ts.map +1 -0
  9. package/dist/core/bazi/SolarTermCalculator.js +452 -0
  10. package/dist/core/bazi/SolarTermCalculator.js.map +1 -0
  11. package/dist/core/bazi/TrueSolarTime.d.ts +64 -0
  12. package/dist/core/bazi/TrueSolarTime.d.ts.map +1 -0
  13. package/dist/core/bazi/TrueSolarTime.js +210 -0
  14. package/dist/core/bazi/TrueSolarTime.js.map +1 -0
  15. package/dist/core/bazi/ephemerisData.d.ts +10 -0
  16. package/dist/core/bazi/ephemerisData.d.ts.map +1 -0
  17. package/dist/core/bazi/ephemerisData.js +88 -0
  18. package/dist/core/bazi/ephemerisData.js.map +1 -0
  19. package/dist/core/bazi/index.d.ts +8 -0
  20. package/dist/core/bazi/index.d.ts.map +1 -0
  21. package/dist/core/bazi/index.js +30 -0
  22. package/dist/core/bazi/index.js.map +1 -0
  23. package/dist/core/bazi/types.d.ts +116 -0
  24. package/dist/core/bazi/types.d.ts.map +1 -0
  25. package/dist/core/bazi/types.js +7 -0
  26. package/dist/core/bazi/types.js.map +1 -0
  27. package/dist/core/calendar/SolarTermsCalculator.d.ts +33 -0
  28. package/dist/core/calendar/SolarTermsCalculator.d.ts.map +1 -0
  29. package/dist/core/calendar/SolarTermsCalculator.js +111 -0
  30. package/dist/core/calendar/SolarTermsCalculator.js.map +1 -0
  31. package/dist/core/calendar/astronomicalCalendar.d.ts +74 -0
  32. package/dist/core/calendar/astronomicalCalendar.d.ts.map +1 -0
  33. package/dist/core/calendar/astronomicalCalendar.js +276 -0
  34. package/dist/core/calendar/astronomicalCalendar.js.map +1 -0
  35. package/dist/core/calendar/calendar.d.ts +81 -0
  36. package/dist/core/calendar/calendar.d.ts.map +1 -0
  37. package/dist/core/calendar/calendar.js +223 -0
  38. package/dist/core/calendar/calendar.js.map +1 -0
  39. package/dist/core/calendar/constants.d.ts +151 -0
  40. package/dist/core/calendar/constants.d.ts.map +1 -0
  41. package/dist/core/calendar/constants.js +97 -0
  42. package/dist/core/calendar/constants.js.map +1 -0
  43. package/dist/core/calendar/julian.d.ts +54 -0
  44. package/dist/core/calendar/julian.d.ts.map +1 -0
  45. package/dist/core/calendar/julian.js +142 -0
  46. package/dist/core/calendar/julian.js.map +1 -0
  47. package/dist/core/calendar/lunarCalendar.d.ts +79 -0
  48. package/dist/core/calendar/lunarCalendar.d.ts.map +1 -0
  49. package/dist/core/calendar/lunarCalendar.js +164 -0
  50. package/dist/core/calendar/lunarCalendar.js.map +1 -0
  51. package/dist/core/calendar/solarTerms.d.ts +105 -0
  52. package/dist/core/calendar/solarTerms.d.ts.map +1 -0
  53. package/dist/core/calendar/solarTerms.js +487 -0
  54. package/dist/core/calendar/solarTerms.js.map +1 -0
  55. package/dist/core/constants/bazi.d.ts +138 -0
  56. package/dist/core/constants/bazi.d.ts.map +1 -0
  57. package/dist/core/constants/bazi.js +332 -0
  58. package/dist/core/constants/bazi.js.map +1 -0
  59. package/dist/core/constants/index.d.ts +6 -0
  60. package/dist/core/constants/index.d.ts.map +1 -0
  61. package/dist/core/constants/index.js +37 -0
  62. package/dist/core/constants/index.js.map +1 -0
  63. package/dist/core/constants/positions.d.ts +27 -0
  64. package/dist/core/constants/positions.d.ts.map +1 -0
  65. package/dist/core/constants/positions.js +39 -0
  66. package/dist/core/constants/positions.js.map +1 -0
  67. package/dist/core/ziwei/BrightnessSystem.d.ts +53 -0
  68. package/dist/core/ziwei/BrightnessSystem.d.ts.map +1 -0
  69. package/dist/core/ziwei/BrightnessSystem.js +278 -0
  70. package/dist/core/ziwei/BrightnessSystem.js.map +1 -0
  71. package/dist/core/ziwei/IztroAdapter.d.ts +78 -0
  72. package/dist/core/ziwei/IztroAdapter.d.ts.map +1 -0
  73. package/dist/core/ziwei/IztroAdapter.js +314 -0
  74. package/dist/core/ziwei/IztroAdapter.js.map +1 -0
  75. package/dist/core/ziwei/MutagenCore.d.ts +81 -0
  76. package/dist/core/ziwei/MutagenCore.d.ts.map +1 -0
  77. package/dist/core/ziwei/MutagenCore.js +246 -0
  78. package/dist/core/ziwei/MutagenCore.js.map +1 -0
  79. package/dist/index.d.ts +13 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +1101 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/output/fortuneTextRenderer.d.ts +63 -0
  84. package/dist/output/fortuneTextRenderer.d.ts.map +1 -0
  85. package/dist/output/fortuneTextRenderer.js +384 -0
  86. package/dist/output/fortuneTextRenderer.js.map +1 -0
  87. package/dist/output/listTextRenderer.d.ts +298 -0
  88. package/dist/output/listTextRenderer.d.ts.map +1 -0
  89. package/dist/output/listTextRenderer.js +942 -0
  90. package/dist/output/listTextRenderer.js.map +1 -0
  91. package/dist/services/bazi/BaziService.d.ts +83 -0
  92. package/dist/services/bazi/BaziService.d.ts.map +1 -0
  93. package/dist/services/bazi/BaziService.js +635 -0
  94. package/dist/services/bazi/BaziService.js.map +1 -0
  95. package/dist/services/bazi/analyzers/ClimateAnalyzer.d.ts +31 -0
  96. package/dist/services/bazi/analyzers/ClimateAnalyzer.d.ts.map +1 -0
  97. package/dist/services/bazi/analyzers/ClimateAnalyzer.js +194 -0
  98. package/dist/services/bazi/analyzers/ClimateAnalyzer.js.map +1 -0
  99. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts +16 -0
  100. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts.map +1 -0
  101. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js +60 -0
  102. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js.map +1 -0
  103. package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts +33 -0
  104. package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts.map +1 -0
  105. package/dist/services/bazi/analyzers/NaYinAnalyzer.js +209 -0
  106. package/dist/services/bazi/analyzers/NaYinAnalyzer.js.map +1 -0
  107. package/dist/services/bazi/analyzers/PatternAnalyzer.d.ts +159 -0
  108. package/dist/services/bazi/analyzers/PatternAnalyzer.d.ts.map +1 -0
  109. package/dist/services/bazi/analyzers/PatternAnalyzer.js +1150 -0
  110. package/dist/services/bazi/analyzers/PatternAnalyzer.js.map +1 -0
  111. package/dist/services/bazi/analyzers/RelationsAnalyzer.d.ts +114 -0
  112. package/dist/services/bazi/analyzers/RelationsAnalyzer.d.ts.map +1 -0
  113. package/dist/services/bazi/analyzers/RelationsAnalyzer.js +704 -0
  114. package/dist/services/bazi/analyzers/RelationsAnalyzer.js.map +1 -0
  115. package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts +236 -0
  116. package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts.map +1 -0
  117. package/dist/services/bazi/analyzers/ShenShaAnalyzer.js +2079 -0
  118. package/dist/services/bazi/analyzers/ShenShaAnalyzer.js.map +1 -0
  119. package/dist/services/bazi/analyzers/StrengthAnalyzer.d.ts +181 -0
  120. package/dist/services/bazi/analyzers/StrengthAnalyzer.d.ts.map +1 -0
  121. package/dist/services/bazi/analyzers/StrengthAnalyzer.js +1119 -0
  122. package/dist/services/bazi/analyzers/StrengthAnalyzer.js.map +1 -0
  123. package/dist/services/bazi/analyzers/TenGodsAnalyzer.d.ts +78 -0
  124. package/dist/services/bazi/analyzers/TenGodsAnalyzer.d.ts.map +1 -0
  125. package/dist/services/bazi/analyzers/TenGodsAnalyzer.js +383 -0
  126. package/dist/services/bazi/analyzers/TenGodsAnalyzer.js.map +1 -0
  127. package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts +46 -0
  128. package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts.map +1 -0
  129. package/dist/services/bazi/analyzers/TraditionalAnalyzer.js +260 -0
  130. package/dist/services/bazi/analyzers/TraditionalAnalyzer.js.map +1 -0
  131. package/dist/services/bazi/analyzers/YongShenAnalyzer.d.ts +70 -0
  132. package/dist/services/bazi/analyzers/YongShenAnalyzer.d.ts.map +1 -0
  133. package/dist/services/bazi/analyzers/YongShenAnalyzer.js +858 -0
  134. package/dist/services/bazi/analyzers/YongShenAnalyzer.js.map +1 -0
  135. package/dist/services/bazi/calculators/DaYunCalculator.d.ts +71 -0
  136. package/dist/services/bazi/calculators/DaYunCalculator.d.ts.map +1 -0
  137. package/dist/services/bazi/calculators/DaYunCalculator.js +496 -0
  138. package/dist/services/bazi/calculators/DaYunCalculator.js.map +1 -0
  139. package/dist/services/bazi/calculators/LiuNianCalculator.d.ts +88 -0
  140. package/dist/services/bazi/calculators/LiuNianCalculator.d.ts.map +1 -0
  141. package/dist/services/bazi/calculators/LiuNianCalculator.js +546 -0
  142. package/dist/services/bazi/calculators/LiuNianCalculator.js.map +1 -0
  143. package/dist/services/bazi/calculators/LiuRiCalculator.d.ts +66 -0
  144. package/dist/services/bazi/calculators/LiuRiCalculator.d.ts.map +1 -0
  145. package/dist/services/bazi/calculators/LiuRiCalculator.js +497 -0
  146. package/dist/services/bazi/calculators/LiuRiCalculator.js.map +1 -0
  147. package/dist/services/bazi/calculators/LiuYueCalculator.d.ts +50 -0
  148. package/dist/services/bazi/calculators/LiuYueCalculator.d.ts.map +1 -0
  149. package/dist/services/bazi/calculators/LiuYueCalculator.js +338 -0
  150. package/dist/services/bazi/calculators/LiuYueCalculator.js.map +1 -0
  151. package/dist/services/bazi/calculators/LuckCycleCalculator.d.ts +123 -0
  152. package/dist/services/bazi/calculators/LuckCycleCalculator.d.ts.map +1 -0
  153. package/dist/services/bazi/calculators/LuckCycleCalculator.js +414 -0
  154. package/dist/services/bazi/calculators/LuckCycleCalculator.js.map +1 -0
  155. package/dist/services/bazi/index.d.ts +21 -0
  156. package/dist/services/bazi/index.d.ts.map +1 -0
  157. package/dist/services/bazi/index.js +83 -0
  158. package/dist/services/bazi/index.js.map +1 -0
  159. package/dist/services/bazi/types.d.ts +597 -0
  160. package/dist/services/bazi/types.d.ts.map +1 -0
  161. package/dist/services/bazi/types.js +123 -0
  162. package/dist/services/bazi/types.js.map +1 -0
  163. package/dist/services/ziwei/ZiweiService.d.ts +86 -0
  164. package/dist/services/ziwei/ZiweiService.d.ts.map +1 -0
  165. package/dist/services/ziwei/ZiweiService.js +343 -0
  166. package/dist/services/ziwei/ZiweiService.js.map +1 -0
  167. package/dist/services/ziwei/calculators/BrightnessCalculator.d.ts +38 -0
  168. package/dist/services/ziwei/calculators/BrightnessCalculator.d.ts.map +1 -0
  169. package/dist/services/ziwei/calculators/BrightnessCalculator.js +142 -0
  170. package/dist/services/ziwei/calculators/BrightnessCalculator.js.map +1 -0
  171. package/dist/services/ziwei/calculators/DailyCalculator.d.ts +27 -0
  172. package/dist/services/ziwei/calculators/DailyCalculator.d.ts.map +1 -0
  173. package/dist/services/ziwei/calculators/DailyCalculator.js +55 -0
  174. package/dist/services/ziwei/calculators/DailyCalculator.js.map +1 -0
  175. package/dist/services/ziwei/calculators/DecadeCalculator.d.ts +46 -0
  176. package/dist/services/ziwei/calculators/DecadeCalculator.d.ts.map +1 -0
  177. package/dist/services/ziwei/calculators/DecadeCalculator.js +181 -0
  178. package/dist/services/ziwei/calculators/DecadeCalculator.js.map +1 -0
  179. package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.d.ts +28 -0
  180. package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.d.ts.map +1 -0
  181. package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.js +84 -0
  182. package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.js.map +1 -0
  183. package/dist/services/ziwei/calculators/HourlyCalculator.d.ts +41 -0
  184. package/dist/services/ziwei/calculators/HourlyCalculator.d.ts.map +1 -0
  185. package/dist/services/ziwei/calculators/HourlyCalculator.js +139 -0
  186. package/dist/services/ziwei/calculators/HourlyCalculator.js.map +1 -0
  187. package/dist/services/ziwei/calculators/MinorLimitCalculator.d.ts +30 -0
  188. package/dist/services/ziwei/calculators/MinorLimitCalculator.d.ts.map +1 -0
  189. package/dist/services/ziwei/calculators/MinorLimitCalculator.js +90 -0
  190. package/dist/services/ziwei/calculators/MinorLimitCalculator.js.map +1 -0
  191. package/dist/services/ziwei/calculators/MonthlyCalculator.d.ts +39 -0
  192. package/dist/services/ziwei/calculators/MonthlyCalculator.d.ts.map +1 -0
  193. package/dist/services/ziwei/calculators/MonthlyCalculator.js +128 -0
  194. package/dist/services/ziwei/calculators/MonthlyCalculator.js.map +1 -0
  195. package/dist/services/ziwei/calculators/MutagenCalculator.d.ts +20 -0
  196. package/dist/services/ziwei/calculators/MutagenCalculator.d.ts.map +1 -0
  197. package/dist/services/ziwei/calculators/MutagenCalculator.js +121 -0
  198. package/dist/services/ziwei/calculators/MutagenCalculator.js.map +1 -0
  199. package/dist/services/ziwei/calculators/PalaceDynamicCalculator.d.ts +35 -0
  200. package/dist/services/ziwei/calculators/PalaceDynamicCalculator.d.ts.map +1 -0
  201. package/dist/services/ziwei/calculators/PalaceDynamicCalculator.js +55 -0
  202. package/dist/services/ziwei/calculators/PalaceDynamicCalculator.js.map +1 -0
  203. package/dist/services/ziwei/calculators/YearlyCalculator.d.ts +35 -0
  204. package/dist/services/ziwei/calculators/YearlyCalculator.d.ts.map +1 -0
  205. package/dist/services/ziwei/calculators/YearlyCalculator.js +119 -0
  206. package/dist/services/ziwei/calculators/YearlyCalculator.js.map +1 -0
  207. package/dist/services/ziwei/index.d.ts +15 -0
  208. package/dist/services/ziwei/index.d.ts.map +1 -0
  209. package/dist/services/ziwei/index.js +48 -0
  210. package/dist/services/ziwei/index.js.map +1 -0
  211. package/dist/services/ziwei/transformers/PalaceTransformer.d.ts +62 -0
  212. package/dist/services/ziwei/transformers/PalaceTransformer.d.ts.map +1 -0
  213. package/dist/services/ziwei/transformers/PalaceTransformer.js +153 -0
  214. package/dist/services/ziwei/transformers/PalaceTransformer.js.map +1 -0
  215. package/dist/services/ziwei/types.d.ts +185 -0
  216. package/dist/services/ziwei/types.d.ts.map +1 -0
  217. package/dist/services/ziwei/types.js +54 -0
  218. package/dist/services/ziwei/types.js.map +1 -0
  219. package/dist/shared/logger.d.ts +51 -0
  220. package/dist/shared/logger.d.ts.map +1 -0
  221. package/dist/shared/logger.js +136 -0
  222. package/dist/shared/logger.js.map +1 -0
  223. package/dist/shared/types.d.ts +91 -0
  224. package/dist/shared/types.d.ts.map +1 -0
  225. package/dist/shared/types.js +7 -0
  226. package/dist/shared/types.js.map +1 -0
  227. package/dist/utils/ageCalculator.d.ts +30 -0
  228. package/dist/utils/ageCalculator.d.ts.map +1 -0
  229. package/dist/utils/ageCalculator.js +51 -0
  230. package/dist/utils/ageCalculator.js.map +1 -0
  231. package/package.json +54 -0
@@ -0,0 +1,1150 @@
1
+ "use strict";
2
+ /**
3
+ * Pattern Analyzer
4
+ * Implements taro-bazi's getSituation pattern recognition system
5
+ * Analyzes BaZi chart patterns and overall structure
6
+ * Returns Chinese text data for UI translation
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PatternAnalyzer = void 0;
10
+ const bazi_1 = require("../../../core/constants/bazi");
11
+ const RelationsAnalyzer_1 = require("./RelationsAnalyzer");
12
+ class PatternAnalyzer {
13
+ /**
14
+ * Main pattern analysis method - implements taro-bazi's getSituation
15
+ */
16
+ static analyze(chart, relationsResult, strengthAnalysis) {
17
+ // Input validation
18
+ if (!chart || !chart.day || !chart.day.stem) {
19
+ throw new Error('Invalid chart data: missing day master');
20
+ }
21
+ // If relations not provided, calculate them
22
+ if (!relationsResult) {
23
+ relationsResult = RelationsAnalyzer_1.RelationsAnalyzer.analyze(chart);
24
+ }
25
+ // Step 1: Analyze day master strength
26
+ const dayMasterAnalysis = strengthAnalysis
27
+ ? this.convertStrengthAnalysis(strengthAnalysis)
28
+ : this.analyzeDayMasterStrength(chart, relationsResult);
29
+ // Validate day master analysis
30
+ if (!dayMasterAnalysis || dayMasterAnalysis.strength === undefined) {
31
+ throw new Error('Day master analysis failed: invalid strength data');
32
+ }
33
+ // Step 2: Identify primary pattern
34
+ const primaryPattern = this.identifyPrimaryPattern(chart, dayMasterAnalysis, relationsResult);
35
+ // Critical validation: ensure primaryPattern is never null
36
+ if (!primaryPattern) {
37
+ throw new Error('Failed to identify primary pattern - this should never happen');
38
+ }
39
+ // Step 3: Find secondary patterns
40
+ const secondaryPatterns = this.findSecondaryPatterns(chart, relationsResult);
41
+ // Step 4: Analyze chart structure
42
+ const chartStructure = this.analyzeChartStructure(chart, dayMasterAnalysis, primaryPattern);
43
+ // Step 5: Identify special features
44
+ const specialFeatures = this.identifySpecialFeatures(chart, relationsResult);
45
+ // Step 6: Generate recommendations
46
+ const recommendations = this.generateRecommendations(primaryPattern, chartStructure);
47
+ return {
48
+ primaryPattern,
49
+ secondaryPatterns,
50
+ chartStructure,
51
+ specialFeatures,
52
+ recommendations
53
+ };
54
+ }
55
+ /**
56
+ * Analyze day master strength using taro-bazi method
57
+ */
58
+ static analyzeDayMasterStrength(chart, relationsResult) {
59
+ let strength = 0;
60
+ const dayMaster = chart.day.stem;
61
+ const dayMasterElement = this.getStemElement(dayMaster);
62
+ const supportingElements = [];
63
+ const drainingElements = [];
64
+ // Count same element stems (比劫)
65
+ const allStems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
66
+ const sameElementCount = allStems.filter(stem => this.getStemElement(stem) === dayMasterElement).length;
67
+ strength += sameElementCount * 8;
68
+ // Count generating element stems (印星)
69
+ const generatingElement = this.getGeneratingElement(dayMasterElement);
70
+ const generatingCount = allStems.filter(stem => this.getStemElement(stem) === generatingElement).length;
71
+ strength += generatingCount * 6;
72
+ if (generatingCount > 0)
73
+ supportingElements.push(generatingElement);
74
+ // Count branches that support day master
75
+ const allBranches = [chart.year.branch, chart.month.branch, chart.day.branch, chart.hour.branch];
76
+ allBranches.forEach(branch => {
77
+ const branchElement = this.getBranchElement(branch);
78
+ if (branchElement === dayMasterElement || branchElement === generatingElement) {
79
+ strength += 4;
80
+ if (!supportingElements.includes(branchElement)) {
81
+ supportingElements.push(branchElement);
82
+ }
83
+ }
84
+ });
85
+ // Subtract draining elements
86
+ const controlledElement = this.getControlledElement(dayMasterElement);
87
+ const controllingElement = this.getControllingElement(dayMasterElement);
88
+ const drainingCount = allStems.filter(stem => {
89
+ const element = this.getStemElement(stem);
90
+ return element === controlledElement || element === controllingElement;
91
+ }).length;
92
+ strength -= drainingCount * 4;
93
+ if (drainingCount > 0) {
94
+ if (!drainingElements.includes(controlledElement))
95
+ drainingElements.push(controlledElement);
96
+ if (!drainingElements.includes(controllingElement))
97
+ drainingElements.push(controllingElement);
98
+ }
99
+ // Factor in relationships
100
+ const relationshipModifier = RelationsAnalyzer_1.RelationsAnalyzer.getRelationshipModifier(relationsResult);
101
+ strength += relationshipModifier * 10;
102
+ // Determine strength type
103
+ let type;
104
+ if (strength >= 80)
105
+ type = '极端';
106
+ else if (strength >= 60)
107
+ type = '身强';
108
+ else if (strength >= 40)
109
+ type = '平衡';
110
+ else
111
+ type = '身弱';
112
+ return { strength, type, supportingElements, drainingElements };
113
+ }
114
+ /**
115
+ * Identify primary chart pattern
116
+ */
117
+ static identifyPrimaryPattern(chart, dayMasterAnalysis, relationsResult) {
118
+ const { strength, type } = dayMasterAnalysis;
119
+ // Priority order of pattern detection (highest to lowest)
120
+ const patterns = [];
121
+ // 1. Check for transformation patterns (化氣格) - highest priority
122
+ const transformationPattern = this.checkTransformationPattern(chart, relationsResult);
123
+ if (transformationPattern) {
124
+ patterns.push({ ...transformationPattern, priority: 10 });
125
+ }
126
+ // 2. Check for follow patterns (從格)
127
+ const followPattern = this.checkFollowPatterns(chart, dayMasterAnalysis, relationsResult);
128
+ if (followPattern) {
129
+ patterns.push({ ...followPattern, priority: 9 });
130
+ }
131
+ // 3. Check for dominant element patterns (專旺格)
132
+ const dominantPattern = this.checkDominantElementPattern(chart, relationsResult);
133
+ if (dominantPattern) {
134
+ patterns.push({ ...dominantPattern, priority: 8 });
135
+ }
136
+ // 4. Check for special structures
137
+ const specialPattern = this.checkSpecialPatterns(chart, relationsResult);
138
+ if (specialPattern) {
139
+ patterns.push({ ...specialPattern, priority: 7 });
140
+ }
141
+ // 5. Check for traditional patterns (建祿格, 羊刃格, etc.)
142
+ const traditionalPattern = this.checkTraditionalPatterns(chart);
143
+ if (traditionalPattern) {
144
+ patterns.push({ ...traditionalPattern, priority: 6 });
145
+ }
146
+ // 6. Regular patterns based on day master strength
147
+ if (type === '身強' || type === '身强') {
148
+ patterns.push({
149
+ type: '身旺格',
150
+ strength: 7,
151
+ description: '日主強旺,精力充沛,適合主動發展',
152
+ priority: 5,
153
+ characteristics: ['精力充沛', '領導能力強']
154
+ });
155
+ }
156
+ else if (type === '身弱') {
157
+ patterns.push({
158
+ type: '身弱格',
159
+ strength: 7,
160
+ description: '日主較弱,需要扶助,適合穩健發展',
161
+ priority: 5,
162
+ characteristics: ['深思熟慮', '善於合作']
163
+ });
164
+ }
165
+ else if (type === '极端' || type === '極端') {
166
+ patterns.push({
167
+ type: '太旺格',
168
+ strength: 6,
169
+ description: '日主過旺,需要宣洩,注意平衡',
170
+ priority: 4,
171
+ characteristics: ['能量強烈', '需要平衡']
172
+ });
173
+ }
174
+ // 7. Default to regular pattern - ALWAYS ensure we have at least one pattern
175
+ if (patterns.length === 0) {
176
+ patterns.push({
177
+ type: '正格',
178
+ strength: 5,
179
+ description: '標準格局,五行較為平衡',
180
+ priority: 3,
181
+ characteristics: ['平衡穩定', '發展均衡']
182
+ });
183
+ }
184
+ // Return the highest priority pattern - guaranteed to exist
185
+ const selectedPattern = patterns.sort((a, b) => b.priority - a.priority)[0];
186
+ // Final safety check
187
+ if (!selectedPattern) {
188
+ // Emergency fallback - should never reach here
189
+ return {
190
+ type: '正格',
191
+ strength: 5,
192
+ description: '標準格局,五行較為平衡',
193
+ priority: 3,
194
+ characteristics: ['平衡穩定', '發展均衡']
195
+ };
196
+ }
197
+ return selectedPattern;
198
+ }
199
+ /**
200
+ * Check for follow-strong pattern (從強格)
201
+ */
202
+ static isFollowStrongPattern(chart, relationsResult) {
203
+ // Day master must be extremely strong with overwhelming support
204
+ const dayMaster = chart.day.stem;
205
+ const dayMasterElement = this.getStemElement(dayMaster);
206
+ const allStems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
207
+ const supportCount = allStems.filter(stem => {
208
+ const element = this.getStemElement(stem);
209
+ return element === dayMasterElement || element === this.getGeneratingElement(dayMasterElement);
210
+ }).length;
211
+ // Must have strong relationship support
212
+ const hasStrongSupport = relationsResult.threeHarmonies.length > 0 ||
213
+ relationsResult.sixHarmonies.length >= 2;
214
+ return supportCount >= 3 && hasStrongSupport;
215
+ }
216
+ /**
217
+ * Check for follow-weak pattern (從弱格)
218
+ */
219
+ static isFollowWeakPattern(chart) {
220
+ const dayMaster = chart.day.stem;
221
+ const dayMasterElement = this.getStemElement(dayMaster);
222
+ const allStems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
223
+ const supportCount = allStems.filter(stem => {
224
+ const element = this.getStemElement(stem);
225
+ return element === dayMasterElement || element === this.getGeneratingElement(dayMasterElement);
226
+ }).length;
227
+ // Day master has minimal support (only itself)
228
+ return supportCount <= 1;
229
+ }
230
+ /**
231
+ * Check for special structure patterns
232
+ */
233
+ static isSpecialStructurePattern(chart, relationsResult) {
234
+ // Check for pure element combinations
235
+ return relationsResult.threeHarmonies.length > 0 ||
236
+ relationsResult.threeMeetings.length > 0 ||
237
+ this.hasDominantElement(chart);
238
+ }
239
+ /**
240
+ * Get special structure subtype
241
+ */
242
+ static getSpecialStructureSubtype(chart, relationsResult) {
243
+ if (relationsResult.threeHarmonies.length > 0) {
244
+ const harmony = relationsResult.threeHarmonies[0];
245
+ return `sanHe${harmony.element}`;
246
+ }
247
+ if (relationsResult.threeMeetings.length > 0) {
248
+ const meeting = relationsResult.threeMeetings[0];
249
+ return `sanHui${meeting.element}`;
250
+ }
251
+ return 'qita';
252
+ }
253
+ /**
254
+ * Check if chart has dominant element
255
+ */
256
+ static hasDominantElement(chart) {
257
+ const allStems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
258
+ const elementCounts = {};
259
+ allStems.forEach(stem => {
260
+ const element = this.getStemElement(stem);
261
+ elementCounts[element] = (elementCounts[element] || 0) + 1;
262
+ });
263
+ return Object.values(elementCounts).some(count => count >= 3);
264
+ }
265
+ /**
266
+ * Find secondary patterns
267
+ */
268
+ static findSecondaryPatterns(chart, relationsResult) {
269
+ const patterns = [];
270
+ // Check for noble person patterns
271
+ if (this.hasNoblePersonPattern(chart)) {
272
+ patterns.push({
273
+ type: '天乙貴人',
274
+ strength: 6,
275
+ description: '天乙貴人星入命,有貴人相助'
276
+ });
277
+ }
278
+ // Check for wealth patterns
279
+ if (this.hasWealthPattern(chart)) {
280
+ patterns.push({
281
+ type: '財星格',
282
+ strength: 5,
283
+ description: '財星旺盛,適合經商或理財'
284
+ });
285
+ }
286
+ // Check for officer patterns
287
+ if (this.hasOfficerPattern(chart)) {
288
+ patterns.push({
289
+ type: '官星格',
290
+ strength: 5,
291
+ description: '官星有力,適合公職或管理'
292
+ });
293
+ }
294
+ return patterns;
295
+ }
296
+ /**
297
+ * Analyze overall chart structure
298
+ */
299
+ static analyzeChartStructure(chart, dayMasterAnalysis, primaryPattern) {
300
+ const { type: dayMasterType } = dayMasterAnalysis;
301
+ // Determine useful and avoid gods based on pattern
302
+ const { usefulGods, avoidGods } = this.determineUsefulGods(chart, primaryPattern, dayMasterAnalysis);
303
+ // Calculate structure score
304
+ let structureScore = 50;
305
+ if (primaryPattern.strength >= 8)
306
+ structureScore += 20;
307
+ if (dayMasterType === '平衡')
308
+ structureScore += 15;
309
+ if (usefulGods.length > 0)
310
+ structureScore += 10;
311
+ // Determine balance type
312
+ let balanceType = '平衡';
313
+ if (dayMasterAnalysis.strength >= 80)
314
+ balanceType = '極端';
315
+ else if (dayMasterAnalysis.strength <= 20)
316
+ balanceType = '極端';
317
+ else if (Math.abs(dayMasterAnalysis.strength - 50) > 20)
318
+ balanceType = '不平衡';
319
+ return {
320
+ dayMasterType: dayMasterAnalysis.originalStrength
321
+ ? this.mapDetailedStrengthToType(dayMasterAnalysis.originalStrength)
322
+ : this.mapStrengthToType(dayMasterAnalysis.type, dayMasterAnalysis.strength),
323
+ usefulGods,
324
+ avoidGods,
325
+ structureScore: Math.min(100, structureScore),
326
+ balanceType
327
+ };
328
+ }
329
+ /**
330
+ * Convert StrengthAnalyzer result to internal format
331
+ */
332
+ static convertStrengthAnalysis(strengthAnalysis) {
333
+ // Map detailed strength to basic type
334
+ let type;
335
+ const dayMasterStrength = strengthAnalysis.dayMasterStrength;
336
+ switch (dayMasterStrength) {
337
+ case '衰極':
338
+ case '身弱':
339
+ case '偏弱':
340
+ type = '身弱';
341
+ break;
342
+ case '中和':
343
+ type = '平衡';
344
+ break;
345
+ case '偏強':
346
+ case '身旺':
347
+ case '旺極':
348
+ type = '身強';
349
+ break;
350
+ default:
351
+ type = '平衡';
352
+ }
353
+ return {
354
+ strength: strengthAnalysis.totalScore || 50,
355
+ type,
356
+ originalStrength: dayMasterStrength,
357
+ supportingElements: [],
358
+ drainingElements: []
359
+ };
360
+ }
361
+ /**
362
+ * Map strength analysis type to display type
363
+ */
364
+ static mapStrengthToType(type, strength) {
365
+ // For extreme cases, determine if it's extremely weak or strong
366
+ if (type === '極端') {
367
+ return strength <= 20 ? '身弱' : '身強';
368
+ }
369
+ // Map type to simplified categories
370
+ switch (type) {
371
+ case '身强': // 身强
372
+ return '身強';
373
+ case '身弱': // 身弱
374
+ return '身弱';
375
+ case '平衡': // 平衡
376
+ return '平衡';
377
+ default:
378
+ // For any other case, determine based on strength value
379
+ if (strength <= 40)
380
+ return '身弱';
381
+ if (strength >= 60)
382
+ return '身強';
383
+ return '平衡';
384
+ }
385
+ }
386
+ /**
387
+ * Map detailed strength levels to display type
388
+ */
389
+ static mapDetailedStrengthToType(strength) {
390
+ switch (strength) {
391
+ case '衰极':
392
+ case '身弱':
393
+ case '偏弱':
394
+ return '身弱';
395
+ case '中和':
396
+ return '平衡';
397
+ case '偏强':
398
+ case '身旺':
399
+ case '旺极':
400
+ return '身強';
401
+ default:
402
+ return '平衡'; // Default to balanced for unknown values
403
+ }
404
+ }
405
+ /**
406
+ * Determine useful and avoid gods based on pattern type
407
+ * This affects YongShen determination
408
+ */
409
+ static determineUsefulGods(chart, primaryPattern, dayMasterAnalysis) {
410
+ const usefulGods = [];
411
+ const avoidGods = [];
412
+ const dayMasterElement = this.getStemElement(chart.day.stem);
413
+ const patternType = primaryPattern.type;
414
+ // Pattern-specific god determination
415
+ switch (patternType) {
416
+ // Follow patterns - go with the flow
417
+ case '從旺格':
418
+ case '從強格':
419
+ // Support the strong trend
420
+ usefulGods.push(dayMasterElement);
421
+ usefulGods.push(this.getGeneratingElement(dayMasterElement));
422
+ avoidGods.push(this.getControllingElement(dayMasterElement));
423
+ avoidGods.push(this.getControlledElement(dayMasterElement));
424
+ break;
425
+ case '從兒格':
426
+ // Support output elements
427
+ const outputElement = this.getControlledElement(dayMasterElement);
428
+ usefulGods.push(outputElement);
429
+ usefulGods.push(this.getControlledElement(outputElement));
430
+ avoidGods.push(this.getControllingElement(dayMasterElement));
431
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
432
+ break;
433
+ case '從財格':
434
+ // Support wealth elements
435
+ const wealthElement = this.getControllingElement(this.getControlledElement(dayMasterElement));
436
+ usefulGods.push(wealthElement);
437
+ usefulGods.push(this.getControlledElement(dayMasterElement));
438
+ avoidGods.push(dayMasterElement);
439
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
440
+ break;
441
+ case '從官格':
442
+ // Support officer elements
443
+ const officerElement = this.getControllingElement(dayMasterElement);
444
+ usefulGods.push(officerElement);
445
+ usefulGods.push(this.getGeneratingElement(officerElement));
446
+ avoidGods.push(dayMasterElement);
447
+ avoidGods.push(this.getControlledElement(dayMasterElement));
448
+ break;
449
+ case '從勢格':
450
+ case '從弱格':
451
+ // Support the dominant elements in the chart
452
+ const elementCounts = this.countElements(chart);
453
+ const sortedElements = Object.entries(elementCounts)
454
+ .filter(([elem,]) => elem !== dayMasterElement)
455
+ .sort(([, a], [, b]) => b - a);
456
+ if (sortedElements.length > 0) {
457
+ usefulGods.push(sortedElements[0][0]);
458
+ if (sortedElements.length > 1) {
459
+ usefulGods.push(sortedElements[1][0]);
460
+ }
461
+ }
462
+ avoidGods.push(dayMasterElement);
463
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
464
+ break;
465
+ // Transformation patterns
466
+ case '化氣格':
467
+ // Support the transformed element
468
+ const transformedElement = primaryPattern.subtype?.split('化氣')[1];
469
+ if (transformedElement) {
470
+ usefulGods.push(transformedElement);
471
+ usefulGods.push(this.getGeneratingElement(transformedElement));
472
+ // Avoid elements that conflict with transformation
473
+ avoidGods.push(this.getControllingElement(transformedElement));
474
+ }
475
+ break;
476
+ // Dominant element patterns
477
+ case '曲直格': // Wood
478
+ usefulGods.push('木', '水');
479
+ avoidGods.push('金');
480
+ break;
481
+ case '炎上格': // Fire
482
+ usefulGods.push('火', '木');
483
+ avoidGods.push('水');
484
+ break;
485
+ case '稼穡格': // Earth
486
+ usefulGods.push('土', '火');
487
+ avoidGods.push('木');
488
+ break;
489
+ case '從革格': // Metal
490
+ usefulGods.push('金', '土');
491
+ avoidGods.push('火');
492
+ break;
493
+ case '潤下格': // Water
494
+ usefulGods.push('水', '金');
495
+ avoidGods.push('土');
496
+ break;
497
+ // Traditional patterns
498
+ case '建祿格':
499
+ case '羊刃格':
500
+ // These patterns indicate strong day master
501
+ usefulGods.push(this.getControlledElement(dayMasterElement));
502
+ usefulGods.push(this.getControllingElement(this.getControlledElement(dayMasterElement)));
503
+ avoidGods.push(dayMasterElement);
504
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
505
+ break;
506
+ // Regular strength-based patterns
507
+ case '身弱格':
508
+ // Weak day master needs support
509
+ usefulGods.push(this.getGeneratingElement(dayMasterElement));
510
+ usefulGods.push(dayMasterElement);
511
+ avoidGods.push(this.getControlledElement(dayMasterElement));
512
+ avoidGods.push(this.getControllingElement(dayMasterElement));
513
+ break;
514
+ case '身旺格':
515
+ case '太旺格':
516
+ // Strong day master needs draining
517
+ usefulGods.push(this.getControlledElement(dayMasterElement));
518
+ usefulGods.push(this.getControllingElement(this.getControlledElement(dayMasterElement)));
519
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
520
+ avoidGods.push(dayMasterElement);
521
+ break;
522
+ default:
523
+ // Balanced pattern - flexible approach
524
+ if (dayMasterAnalysis.strength > 50) {
525
+ usefulGods.push(this.getControlledElement(dayMasterElement));
526
+ avoidGods.push(this.getGeneratingElement(dayMasterElement));
527
+ }
528
+ else {
529
+ usefulGods.push(this.getGeneratingElement(dayMasterElement));
530
+ avoidGods.push(this.getControlledElement(dayMasterElement));
531
+ }
532
+ break;
533
+ }
534
+ // Remove duplicates
535
+ return {
536
+ usefulGods: [...new Set(usefulGods)],
537
+ avoidGods: [...new Set(avoidGods)]
538
+ };
539
+ }
540
+ /**
541
+ * Identify special features
542
+ */
543
+ static identifySpecialFeatures(chart, relationsResult) {
544
+ const features = [];
545
+ // Check for major relationship patterns
546
+ if (relationsResult.threeHarmonies.length > 0) {
547
+ features.push({
548
+ type: '三合',
549
+ description: '出現三合局,力量集中',
550
+ impact: '正面'
551
+ });
552
+ }
553
+ if (relationsResult.sixConflicts.length >= 2) {
554
+ features.push({
555
+ type: '多衝',
556
+ description: '出現多個衝克關係,易有動盪',
557
+ impact: '负面'
558
+ });
559
+ }
560
+ // Check for empty pillars
561
+ if (this.hasEmptyPillars(chart)) {
562
+ features.push({
563
+ type: '空亡',
564
+ description: '命中有空亡,需特別注意',
565
+ impact: '中性'
566
+ });
567
+ }
568
+ return features;
569
+ }
570
+ /**
571
+ * Generate pattern-based recommendations
572
+ */
573
+ static generateRecommendations(primaryPattern, chartStructure) {
574
+ const favorableElements = [];
575
+ const unfavorableElements = [];
576
+ const careerSuggestions = [];
577
+ const lifestyleSuggestions = [];
578
+ // Extract elements from useful/avoid gods
579
+ chartStructure.usefulGods.forEach((god) => {
580
+ const element = god.replace('elements.', '');
581
+ favorableElements.push(element);
582
+ });
583
+ chartStructure.avoidGods.forEach((god) => {
584
+ const element = god.replace('elements.', '');
585
+ unfavorableElements.push(element);
586
+ });
587
+ // Pattern-specific career and lifestyle suggestions
588
+ const patternType = primaryPattern.type;
589
+ switch (patternType) {
590
+ // Follow patterns
591
+ case '從旺格':
592
+ case '從強格':
593
+ careerSuggestions.push('適合領導職位');
594
+ careerSuggestions.push('獨立創業');
595
+ careerSuggestions.push('管理經營');
596
+ lifestyleSuggestions.push('果斷決策');
597
+ lifestyleSuggestions.push('保持自信');
598
+ break;
599
+ case '從兒格':
600
+ careerSuggestions.push('創意產業');
601
+ careerSuggestions.push('藝術表演');
602
+ careerSuggestions.push('媒體傳播');
603
+ lifestyleSuggestions.push('充分表達自我');
604
+ lifestyleSuggestions.push('保持創新思維');
605
+ break;
606
+ case '從財格':
607
+ careerSuggestions.push('商業經營');
608
+ careerSuggestions.push('金融理財');
609
+ careerSuggestions.push('投資管理');
610
+ lifestyleSuggestions.push('講求實際');
611
+ lifestyleSuggestions.push('重視物質基礎');
612
+ break;
613
+ case '從官格':
614
+ careerSuggestions.push('公職人員');
615
+ careerSuggestions.push('管理階層');
616
+ careerSuggestions.push('法律相關');
617
+ lifestyleSuggestions.push('紀律嚴明');
618
+ lifestyleSuggestions.push('組織有序');
619
+ break;
620
+ case '從勢格':
621
+ case '從弱格':
622
+ careerSuggestions.push('支援服務');
623
+ careerSuggestions.push('服務業');
624
+ careerSuggestions.push('團隊合作');
625
+ lifestyleSuggestions.push('靈活適應');
626
+ lifestyleSuggestions.push('合作共贏');
627
+ break;
628
+ // Transformation patterns
629
+ case '化氣格':
630
+ careerSuggestions.push('專業技術');
631
+ careerSuggestions.push('技術研發');
632
+ lifestyleSuggestions.push('專注目標');
633
+ lifestyleSuggestions.push('不斷轉型');
634
+ break;
635
+ // Dominant element patterns
636
+ case '曲直格': // Wood
637
+ careerSuggestions.push('教育培訓');
638
+ careerSuggestions.push('成長發展');
639
+ careerSuggestions.push('環保產業');
640
+ lifestyleSuggestions.push('持續成長');
641
+ lifestyleSuggestions.push('不斷學習');
642
+ break;
643
+ case '炎上格': // Fire
644
+ careerSuggestions.push('娛樂表演');
645
+ careerSuggestions.push('科技產業');
646
+ careerSuggestions.push('能源產業');
647
+ lifestyleSuggestions.push('熱情奔放');
648
+ lifestyleSuggestions.push('充滿活力');
649
+ break;
650
+ case '稼穡格': // Earth
651
+ careerSuggestions.push('房地產業');
652
+ careerSuggestions.push('農業發展');
653
+ careerSuggestions.push('諮詢服務');
654
+ lifestyleSuggestions.push('穩定踏實');
655
+ lifestyleSuggestions.push('養育關懷');
656
+ break;
657
+ case '從革格': // Metal
658
+ careerSuggestions.push('工程技術');
659
+ careerSuggestions.push('軍事國防');
660
+ careerSuggestions.push('精密製造');
661
+ lifestyleSuggestions.push('結構嚴謹');
662
+ lifestyleSuggestions.push('精緷優雅');
663
+ break;
664
+ case '潤下格': // Water
665
+ careerSuggestions.push('傳播媒體');
666
+ careerSuggestions.push('物流運輸');
667
+ careerSuggestions.push('研究開發');
668
+ lifestyleSuggestions.push('靈活變通');
669
+ lifestyleSuggestions.push('智慧思考');
670
+ break;
671
+ // Special patterns
672
+ case '五行俱全格':
673
+ careerSuggestions.push('多元發展');
674
+ careerSuggestions.push('全能型人才');
675
+ lifestyleSuggestions.push('平衡發展');
676
+ lifestyleSuggestions.push('多元興趣');
677
+ break;
678
+ case '魁罡格':
679
+ careerSuggestions.push('領導管理');
680
+ careerSuggestions.push('軍警法務');
681
+ careerSuggestions.push('執法部門');
682
+ lifestyleSuggestions.push('威嚴果斷');
683
+ lifestyleSuggestions.push('決策果敢');
684
+ break;
685
+ // Traditional patterns
686
+ case '建祿格':
687
+ careerSuggestions.push('自主創業');
688
+ careerSuggestions.push('專業技能');
689
+ lifestyleSuggestions.push('獨立自主');
690
+ lifestyleSuggestions.push('自力更生');
691
+ break;
692
+ case '羊刃格':
693
+ careerSuggestions.push('競爭激烈行業');
694
+ careerSuggestions.push('體育運動');
695
+ careerSuggestions.push('業務銷售');
696
+ lifestyleSuggestions.push('積極主動');
697
+ lifestyleSuggestions.push('喜歡競爭');
698
+ break;
699
+ // Regular patterns
700
+ case '身旺格':
701
+ careerSuggestions.push('領導管理');
702
+ careerSuggestions.push('積極開拓');
703
+ lifestyleSuggestions.push('充滿活力');
704
+ lifestyleSuggestions.push('主動出擊');
705
+ break;
706
+ case '身弱格':
707
+ careerSuggestions.push('支援服務');
708
+ careerSuggestions.push('分析研究');
709
+ lifestyleSuggestions.push('深思熟慮');
710
+ lifestyleSuggestions.push('謹慎小心');
711
+ break;
712
+ default:
713
+ careerSuggestions.push('穩定職業');
714
+ careerSuggestions.push('傳統行業');
715
+ lifestyleSuggestions.push('平衡生活');
716
+ lifestyleSuggestions.push('中庸之道');
717
+ break;
718
+ }
719
+ // Add general suggestions based on structure score
720
+ if (chartStructure.structureScore < 50) {
721
+ lifestyleSuggestions.push('持續改善');
722
+ lifestyleSuggestions.push('尋求指導');
723
+ }
724
+ return {
725
+ favorableElements: [...new Set(favorableElements)],
726
+ unfavorableElements: [...new Set(unfavorableElements)],
727
+ careerSuggestions: [...new Set(careerSuggestions)],
728
+ lifestyleSuggestions: [...new Set(lifestyleSuggestions)]
729
+ };
730
+ }
731
+ /**
732
+ * Check for transformation patterns (化氣格)
733
+ * Based on stem combinations with monthly branch support
734
+ */
735
+ static checkTransformationPattern(chart, relationsResult) {
736
+ const dayMaster = chart.day.stem;
737
+ const allStems = [chart.year.stem, chart.month.stem, chart.hour.stem];
738
+ const monthBranch = chart.month.branch;
739
+ // Transformation combinations: [stem1, stem2, supportBranches, element]
740
+ const transformations = [
741
+ ['甲', '己', ['辰', '戌', '丑', '未'], '土'],
742
+ ['乙', '庚', ['申', '酉', '戌'], '金'],
743
+ ['丙', '辛', ['亥', '子', '丑'], '水'],
744
+ ['丁', '壬', ['寅', '卯', '辰'], '木'],
745
+ ['戊', '癸', ['巳', '午', '未'], '火']
746
+ ];
747
+ for (const [stem1, stem2, supportBranches, element] of transformations) {
748
+ if (dayMaster === stem1 && allStems.includes(stem2)) {
749
+ if (supportBranches.includes(monthBranch)) {
750
+ return {
751
+ type: '化氣格',
752
+ subtype: `化氣${element}格`,
753
+ strength: 9,
754
+ description: `化為${element}氣,特殊轉化格局`,
755
+ priority: 10,
756
+ characteristics: ['轉化特質', `${element}行屬性`]
757
+ };
758
+ }
759
+ }
760
+ else if (dayMaster === stem2 && allStems.includes(stem1)) {
761
+ if (supportBranches.includes(monthBranch)) {
762
+ return {
763
+ type: '化氣格',
764
+ subtype: `化氣${element}格`,
765
+ strength: 9,
766
+ description: `化為${element}氣,特殊轉化格局`,
767
+ priority: 10,
768
+ characteristics: ['轉化特質', `${element}行屬性`]
769
+ };
770
+ }
771
+ }
772
+ }
773
+ return null;
774
+ }
775
+ /**
776
+ * Check for follow patterns (從格)
777
+ * Including 從兒格, 從財格, 從官格, 從勢格, 從旺格
778
+ */
779
+ static checkFollowPatterns(chart, dayMasterAnalysis, relationsResult) {
780
+ const dayMaster = chart.day.stem;
781
+ const dayMasterElement = this.getStemElement(dayMaster);
782
+ const { strength, supportingElements, drainingElements } = dayMasterAnalysis;
783
+ // Count ten gods appearances
784
+ const tenGodCounts = this.countTenGods(chart);
785
+ // 從旺格 - Follow strong pattern
786
+ if (strength >= 80 && supportingElements.length >= 2) {
787
+ return {
788
+ type: '從旺格',
789
+ strength: 9,
790
+ description: '日主極強,順勢而為',
791
+ priority: 9,
792
+ characteristics: ['極度強旺', '獨立自主']
793
+ };
794
+ }
795
+ // 從弱格 - Follow weak pattern (day master has minimal support)
796
+ if (strength <= 20 && supportingElements.length === 0) {
797
+ // Check which element is dominant to determine subtype
798
+ // 從兒格 - Follow output pattern
799
+ if (tenGodCounts['食神'] + tenGodCounts['傷官'] >= 3) {
800
+ return {
801
+ type: '從兒格',
802
+ strength: 9,
803
+ description: '食傷旺盛,從兒之格',
804
+ priority: 9,
805
+ characteristics: ['創意豐富', '表達能力強']
806
+ };
807
+ }
808
+ // 從財格 - Follow wealth pattern
809
+ if (tenGodCounts['正財'] + tenGodCounts['偏財'] >= 3) {
810
+ return {
811
+ type: '從財格',
812
+ strength: 9,
813
+ description: '財星旺盛,從財之格',
814
+ priority: 9,
815
+ characteristics: ['財運亨通', '實際務實']
816
+ };
817
+ }
818
+ // 從官格 - Follow officer pattern
819
+ if (tenGodCounts['正官'] + tenGodCounts['七殺'] >= 3) {
820
+ return {
821
+ type: '從官格',
822
+ strength: 9,
823
+ description: '官星旺盛,從官之格',
824
+ priority: 9,
825
+ characteristics: ['權威影響力', '紀律嚴明']
826
+ };
827
+ }
828
+ // 從勢格 - Follow trend pattern (general weak follow)
829
+ return {
830
+ type: '從勢格',
831
+ strength: 8,
832
+ description: '順從大勢,從勢之格',
833
+ priority: 8,
834
+ characteristics: ['適應力強', '善於合作']
835
+ };
836
+ }
837
+ return null;
838
+ }
839
+ /**
840
+ * Check for dominant element patterns (專旺格)
841
+ * Including 曲直格, 炎上格, 稼穡格, 從革格, 潤下格
842
+ */
843
+ static checkDominantElementPattern(chart, relationsResult) {
844
+ const elementCounts = this.countElements(chart);
845
+ const dominantElement = Object.entries(elementCounts)
846
+ .sort(([, a], [, b]) => b - a)[0];
847
+ // Need at least 5 out of 8 positions to be the same element
848
+ if (dominantElement[1] >= 5) {
849
+ const element = dominantElement[0];
850
+ const patterns = {
851
+ '木': {
852
+ type: '曲直格',
853
+ description: '木氣純粹,曲直之格',
854
+ characteristics: ['生長發展', '靈活變通']
855
+ },
856
+ '火': {
857
+ type: '炎上格',
858
+ description: '火氣純粹,炎上之格',
859
+ characteristics: ['熱情奔放', '光明磊落']
860
+ },
861
+ '土': {
862
+ type: '稼穡格',
863
+ description: '土氣純粹,稼穡之格',
864
+ characteristics: ['穩定實在', '調和養育']
865
+ },
866
+ '金': {
867
+ type: '從革格',
868
+ description: '金氣純粹,從革之格',
869
+ characteristics: ['果敢決斷', '精緷完美']
870
+ },
871
+ '水': {
872
+ type: '潤下格',
873
+ description: '水氣純粹,潤下之格',
874
+ characteristics: ['流動變化', '智慧深沉']
875
+ }
876
+ };
877
+ if (patterns[element]) {
878
+ return {
879
+ ...patterns[element],
880
+ strength: 9,
881
+ priority: 8
882
+ };
883
+ }
884
+ }
885
+ return null;
886
+ }
887
+ /**
888
+ * Check for special patterns
889
+ * Including 兩神成象格, 五行俱全格, 天元一氣格, 地支一氣格, 魁罡格, 金神格
890
+ */
891
+ static checkSpecialPatterns(chart, relationsResult) {
892
+ // 五行俱全格 - All five elements present
893
+ const elementCounts = this.countElements(chart);
894
+ if (Object.keys(elementCounts).length === 5 && Object.values(elementCounts).every(count => count > 0)) {
895
+ return {
896
+ type: '五行俱全格',
897
+ strength: 8,
898
+ description: '五行俱全,各元素皆備',
899
+ priority: 7,
900
+ characteristics: ['完整無缺', '多才多藝']
901
+ };
902
+ }
903
+ // 兩神成象格 - Two elements dominate
904
+ const sortedElements = Object.entries(elementCounts)
905
+ .filter(([, count]) => count > 0)
906
+ .sort(([, a], [, b]) => b - a);
907
+ if (sortedElements.length === 2 && sortedElements[0][1] + sortedElements[1][1] >= 7) {
908
+ return {
909
+ type: '兩神成象格',
910
+ strength: 8,
911
+ description: '兩神成象,專精特化',
912
+ priority: 7,
913
+ characteristics: ['專注集中', '特化發展']
914
+ };
915
+ }
916
+ // 天元一氣格 - All heavenly stems are the same
917
+ const stems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
918
+ if (new Set(stems).size === 1) {
919
+ return {
920
+ type: '天元一氣格',
921
+ strength: 9,
922
+ description: '天元一氣,純粹集中',
923
+ priority: 8,
924
+ characteristics: ['純粹無雜', '高度集中']
925
+ };
926
+ }
927
+ // 地支一氣格 - All earthly branches are the same element
928
+ const branches = [chart.year.branch, chart.month.branch, chart.day.branch, chart.hour.branch];
929
+ const branchElements = branches.map(b => this.getBranchElement(b));
930
+ if (new Set(branchElements).size === 1) {
931
+ return {
932
+ type: '地支一氣格',
933
+ strength: 8,
934
+ description: '地支一氣,統一協調',
935
+ priority: 7,
936
+ characteristics: ['根基穩固', '統一協調']
937
+ };
938
+ }
939
+ // 魁罡格 - Day pillar is 庚辰, 庚戌, 戊辰, or 戊戌
940
+ const kuiGangPillars = ['庚辰', '庚戌', '戊辰', '戊戌'];
941
+ const dayPillar = chart.day.stem + chart.day.branch;
942
+ if (kuiGangPillars.includes(dayPillar)) {
943
+ return {
944
+ type: '魁罡格',
945
+ strength: 8,
946
+ description: '魁罡入命,威權顯赫',
947
+ priority: 7,
948
+ characteristics: ['權威強大', '威嚴統御']
949
+ };
950
+ }
951
+ // 金神格 - Specific combinations with metal elements
952
+ if (this.checkJinShenPattern(chart)) {
953
+ return {
954
+ type: '金神格',
955
+ strength: 8,
956
+ description: '金神入命,銳利精明',
957
+ priority: 7,
958
+ characteristics: ['銳利果敢', '策略精明']
959
+ };
960
+ }
961
+ return null;
962
+ }
963
+ /**
964
+ * Check for traditional patterns from taro-bazi
965
+ * Including 建祿格, 羊刃格, etc.
966
+ */
967
+ static checkTraditionalPatterns(chart) {
968
+ const dayMaster = chart.day.stem;
969
+ const monthBranch = chart.month.branch;
970
+ const monthHiddenStems = this.getHiddenStems(monthBranch);
971
+ // 建祿格 - Day master at prosperous position
972
+ if (monthHiddenStems[0] === dayMaster) {
973
+ return {
974
+ type: '建祿格',
975
+ strength: 8,
976
+ description: '月支帶祿,自力更生',
977
+ priority: 6,
978
+ characteristics: ['自力更生', '能力出眾']
979
+ };
980
+ }
981
+ // 羊刃格 - Yang blade pattern
982
+ const yangBladeMap = {
983
+ '甲': '卯', '丙': '午', '戊': '午', '庚': '酉', '壬': '子'
984
+ };
985
+ if (yangBladeMap[dayMaster] === monthBranch) {
986
+ return {
987
+ type: '羊刃格',
988
+ strength: 8,
989
+ description: '月支為刃,剛強威猛',
990
+ priority: 6,
991
+ characteristics: ['剛強進取', '競爭力強']
992
+ };
993
+ }
994
+ return null;
995
+ }
996
+ /**
997
+ * Count ten gods appearances in the chart
998
+ */
999
+ static countTenGods(chart) {
1000
+ const counts = {
1001
+ '比肩': 0, '劫財': 0, '食神': 0, '傷官': 0,
1002
+ '正財': 0, '偏財': 0, '正官': 0, '七殺': 0,
1003
+ '正印': 0, '偏印': 0
1004
+ };
1005
+ const dayMaster = chart.day.stem;
1006
+ const allStems = [chart.year.stem, chart.month.stem, chart.hour.stem];
1007
+ const allBranches = [chart.year.branch, chart.month.branch, chart.day.branch, chart.hour.branch];
1008
+ // Count stems
1009
+ allStems.forEach(stem => {
1010
+ const tenGod = bazi_1.TEN_GODS[dayMaster]?.[stem];
1011
+ if (tenGod && counts[tenGod] !== undefined) {
1012
+ counts[tenGod]++;
1013
+ }
1014
+ });
1015
+ // Count hidden stems in branches
1016
+ allBranches.forEach(branch => {
1017
+ const hiddenStems = this.getHiddenStems(branch);
1018
+ hiddenStems.forEach(stem => {
1019
+ const tenGod = bazi_1.TEN_GODS[dayMaster]?.[stem];
1020
+ if (tenGod && counts[tenGod] !== undefined) {
1021
+ counts[tenGod]++;
1022
+ }
1023
+ });
1024
+ });
1025
+ return counts;
1026
+ }
1027
+ /**
1028
+ * Count elements in the chart
1029
+ */
1030
+ static countElements(chart) {
1031
+ const counts = {
1032
+ '木': 0, '火': 0, '土': 0, '金': 0, '水': 0
1033
+ };
1034
+ // Count stem elements
1035
+ const allStems = [chart.year.stem, chart.month.stem, chart.day.stem, chart.hour.stem];
1036
+ allStems.forEach(stem => {
1037
+ const element = this.getStemElement(stem);
1038
+ if (element)
1039
+ counts[element]++;
1040
+ });
1041
+ // Count branch elements
1042
+ const allBranches = [chart.year.branch, chart.month.branch, chart.day.branch, chart.hour.branch];
1043
+ allBranches.forEach(branch => {
1044
+ const element = this.getBranchElement(branch);
1045
+ if (element)
1046
+ counts[element]++;
1047
+ });
1048
+ return counts;
1049
+ }
1050
+ /**
1051
+ * Check for Jin Shen pattern
1052
+ */
1053
+ static checkJinShenPattern(chart) {
1054
+ // Jin Shen pattern requires specific day pillars with metal dominance
1055
+ const jinShenDays = ['乙丑', '己巳', '癸酉'];
1056
+ const dayPillar = chart.day.stem + chart.day.branch;
1057
+ if (!jinShenDays.includes(dayPillar))
1058
+ return false;
1059
+ // Count metal elements
1060
+ const elementCounts = this.countElements(chart);
1061
+ return elementCounts['金'] >= 3;
1062
+ }
1063
+ /**
1064
+ * Get hidden stems for a branch
1065
+ */
1066
+ static getHiddenStems(branch) {
1067
+ const hiddenStemsMap = {
1068
+ '子': ['癸'],
1069
+ '丑': ['己', '癸', '辛'],
1070
+ '寅': ['甲', '丙', '戊'],
1071
+ '卯': ['乙'],
1072
+ '辰': ['戊', '乙', '癸'],
1073
+ '巳': ['丙', '戊', '庚'],
1074
+ '午': ['丁', '己'],
1075
+ '未': ['己', '丁', '乙'],
1076
+ '申': ['庚', '壬', '戊'],
1077
+ '酉': ['辛'],
1078
+ '戌': ['戊', '辛', '丁'],
1079
+ '亥': ['壬', '甲']
1080
+ };
1081
+ return hiddenStemsMap[branch] || [];
1082
+ }
1083
+ // Helper methods
1084
+ static hasNoblePersonPattern(chart) {
1085
+ // Implementation for noble person star detection
1086
+ // This would check for specific combinations that indicate noble person stars
1087
+ const dayMaster = chart.day.stem;
1088
+ const dayBranch = chart.day.branch;
1089
+ // Simplified noble person detection based on day master
1090
+ const noblePersonMap = {
1091
+ '甲': ['丑', '未'], '戊': ['丑', '未'],
1092
+ '乙': ['子', '申'], '己': ['子', '申'],
1093
+ '丙': ['亥', '酉'], '丁': ['亥', '酉'],
1094
+ '庚': ['寅', '午'], '辛': ['寅', '午'],
1095
+ '壬': ['卯', '巳'], '癸': ['卯', '巳']
1096
+ };
1097
+ const nobleBranches = noblePersonMap[dayMaster] || [];
1098
+ const allBranches = [chart.year.branch, chart.month.branch, chart.hour.branch];
1099
+ return allBranches.some(branch => nobleBranches.includes(branch));
1100
+ }
1101
+ static hasWealthPattern(chart) {
1102
+ const dayMaster = chart.day.stem;
1103
+ const allStems = [chart.year.stem, chart.month.stem, chart.hour.stem];
1104
+ return allStems.some(stem => {
1105
+ const tenGod = bazi_1.TEN_GODS[dayMaster]?.[stem];
1106
+ return tenGod === '正財' || tenGod === '偏財';
1107
+ });
1108
+ }
1109
+ static hasOfficerPattern(chart) {
1110
+ const dayMaster = chart.day.stem;
1111
+ const allStems = [chart.year.stem, chart.month.stem, chart.hour.stem];
1112
+ return allStems.some(stem => {
1113
+ const tenGod = bazi_1.TEN_GODS[dayMaster]?.[stem];
1114
+ return tenGod === '正官' || tenGod === '七殺';
1115
+ });
1116
+ }
1117
+ static hasEmptyPillars(chart) {
1118
+ // Check for missing elements or weak pillars
1119
+ return false; // Simplified
1120
+ }
1121
+ // Element relationship helpers
1122
+ static getStemElement(stem) {
1123
+ const stemData = bazi_1.HEAVENLY_STEMS.find(s => s.name === stem);
1124
+ return stemData?.element || '';
1125
+ }
1126
+ static getBranchElement(branch) {
1127
+ const branchData = bazi_1.EARTHLY_BRANCHES.find(b => b.name === branch);
1128
+ return branchData?.element || '';
1129
+ }
1130
+ static getGeneratingElement(element) {
1131
+ const cycle = {
1132
+ '水': '金', '木': '水', '火': '木', '土': '火', '金': '土'
1133
+ };
1134
+ return cycle[element] || '';
1135
+ }
1136
+ static getControlledElement(element) {
1137
+ const cycle = {
1138
+ '木': '火', '火': '土', '土': '金', '金': '水', '水': '木'
1139
+ };
1140
+ return cycle[element] || '';
1141
+ }
1142
+ static getControllingElement(element) {
1143
+ const cycle = {
1144
+ '木': '金', '火': '水', '土': '木', '金': '火', '水': '土'
1145
+ };
1146
+ return cycle[element] || '';
1147
+ }
1148
+ }
1149
+ exports.PatternAnalyzer = PatternAnalyzer;
1150
+ //# sourceMappingURL=PatternAnalyzer.js.map