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.
- package/LICENSE +201 -0
- package/README.md +118 -0
- package/dist/core/bazi/BaziCore.d.ts +112 -0
- package/dist/core/bazi/BaziCore.d.ts.map +1 -0
- package/dist/core/bazi/BaziCore.js +606 -0
- package/dist/core/bazi/BaziCore.js.map +1 -0
- package/dist/core/bazi/SolarTermCalculator.d.ts +46 -0
- package/dist/core/bazi/SolarTermCalculator.d.ts.map +1 -0
- package/dist/core/bazi/SolarTermCalculator.js +452 -0
- package/dist/core/bazi/SolarTermCalculator.js.map +1 -0
- package/dist/core/bazi/TrueSolarTime.d.ts +64 -0
- package/dist/core/bazi/TrueSolarTime.d.ts.map +1 -0
- package/dist/core/bazi/TrueSolarTime.js +210 -0
- package/dist/core/bazi/TrueSolarTime.js.map +1 -0
- package/dist/core/bazi/ephemerisData.d.ts +10 -0
- package/dist/core/bazi/ephemerisData.d.ts.map +1 -0
- package/dist/core/bazi/ephemerisData.js +88 -0
- package/dist/core/bazi/ephemerisData.js.map +1 -0
- package/dist/core/bazi/index.d.ts +8 -0
- package/dist/core/bazi/index.d.ts.map +1 -0
- package/dist/core/bazi/index.js +30 -0
- package/dist/core/bazi/index.js.map +1 -0
- package/dist/core/bazi/types.d.ts +116 -0
- package/dist/core/bazi/types.d.ts.map +1 -0
- package/dist/core/bazi/types.js +7 -0
- package/dist/core/bazi/types.js.map +1 -0
- package/dist/core/calendar/SolarTermsCalculator.d.ts +33 -0
- package/dist/core/calendar/SolarTermsCalculator.d.ts.map +1 -0
- package/dist/core/calendar/SolarTermsCalculator.js +111 -0
- package/dist/core/calendar/SolarTermsCalculator.js.map +1 -0
- package/dist/core/calendar/astronomicalCalendar.d.ts +74 -0
- package/dist/core/calendar/astronomicalCalendar.d.ts.map +1 -0
- package/dist/core/calendar/astronomicalCalendar.js +276 -0
- package/dist/core/calendar/astronomicalCalendar.js.map +1 -0
- package/dist/core/calendar/calendar.d.ts +81 -0
- package/dist/core/calendar/calendar.d.ts.map +1 -0
- package/dist/core/calendar/calendar.js +223 -0
- package/dist/core/calendar/calendar.js.map +1 -0
- package/dist/core/calendar/constants.d.ts +151 -0
- package/dist/core/calendar/constants.d.ts.map +1 -0
- package/dist/core/calendar/constants.js +97 -0
- package/dist/core/calendar/constants.js.map +1 -0
- package/dist/core/calendar/julian.d.ts +54 -0
- package/dist/core/calendar/julian.d.ts.map +1 -0
- package/dist/core/calendar/julian.js +142 -0
- package/dist/core/calendar/julian.js.map +1 -0
- package/dist/core/calendar/lunarCalendar.d.ts +79 -0
- package/dist/core/calendar/lunarCalendar.d.ts.map +1 -0
- package/dist/core/calendar/lunarCalendar.js +164 -0
- package/dist/core/calendar/lunarCalendar.js.map +1 -0
- package/dist/core/calendar/solarTerms.d.ts +105 -0
- package/dist/core/calendar/solarTerms.d.ts.map +1 -0
- package/dist/core/calendar/solarTerms.js +487 -0
- package/dist/core/calendar/solarTerms.js.map +1 -0
- package/dist/core/constants/bazi.d.ts +138 -0
- package/dist/core/constants/bazi.d.ts.map +1 -0
- package/dist/core/constants/bazi.js +332 -0
- package/dist/core/constants/bazi.js.map +1 -0
- package/dist/core/constants/index.d.ts +6 -0
- package/dist/core/constants/index.d.ts.map +1 -0
- package/dist/core/constants/index.js +37 -0
- package/dist/core/constants/index.js.map +1 -0
- package/dist/core/constants/positions.d.ts +27 -0
- package/dist/core/constants/positions.d.ts.map +1 -0
- package/dist/core/constants/positions.js +39 -0
- package/dist/core/constants/positions.js.map +1 -0
- package/dist/core/ziwei/BrightnessSystem.d.ts +53 -0
- package/dist/core/ziwei/BrightnessSystem.d.ts.map +1 -0
- package/dist/core/ziwei/BrightnessSystem.js +278 -0
- package/dist/core/ziwei/BrightnessSystem.js.map +1 -0
- package/dist/core/ziwei/IztroAdapter.d.ts +78 -0
- package/dist/core/ziwei/IztroAdapter.d.ts.map +1 -0
- package/dist/core/ziwei/IztroAdapter.js +314 -0
- package/dist/core/ziwei/IztroAdapter.js.map +1 -0
- package/dist/core/ziwei/MutagenCore.d.ts +81 -0
- package/dist/core/ziwei/MutagenCore.d.ts.map +1 -0
- package/dist/core/ziwei/MutagenCore.js +246 -0
- package/dist/core/ziwei/MutagenCore.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1101 -0
- package/dist/index.js.map +1 -0
- package/dist/output/fortuneTextRenderer.d.ts +63 -0
- package/dist/output/fortuneTextRenderer.d.ts.map +1 -0
- package/dist/output/fortuneTextRenderer.js +384 -0
- package/dist/output/fortuneTextRenderer.js.map +1 -0
- package/dist/output/listTextRenderer.d.ts +298 -0
- package/dist/output/listTextRenderer.d.ts.map +1 -0
- package/dist/output/listTextRenderer.js +942 -0
- package/dist/output/listTextRenderer.js.map +1 -0
- package/dist/services/bazi/BaziService.d.ts +83 -0
- package/dist/services/bazi/BaziService.d.ts.map +1 -0
- package/dist/services/bazi/BaziService.js +635 -0
- package/dist/services/bazi/BaziService.js.map +1 -0
- package/dist/services/bazi/analyzers/ClimateAnalyzer.d.ts +31 -0
- package/dist/services/bazi/analyzers/ClimateAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/ClimateAnalyzer.js +194 -0
- package/dist/services/bazi/analyzers/ClimateAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts +16 -0
- package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js +60 -0
- package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts +33 -0
- package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/NaYinAnalyzer.js +209 -0
- package/dist/services/bazi/analyzers/NaYinAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/PatternAnalyzer.d.ts +159 -0
- package/dist/services/bazi/analyzers/PatternAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/PatternAnalyzer.js +1150 -0
- package/dist/services/bazi/analyzers/PatternAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/RelationsAnalyzer.d.ts +114 -0
- package/dist/services/bazi/analyzers/RelationsAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/RelationsAnalyzer.js +704 -0
- package/dist/services/bazi/analyzers/RelationsAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts +236 -0
- package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/ShenShaAnalyzer.js +2079 -0
- package/dist/services/bazi/analyzers/ShenShaAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/StrengthAnalyzer.d.ts +181 -0
- package/dist/services/bazi/analyzers/StrengthAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/StrengthAnalyzer.js +1119 -0
- package/dist/services/bazi/analyzers/StrengthAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/TenGodsAnalyzer.d.ts +78 -0
- package/dist/services/bazi/analyzers/TenGodsAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/TenGodsAnalyzer.js +383 -0
- package/dist/services/bazi/analyzers/TenGodsAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts +46 -0
- package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/TraditionalAnalyzer.js +260 -0
- package/dist/services/bazi/analyzers/TraditionalAnalyzer.js.map +1 -0
- package/dist/services/bazi/analyzers/YongShenAnalyzer.d.ts +70 -0
- package/dist/services/bazi/analyzers/YongShenAnalyzer.d.ts.map +1 -0
- package/dist/services/bazi/analyzers/YongShenAnalyzer.js +858 -0
- package/dist/services/bazi/analyzers/YongShenAnalyzer.js.map +1 -0
- package/dist/services/bazi/calculators/DaYunCalculator.d.ts +71 -0
- package/dist/services/bazi/calculators/DaYunCalculator.d.ts.map +1 -0
- package/dist/services/bazi/calculators/DaYunCalculator.js +496 -0
- package/dist/services/bazi/calculators/DaYunCalculator.js.map +1 -0
- package/dist/services/bazi/calculators/LiuNianCalculator.d.ts +88 -0
- package/dist/services/bazi/calculators/LiuNianCalculator.d.ts.map +1 -0
- package/dist/services/bazi/calculators/LiuNianCalculator.js +546 -0
- package/dist/services/bazi/calculators/LiuNianCalculator.js.map +1 -0
- package/dist/services/bazi/calculators/LiuRiCalculator.d.ts +66 -0
- package/dist/services/bazi/calculators/LiuRiCalculator.d.ts.map +1 -0
- package/dist/services/bazi/calculators/LiuRiCalculator.js +497 -0
- package/dist/services/bazi/calculators/LiuRiCalculator.js.map +1 -0
- package/dist/services/bazi/calculators/LiuYueCalculator.d.ts +50 -0
- package/dist/services/bazi/calculators/LiuYueCalculator.d.ts.map +1 -0
- package/dist/services/bazi/calculators/LiuYueCalculator.js +338 -0
- package/dist/services/bazi/calculators/LiuYueCalculator.js.map +1 -0
- package/dist/services/bazi/calculators/LuckCycleCalculator.d.ts +123 -0
- package/dist/services/bazi/calculators/LuckCycleCalculator.d.ts.map +1 -0
- package/dist/services/bazi/calculators/LuckCycleCalculator.js +414 -0
- package/dist/services/bazi/calculators/LuckCycleCalculator.js.map +1 -0
- package/dist/services/bazi/index.d.ts +21 -0
- package/dist/services/bazi/index.d.ts.map +1 -0
- package/dist/services/bazi/index.js +83 -0
- package/dist/services/bazi/index.js.map +1 -0
- package/dist/services/bazi/types.d.ts +597 -0
- package/dist/services/bazi/types.d.ts.map +1 -0
- package/dist/services/bazi/types.js +123 -0
- package/dist/services/bazi/types.js.map +1 -0
- package/dist/services/ziwei/ZiweiService.d.ts +86 -0
- package/dist/services/ziwei/ZiweiService.d.ts.map +1 -0
- package/dist/services/ziwei/ZiweiService.js +343 -0
- package/dist/services/ziwei/ZiweiService.js.map +1 -0
- package/dist/services/ziwei/calculators/BrightnessCalculator.d.ts +38 -0
- package/dist/services/ziwei/calculators/BrightnessCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/BrightnessCalculator.js +142 -0
- package/dist/services/ziwei/calculators/BrightnessCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/DailyCalculator.d.ts +27 -0
- package/dist/services/ziwei/calculators/DailyCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/DailyCalculator.js +55 -0
- package/dist/services/ziwei/calculators/DailyCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/DecadeCalculator.d.ts +46 -0
- package/dist/services/ziwei/calculators/DecadeCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/DecadeCalculator.js +181 -0
- package/dist/services/ziwei/calculators/DecadeCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.d.ts +28 -0
- package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.js +84 -0
- package/dist/services/ziwei/calculators/HoroscopeStarsCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/HourlyCalculator.d.ts +41 -0
- package/dist/services/ziwei/calculators/HourlyCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/HourlyCalculator.js +139 -0
- package/dist/services/ziwei/calculators/HourlyCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/MinorLimitCalculator.d.ts +30 -0
- package/dist/services/ziwei/calculators/MinorLimitCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/MinorLimitCalculator.js +90 -0
- package/dist/services/ziwei/calculators/MinorLimitCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/MonthlyCalculator.d.ts +39 -0
- package/dist/services/ziwei/calculators/MonthlyCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/MonthlyCalculator.js +128 -0
- package/dist/services/ziwei/calculators/MonthlyCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/MutagenCalculator.d.ts +20 -0
- package/dist/services/ziwei/calculators/MutagenCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/MutagenCalculator.js +121 -0
- package/dist/services/ziwei/calculators/MutagenCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/PalaceDynamicCalculator.d.ts +35 -0
- package/dist/services/ziwei/calculators/PalaceDynamicCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/PalaceDynamicCalculator.js +55 -0
- package/dist/services/ziwei/calculators/PalaceDynamicCalculator.js.map +1 -0
- package/dist/services/ziwei/calculators/YearlyCalculator.d.ts +35 -0
- package/dist/services/ziwei/calculators/YearlyCalculator.d.ts.map +1 -0
- package/dist/services/ziwei/calculators/YearlyCalculator.js +119 -0
- package/dist/services/ziwei/calculators/YearlyCalculator.js.map +1 -0
- package/dist/services/ziwei/index.d.ts +15 -0
- package/dist/services/ziwei/index.d.ts.map +1 -0
- package/dist/services/ziwei/index.js +48 -0
- package/dist/services/ziwei/index.js.map +1 -0
- package/dist/services/ziwei/transformers/PalaceTransformer.d.ts +62 -0
- package/dist/services/ziwei/transformers/PalaceTransformer.d.ts.map +1 -0
- package/dist/services/ziwei/transformers/PalaceTransformer.js +153 -0
- package/dist/services/ziwei/transformers/PalaceTransformer.js.map +1 -0
- package/dist/services/ziwei/types.d.ts +185 -0
- package/dist/services/ziwei/types.d.ts.map +1 -0
- package/dist/services/ziwei/types.js +54 -0
- package/dist/services/ziwei/types.js.map +1 -0
- package/dist/shared/logger.d.ts +51 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +136 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/types.d.ts +91 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +7 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/utils/ageCalculator.d.ts +30 -0
- package/dist/utils/ageCalculator.d.ts.map +1 -0
- package/dist/utils/ageCalculator.js +51 -0
- package/dist/utils/ageCalculator.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,1119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Day Master Strength Analyzer
|
|
4
|
+
* Quantitative analysis of day master strength using 八字日主旺衰分析的确定性量化算法
|
|
5
|
+
* Based on 八字旺衰量化算法研究.md specification
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.StrengthAnalyzer = void 0;
|
|
9
|
+
const bazi_1 = require("../../../core/constants/bazi");
|
|
10
|
+
const lunar_javascript_1 = require("lunar-javascript");
|
|
11
|
+
// Total energy pool for the BaZi chart
|
|
12
|
+
const TOTAL_ENERGY = 360;
|
|
13
|
+
const MONTH_BRANCH_ENERGY = 180; // 50% to month branch
|
|
14
|
+
const OTHER_POSITIONS_ENERGY = 180; // 50% to other 7 positions
|
|
15
|
+
// Position weights for non-month positions
|
|
16
|
+
const POSITION_WEIGHTS = {
|
|
17
|
+
dayBranch: 40, // 日支
|
|
18
|
+
monthStem: 35, // 月干
|
|
19
|
+
hourStem: 30, // 时干
|
|
20
|
+
hourBranch: 25, // 时支
|
|
21
|
+
yearStem: 25, // 年干
|
|
22
|
+
yearBranch: 25 // 年支
|
|
23
|
+
};
|
|
24
|
+
const STRENGTH_CATEGORIES = [
|
|
25
|
+
{ min: -360, max: -150, strength: '衰极', description: '衰极' },
|
|
26
|
+
{ min: -149, max: -80, strength: '身弱', description: '身弱' },
|
|
27
|
+
{ min: -79, max: -30, strength: '偏弱', description: '偏弱' },
|
|
28
|
+
{ min: -29, max: 29, strength: '中和', description: '中和' },
|
|
29
|
+
{ min: 30, max: 79, strength: '偏强', description: '偏强' },
|
|
30
|
+
{ min: 80, max: 149, strength: '身旺', description: '身旺' },
|
|
31
|
+
{ min: 150, max: 360, strength: '旺极', description: '旺极' }
|
|
32
|
+
];
|
|
33
|
+
// Month branch commanding elements table
|
|
34
|
+
const MONTH_COMMANDING_ELEMENTS = {
|
|
35
|
+
'寅': [{ element: '戊', days: 7 }, { element: '丙', days: 7 }, { element: '甲', days: 16 }],
|
|
36
|
+
'卯': [{ element: '甲', days: 10 }, { element: '乙', days: 20 }],
|
|
37
|
+
'辰': [{ element: '乙', days: 9 }, { element: '癸', days: 3 }, { element: '戊', days: 18 }],
|
|
38
|
+
'巳': [{ element: '戊', days: 5 }, { element: '庚', days: 9 }, { element: '丙', days: 16 }],
|
|
39
|
+
'午': [{ element: '丙', days: 10 }, { element: '己', days: 9 }, { element: '丁', days: 11 }],
|
|
40
|
+
'未': [{ element: '丁', days: 9 }, { element: '乙', days: 3 }, { element: '己', days: 18 }],
|
|
41
|
+
'申': [{ element: '己', days: 7 }, { element: '壬', days: 7 }, { element: '庚', days: 16 }],
|
|
42
|
+
'酉': [{ element: '庚', days: 10 }, { element: '辛', days: 20 }],
|
|
43
|
+
'戌': [{ element: '辛', days: 9 }, { element: '丁', days: 3 }, { element: '戊', days: 18 }],
|
|
44
|
+
'亥': [{ element: '戊', days: 7 }, { element: '甲', days: 7 }, { element: '壬', days: 16 }],
|
|
45
|
+
'子': [{ element: '壬', days: 10 }, { element: '癸', days: 20 }],
|
|
46
|
+
'丑': [{ element: '癸', days: 9 }, { element: '辛', days: 3 }, { element: '己', days: 18 }]
|
|
47
|
+
};
|
|
48
|
+
// Distance decay coefficients
|
|
49
|
+
const DISTANCE_DECAY = {
|
|
50
|
+
adjacent: 1.0, // 相邻 (year-month, month-day, day-hour)
|
|
51
|
+
oneApart: 0.7, // 隔位 (year-day, month-hour)
|
|
52
|
+
twoApart: 0.5 // 遥隔 (year-hour)
|
|
53
|
+
};
|
|
54
|
+
class StrengthAnalyzer {
|
|
55
|
+
/**
|
|
56
|
+
* Analyze day master strength for components (synchronous)
|
|
57
|
+
* 使用360分量化算法计算日主旺衰
|
|
58
|
+
*/
|
|
59
|
+
static analyzeDayMasterStrength(chart, birthInfo) {
|
|
60
|
+
const dayMaster = chart.day.stem;
|
|
61
|
+
const dayMasterElement = this.getStemElement(dayMaster);
|
|
62
|
+
// 详细的计算步骤记录
|
|
63
|
+
const detailedBreakdown = [];
|
|
64
|
+
// Step 1: 静态评分系统 (Static Scoring)
|
|
65
|
+
const staticScores = this.calculateStaticScores(chart, birthInfo, detailedBreakdown);
|
|
66
|
+
// Step 2: 动态计算引擎 (Dynamic Calculations)
|
|
67
|
+
const dynamicResult = this.applyDynamicCalculations(chart, staticScores, detailedBreakdown);
|
|
68
|
+
// Step 3: 计算最终旺衰分数 (Final Strength Score)
|
|
69
|
+
const finalScores = dynamicResult.scores;
|
|
70
|
+
const { supportingForce, opposingForce } = this.calculateForces(dayMasterElement, finalScores);
|
|
71
|
+
const finalStrengthScore = supportingForce - opposingForce;
|
|
72
|
+
// 确定强弱类别
|
|
73
|
+
const category = this.categorizeStrength(finalStrengthScore);
|
|
74
|
+
// 计算百分比(基于支持力量占总力量的比例)
|
|
75
|
+
const totalForce = supportingForce + opposingForce;
|
|
76
|
+
const percentage = totalForce > 0 ? Math.round((supportingForce / totalForce) * 100) : 50;
|
|
77
|
+
// 获取月令司令元素
|
|
78
|
+
const monthCommandingElement = this.getMonthCommandingElement(chart.month.branch, birthInfo);
|
|
79
|
+
// Calculate dynamic adjustments (difference between final and static)
|
|
80
|
+
const dynamicAdjustments = {
|
|
81
|
+
wood: finalScores.wood - staticScores.wood,
|
|
82
|
+
fire: finalScores.fire - staticScores.fire,
|
|
83
|
+
earth: finalScores.earth - staticScores.earth,
|
|
84
|
+
metal: finalScores.metal - staticScores.metal,
|
|
85
|
+
water: finalScores.water - staticScores.water
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
strength: category.strength,
|
|
89
|
+
score: finalStrengthScore,
|
|
90
|
+
percentage,
|
|
91
|
+
factors: {
|
|
92
|
+
staticScores,
|
|
93
|
+
dynamicScores: dynamicAdjustments,
|
|
94
|
+
supportingForce,
|
|
95
|
+
opposingForce,
|
|
96
|
+
monthCommandingElement,
|
|
97
|
+
detailedBreakdown
|
|
98
|
+
},
|
|
99
|
+
analysis: this.generateAnalysis(category, finalStrengthScore, dayMasterElement),
|
|
100
|
+
suggestions: this.generateSuggestions(category.strength, dayMasterElement)
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Analyze day master strength quantitatively
|
|
105
|
+
* Async wrapper for service layer compatibility
|
|
106
|
+
*/
|
|
107
|
+
static async analyze(chart, birthInfo) {
|
|
108
|
+
const analysis = this.analyzeDayMasterStrength(chart, birthInfo);
|
|
109
|
+
// Generate characteristics based on strength category
|
|
110
|
+
const characteristics = this.generateCharacteristics(analysis.strength, analysis.score, analysis.factors);
|
|
111
|
+
// Convert detailed breakdown to the format expected by the type
|
|
112
|
+
const details = analysis.factors.detailedBreakdown.map(item => ({
|
|
113
|
+
category: this.categorizeBreakdownItem(item.item),
|
|
114
|
+
item: item.item,
|
|
115
|
+
score: item.baseScore,
|
|
116
|
+
adjustment: item.finalScore - item.baseScore,
|
|
117
|
+
adjustmentString: item.adjustment,
|
|
118
|
+
finalScore: item.finalScore
|
|
119
|
+
}));
|
|
120
|
+
return {
|
|
121
|
+
dayMasterStrength: analysis.strength,
|
|
122
|
+
totalScore: analysis.score,
|
|
123
|
+
breakdown: {
|
|
124
|
+
base: 0, // Not applicable in new algorithm
|
|
125
|
+
monthSupport: analysis.factors.monthCommandingElement ?
|
|
126
|
+
(analysis.factors.staticScores[this.getElementKey(analysis.factors.monthCommandingElement)] || 0) : 0,
|
|
127
|
+
stemSupport: analysis.factors.supportingForce,
|
|
128
|
+
branchSupport: 0, // Included in total scores
|
|
129
|
+
seasonalAdjustment: 0,
|
|
130
|
+
branchInteractionAdjustment: 0
|
|
131
|
+
},
|
|
132
|
+
percentage: analysis.percentage,
|
|
133
|
+
analysis: analysis.analysis,
|
|
134
|
+
details,
|
|
135
|
+
characteristics,
|
|
136
|
+
recommendations: analysis.suggestions
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Calculate static scores for all elements
|
|
141
|
+
* 静态评分系统:建立基础能量值
|
|
142
|
+
*/
|
|
143
|
+
static calculateStaticScores(chart, birthInfo, breakdown) {
|
|
144
|
+
const scores = {
|
|
145
|
+
wood: 0,
|
|
146
|
+
fire: 0,
|
|
147
|
+
earth: 0,
|
|
148
|
+
metal: 0,
|
|
149
|
+
water: 0
|
|
150
|
+
};
|
|
151
|
+
// 1. 月令司令元素得90分 (根据算法文档更新)
|
|
152
|
+
const monthBranch = chart.month.branch;
|
|
153
|
+
const commandingElement = this.getMonthCommandingElement(monthBranch, birthInfo);
|
|
154
|
+
const commandingElementKey = this.getElementKey(commandingElement);
|
|
155
|
+
const COMMANDING_ELEMENT_SCORE = 90; // 司令元素得90分
|
|
156
|
+
// 确保commandingElement有效
|
|
157
|
+
if (commandingElement && commandingElementKey) {
|
|
158
|
+
scores[commandingElementKey] += COMMANDING_ELEMENT_SCORE;
|
|
159
|
+
}
|
|
160
|
+
breakdown.push({
|
|
161
|
+
item: `月支${monthBranch}司令${commandingElement}`,
|
|
162
|
+
element: commandingElement,
|
|
163
|
+
baseScore: COMMANDING_ELEMENT_SCORE,
|
|
164
|
+
adjustment: '',
|
|
165
|
+
finalScore: COMMANDING_ELEMENT_SCORE
|
|
166
|
+
});
|
|
167
|
+
// 2. 剩余90分按月支藏干分配
|
|
168
|
+
const REMAINING_MONTH_SCORE = 90;
|
|
169
|
+
this.distributeHiddenStemScores(monthBranch, REMAINING_MONTH_SCORE, '月支', scores, breakdown);
|
|
170
|
+
// 3. 其他6个位置共享180分(月支已单独处理)
|
|
171
|
+
// Year stem
|
|
172
|
+
const yearStemElement = this.getStemElement(chart.year.stem);
|
|
173
|
+
const yearStemKey = this.getElementKey(yearStemElement);
|
|
174
|
+
scores[yearStemKey] += POSITION_WEIGHTS.yearStem;
|
|
175
|
+
breakdown.push({
|
|
176
|
+
item: `年干${chart.year.stem}`,
|
|
177
|
+
element: yearStemElement,
|
|
178
|
+
baseScore: POSITION_WEIGHTS.yearStem,
|
|
179
|
+
adjustment: '',
|
|
180
|
+
finalScore: POSITION_WEIGHTS.yearStem
|
|
181
|
+
});
|
|
182
|
+
// Year branch hidden stems
|
|
183
|
+
this.distributeHiddenStemScores(chart.year.branch, POSITION_WEIGHTS.yearBranch, '年支', scores, breakdown);
|
|
184
|
+
// Month stem - Skip if it's the same as month commanding element
|
|
185
|
+
const monthStemElement = this.getStemElement(chart.month.stem);
|
|
186
|
+
// Include month stem in calculations
|
|
187
|
+
// While the document examples might have omitted it, the month stem should
|
|
188
|
+
// receive its allocated 35 points as part of the comprehensive calculation
|
|
189
|
+
const includeMonthStem = true; // Include month stem for complete analysis
|
|
190
|
+
if (includeMonthStem) {
|
|
191
|
+
const monthStemKey = this.getElementKey(monthStemElement);
|
|
192
|
+
scores[monthStemKey] += POSITION_WEIGHTS.monthStem;
|
|
193
|
+
breakdown.push({
|
|
194
|
+
item: `月干${chart.month.stem}`,
|
|
195
|
+
element: monthStemElement,
|
|
196
|
+
baseScore: POSITION_WEIGHTS.monthStem,
|
|
197
|
+
adjustment: '',
|
|
198
|
+
finalScore: POSITION_WEIGHTS.monthStem
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Day branch hidden stems
|
|
202
|
+
this.distributeHiddenStemScores(chart.day.branch, POSITION_WEIGHTS.dayBranch, '日支', scores, breakdown);
|
|
203
|
+
// Hour stem
|
|
204
|
+
const hourStemElement = this.getStemElement(chart.hour.stem);
|
|
205
|
+
const hourStemKey = this.getElementKey(hourStemElement);
|
|
206
|
+
scores[hourStemKey] += POSITION_WEIGHTS.hourStem;
|
|
207
|
+
breakdown.push({
|
|
208
|
+
item: `时干${chart.hour.stem}`,
|
|
209
|
+
element: hourStemElement,
|
|
210
|
+
baseScore: POSITION_WEIGHTS.hourStem,
|
|
211
|
+
adjustment: '',
|
|
212
|
+
finalScore: POSITION_WEIGHTS.hourStem
|
|
213
|
+
});
|
|
214
|
+
// Hour branch hidden stems
|
|
215
|
+
this.distributeHiddenStemScores(chart.hour.branch, POSITION_WEIGHTS.hourBranch, '时支', scores, breakdown);
|
|
216
|
+
return scores;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Distribute scores among hidden stems in a branch
|
|
220
|
+
*/
|
|
221
|
+
static distributeHiddenStemScores(branch, totalScore, position, scores, breakdown) {
|
|
222
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[branch];
|
|
223
|
+
if (!hiddenStems)
|
|
224
|
+
return;
|
|
225
|
+
hiddenStems.forEach(({ stem, power }) => {
|
|
226
|
+
const element = this.getStemElement(stem);
|
|
227
|
+
const elementKey = this.getElementKey(element);
|
|
228
|
+
const score = Math.round((totalScore || 0) * (power || 0));
|
|
229
|
+
if (!isNaN(score) && isFinite(score)) {
|
|
230
|
+
scores[elementKey] += score;
|
|
231
|
+
}
|
|
232
|
+
breakdown.push({
|
|
233
|
+
item: `${position}${branch}藏${stem}`,
|
|
234
|
+
element,
|
|
235
|
+
baseScore: !isNaN(score) && isFinite(score) ? score : 0,
|
|
236
|
+
adjustment: '',
|
|
237
|
+
finalScore: !isNaN(score) && isFinite(score) ? score : 0
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Apply dynamic calculations including combinations, clashes, etc.
|
|
243
|
+
* 动态计算引擎:基于规则的分值修正系统
|
|
244
|
+
*/
|
|
245
|
+
static applyDynamicCalculations(chart, staticScores, breakdown) {
|
|
246
|
+
// Clone scores for modification
|
|
247
|
+
const scores = { ...staticScores };
|
|
248
|
+
const adjustments = [];
|
|
249
|
+
// Priority order: 三会 > 三合 > 六合 > 冲 > 刑 > 害 > 生克
|
|
250
|
+
// 1. Check Three Meetings (三会局)
|
|
251
|
+
this.checkThreeMeetings(chart, scores, adjustments, breakdown);
|
|
252
|
+
// 2. Check Three Harmonies (三合局)
|
|
253
|
+
this.checkThreeHarmonies(chart, scores, adjustments, breakdown);
|
|
254
|
+
// 3. Check Six Combinations (六合)
|
|
255
|
+
this.checkSixCombinations(chart, scores, adjustments, breakdown);
|
|
256
|
+
// 4. Check Clashes (冲)
|
|
257
|
+
this.checkClashes(chart, scores, adjustments, breakdown);
|
|
258
|
+
// 5. Check Punishments (刑)
|
|
259
|
+
this.checkPunishments(chart, scores, adjustments, breakdown);
|
|
260
|
+
// 6. Check Harms (害)
|
|
261
|
+
this.checkHarms(chart, scores, adjustments, breakdown);
|
|
262
|
+
// 7. Apply Generating and Overcoming (生克)
|
|
263
|
+
// NOTE: Temporarily disabled - this method is incorrectly reducing all scores
|
|
264
|
+
// this.applyGeneratingOvercoming(chart, scores, adjustments, breakdown);
|
|
265
|
+
return { scores, adjustments };
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Calculate supporting and opposing forces
|
|
269
|
+
* 阵营划分:我党vs异党
|
|
270
|
+
*/
|
|
271
|
+
static calculateForces(dayMasterElement, scores) {
|
|
272
|
+
const dayMasterKey = this.getElementKey(dayMasterElement);
|
|
273
|
+
const generatingKey = this.getElementKey(this.getGeneratingElement(dayMasterElement));
|
|
274
|
+
// 我党: 比劫(same) + 印枭(generating)
|
|
275
|
+
const supportingForce = (scores[dayMasterKey] || 0) + (scores[generatingKey] || 0);
|
|
276
|
+
// 异党: 官杀(controlling) + 食伤(generated) + 财才(controlled)
|
|
277
|
+
const controllingKey = this.getElementKey(this.getControllingElement(dayMasterElement));
|
|
278
|
+
const generatedKey = this.getElementKey(this.getGeneratedElement(dayMasterElement));
|
|
279
|
+
const controlledKey = this.getElementKey(this.getControlledElement(dayMasterElement));
|
|
280
|
+
const opposingForce = (scores[controllingKey] || 0) + (scores[generatedKey] || 0) + (scores[controlledKey] || 0);
|
|
281
|
+
// 确保返回值不是NaN
|
|
282
|
+
return {
|
|
283
|
+
supportingForce: isNaN(supportingForce) ? 0 : supportingForce,
|
|
284
|
+
opposingForce: isNaN(opposingForce) ? 0 : opposingForce
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get the commanding element for a month branch
|
|
289
|
+
*/
|
|
290
|
+
static getMonthCommandingElement(monthBranch, birthInfo) {
|
|
291
|
+
// If we have birth info, calculate the exact commanding element based on days
|
|
292
|
+
if (birthInfo) {
|
|
293
|
+
try {
|
|
294
|
+
let solar;
|
|
295
|
+
// 兼容两种格式的birthInfo
|
|
296
|
+
if (birthInfo.solar instanceof Date) {
|
|
297
|
+
// Core格式:包含solar Date对象
|
|
298
|
+
const date = birthInfo.solar;
|
|
299
|
+
solar = lunar_javascript_1.Solar.fromYmdHms(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
|
|
300
|
+
}
|
|
301
|
+
else if (birthInfo.year && birthInfo.month && birthInfo.day) {
|
|
302
|
+
// Service格式:包含具体日期字段
|
|
303
|
+
solar = lunar_javascript_1.Solar.fromYmdHms(birthInfo.year, birthInfo.month, birthInfo.day, birthInfo.hour || 0, birthInfo.minute || 0, 0);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
// 格式不可识别,使用当前月支
|
|
307
|
+
return monthBranch + '司令';
|
|
308
|
+
}
|
|
309
|
+
const lunar = solar.getLunar();
|
|
310
|
+
// Get the previous Jie (major solar term) that marks the start of this month
|
|
311
|
+
const prevJie = lunar.getPrevJie();
|
|
312
|
+
if (prevJie) {
|
|
313
|
+
// Calculate days from the start of the solar term
|
|
314
|
+
const termDate = prevJie.getSolar();
|
|
315
|
+
const currentDate = new Date(solar.getYear(), solar.getMonth() - 1, solar.getDay());
|
|
316
|
+
const termDateObj = new Date(termDate.getYear(), termDate.getMonth() - 1, termDate.getDay());
|
|
317
|
+
const daysSinceTermStart = Math.floor((currentDate.getTime() - termDateObj.getTime()) / (1000 * 60 * 60 * 24));
|
|
318
|
+
// Get commanding elements for this month
|
|
319
|
+
const commanders = MONTH_COMMANDING_ELEMENTS[monthBranch];
|
|
320
|
+
if (commanders && commanders.length > 0) {
|
|
321
|
+
// Find which element is commanding based on accumulated days
|
|
322
|
+
let accumulatedDays = 0;
|
|
323
|
+
for (const commander of commanders) {
|
|
324
|
+
accumulatedDays += commander.days;
|
|
325
|
+
if (daysSinceTermStart < accumulatedDays) {
|
|
326
|
+
return commander.element;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// If we've gone past all defined days, return the last element
|
|
330
|
+
return commanders[commanders.length - 1].element;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
// Fallback to default method if calculation fails
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Default: use the last element which usually has the most days
|
|
339
|
+
const commanders = MONTH_COMMANDING_ELEMENTS[monthBranch];
|
|
340
|
+
if (commanders && commanders.length > 0) {
|
|
341
|
+
return commanders[commanders.length - 1].element;
|
|
342
|
+
}
|
|
343
|
+
// Final fallback: use main qi of branch
|
|
344
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[monthBranch];
|
|
345
|
+
if (hiddenStems && hiddenStems.length > 0) {
|
|
346
|
+
return hiddenStems[0].stem;
|
|
347
|
+
}
|
|
348
|
+
return '戊'; // Default to earth if not found
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Check for Three Meetings (三会局)
|
|
352
|
+
*/
|
|
353
|
+
static checkThreeMeetings(chart, scores, adjustments, breakdown) {
|
|
354
|
+
const branches = [
|
|
355
|
+
chart.year.branch,
|
|
356
|
+
chart.month.branch,
|
|
357
|
+
chart.day.branch,
|
|
358
|
+
chart.hour.branch
|
|
359
|
+
];
|
|
360
|
+
const meetings = [
|
|
361
|
+
{ branches: ['亥', '子', '丑'], element: '水', name: '北方水局' },
|
|
362
|
+
{ branches: ['寅', '卯', '辰'], element: '木', name: '东方木局' },
|
|
363
|
+
{ branches: ['巳', '午', '未'], element: '火', name: '南方火局' },
|
|
364
|
+
{ branches: ['申', '酉', '戌'], element: '金', name: '西方金局' }
|
|
365
|
+
];
|
|
366
|
+
for (const meeting of meetings) {
|
|
367
|
+
const foundBranches = meeting.branches.filter(b => branches.includes(b));
|
|
368
|
+
if (foundBranches.length === 3) {
|
|
369
|
+
// Three meeting found - transform all participating branches' energy
|
|
370
|
+
const totalEnergy = this.calculateBranchEnergy(foundBranches, chart, scores);
|
|
371
|
+
// Clear original element scores for participating branches
|
|
372
|
+
this.clearBranchScores(foundBranches, chart, scores);
|
|
373
|
+
// Add total energy to the meeting element
|
|
374
|
+
scores[meeting.element] += totalEnergy;
|
|
375
|
+
adjustments.push({
|
|
376
|
+
type: '三会局',
|
|
377
|
+
description: `${meeting.name}成功,${foundBranches.join('、')}化为${this.getElementName(meeting.element)}`,
|
|
378
|
+
scoreChange: totalEnergy
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Check for Three Harmonies (三合局)
|
|
385
|
+
*/
|
|
386
|
+
static checkThreeHarmonies(chart, scores, adjustments, breakdown) {
|
|
387
|
+
const branches = [
|
|
388
|
+
chart.year.branch,
|
|
389
|
+
chart.month.branch,
|
|
390
|
+
chart.day.branch,
|
|
391
|
+
chart.hour.branch
|
|
392
|
+
];
|
|
393
|
+
const harmonies = [
|
|
394
|
+
{ branches: ['申', '子', '辰'], element: '水', name: '水局' },
|
|
395
|
+
{ branches: ['亥', '卯', '未'], element: '木', name: '木局' },
|
|
396
|
+
{ branches: ['寅', '午', '戌'], element: '火', name: '火局' },
|
|
397
|
+
{ branches: ['巳', '酉', '丑'], element: '金', name: '金局' }
|
|
398
|
+
];
|
|
399
|
+
for (const harmony of harmonies) {
|
|
400
|
+
const foundBranches = harmony.branches.filter(b => branches.includes(b));
|
|
401
|
+
if (foundBranches.length === 3) {
|
|
402
|
+
// Check if harmony can transform (needs seasonal support and stem revelation)
|
|
403
|
+
const canTransform = this.checkHarmonyTransformation(harmony.element, chart);
|
|
404
|
+
if (canTransform) {
|
|
405
|
+
// Transform all energy to the harmony element
|
|
406
|
+
const totalEnergy = this.calculateBranchEnergy(foundBranches, chart, scores);
|
|
407
|
+
this.clearBranchScores(foundBranches, chart, scores);
|
|
408
|
+
scores[harmony.element] += totalEnergy;
|
|
409
|
+
adjustments.push({
|
|
410
|
+
type: '三合化局',
|
|
411
|
+
description: `${harmony.name}化成功,${foundBranches.join('、')}化为${this.getElementName(harmony.element)}`,
|
|
412
|
+
scoreChange: totalEnergy
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
// Just increase affinity, no transformation
|
|
417
|
+
foundBranches.forEach(branch => {
|
|
418
|
+
const branchScores = this.getBranchElementScores(branch, chart, scores);
|
|
419
|
+
Object.entries(branchScores).forEach(([element, score]) => {
|
|
420
|
+
const increase = Math.round(score * 0.3);
|
|
421
|
+
scores[element] += increase;
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
adjustments.push({
|
|
425
|
+
type: '三合不化',
|
|
426
|
+
description: `${harmony.name}合而不化,各增力30%`,
|
|
427
|
+
scoreChange: 0
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Check for Six Combinations (六合)
|
|
435
|
+
*/
|
|
436
|
+
static checkSixCombinations(chart, scores, adjustments, breakdown) {
|
|
437
|
+
const combinations = [
|
|
438
|
+
{ pair: ['子', '丑'], result: '土' },
|
|
439
|
+
{ pair: ['寅', '亥'], result: '木' },
|
|
440
|
+
{ pair: ['卯', '戌'], result: '火' },
|
|
441
|
+
{ pair: ['辰', '酉'], result: '金' },
|
|
442
|
+
{ pair: ['巳', '申'], result: '水' },
|
|
443
|
+
{ pair: ['午', '未'], result: '土' }
|
|
444
|
+
];
|
|
445
|
+
const positions = [
|
|
446
|
+
{ branch: chart.year.branch, name: '年支' },
|
|
447
|
+
{ branch: chart.month.branch, name: '月支' },
|
|
448
|
+
{ branch: chart.day.branch, name: '日支' },
|
|
449
|
+
{ branch: chart.hour.branch, name: '时支' }
|
|
450
|
+
];
|
|
451
|
+
// Check adjacent positions only
|
|
452
|
+
for (let i = 0; i < positions.length - 1; i++) {
|
|
453
|
+
const branch1 = positions[i].branch;
|
|
454
|
+
const branch2 = positions[i + 1].branch;
|
|
455
|
+
for (const combo of combinations) {
|
|
456
|
+
if ((combo.pair[0] === branch1 && combo.pair[1] === branch2) ||
|
|
457
|
+
(combo.pair[1] === branch1 && combo.pair[0] === branch2)) {
|
|
458
|
+
// Found a six combination
|
|
459
|
+
const canTransform = this.checkCombinationTransformation(combo.result, chart);
|
|
460
|
+
if (canTransform) {
|
|
461
|
+
// Transform both branches to the result element
|
|
462
|
+
const energy1 = this.getBranchTotalScore(branch1, chart, scores);
|
|
463
|
+
const energy2 = this.getBranchTotalScore(branch2, chart, scores);
|
|
464
|
+
this.clearBranchScores([branch1, branch2], chart, scores);
|
|
465
|
+
scores[combo.result] += energy1 + energy2;
|
|
466
|
+
adjustments.push({
|
|
467
|
+
type: '六合化',
|
|
468
|
+
description: `${branch1}${branch2}合化${this.getElementName(combo.result)}`,
|
|
469
|
+
scoreChange: energy1 + energy2
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
// Just increase affinity
|
|
474
|
+
adjustments.push({
|
|
475
|
+
type: '六合不化',
|
|
476
|
+
description: `${branch1}${branch2}合而不化,各增力20%`,
|
|
477
|
+
scoreChange: 0
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Check for Clashes (冲)
|
|
486
|
+
*/
|
|
487
|
+
static checkClashes(chart, scores, adjustments, breakdown) {
|
|
488
|
+
const clashes = [
|
|
489
|
+
['子', '午'], ['丑', '未'], ['寅', '申'],
|
|
490
|
+
['卯', '酉'], ['辰', '戌'], ['巳', '亥']
|
|
491
|
+
];
|
|
492
|
+
const positions = [
|
|
493
|
+
{ branch: chart.year.branch, name: '年支', index: 0 },
|
|
494
|
+
{ branch: chart.month.branch, name: '月支', index: 1 },
|
|
495
|
+
{ branch: chart.day.branch, name: '日支', index: 2 },
|
|
496
|
+
{ branch: chart.hour.branch, name: '时支', index: 3 }
|
|
497
|
+
];
|
|
498
|
+
for (let i = 0; i < positions.length; i++) {
|
|
499
|
+
for (let j = i + 1; j < positions.length; j++) {
|
|
500
|
+
const pos1 = positions[i];
|
|
501
|
+
const pos2 = positions[j];
|
|
502
|
+
for (const clash of clashes) {
|
|
503
|
+
if ((clash[0] === pos1.branch && clash[1] === pos2.branch) ||
|
|
504
|
+
(clash[1] === pos1.branch && clash[0] === pos2.branch)) {
|
|
505
|
+
// Apply clash with distance decay
|
|
506
|
+
const distance = Math.abs(pos1.index - pos2.index);
|
|
507
|
+
const decay = distance === 1 ? DISTANCE_DECAY.adjacent :
|
|
508
|
+
distance === 2 ? DISTANCE_DECAY.oneApart :
|
|
509
|
+
DISTANCE_DECAY.twoApart;
|
|
510
|
+
// Reduce scores by 50% * decay
|
|
511
|
+
const reduction = 0.5 * decay;
|
|
512
|
+
this.reduceBranchScores(pos1.branch, scores, reduction, chart);
|
|
513
|
+
this.reduceBranchScores(pos2.branch, scores, reduction, chart);
|
|
514
|
+
adjustments.push({
|
|
515
|
+
type: '地支相冲',
|
|
516
|
+
description: `${pos1.name}${pos1.branch}与${pos2.name}${pos2.branch}相冲`,
|
|
517
|
+
scoreChange: 0
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Check for Punishments (刑)
|
|
526
|
+
*/
|
|
527
|
+
static checkPunishments(chart, scores, adjustments, breakdown) {
|
|
528
|
+
const positions = [
|
|
529
|
+
{ branch: chart.year.branch, name: '年支', index: 0 },
|
|
530
|
+
{ branch: chart.month.branch, name: '月支', index: 1 },
|
|
531
|
+
{ branch: chart.day.branch, name: '日支', index: 2 },
|
|
532
|
+
{ branch: chart.hour.branch, name: '时支', index: 3 }
|
|
533
|
+
];
|
|
534
|
+
// Self punishments (自刑)
|
|
535
|
+
const selfPunishments = ['辰', '午', '酉', '亥'];
|
|
536
|
+
const branchCounts = {};
|
|
537
|
+
positions.forEach(pos => {
|
|
538
|
+
branchCounts[pos.branch] = (branchCounts[pos.branch] || 0) + 1;
|
|
539
|
+
});
|
|
540
|
+
// Check for self punishments (two of same branch)
|
|
541
|
+
Object.entries(branchCounts).forEach(([branch, count]) => {
|
|
542
|
+
if (count >= 2 && selfPunishments.includes(branch)) {
|
|
543
|
+
// Self punishment - reduce by 30%
|
|
544
|
+
this.reduceBranchScores(branch, scores, 0.3, chart);
|
|
545
|
+
adjustments.push({
|
|
546
|
+
type: '自刑',
|
|
547
|
+
description: `${branch}${branch}自刑`,
|
|
548
|
+
scoreChange: 0
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
// Other punishments
|
|
553
|
+
const punishments = [
|
|
554
|
+
// 无恩之刑
|
|
555
|
+
['子', '卯'],
|
|
556
|
+
// 恃势之刑 (任意两个都算)
|
|
557
|
+
['寅', '巳'], ['巳', '申'], ['寅', '申'],
|
|
558
|
+
// 无礼之刑 (任意两个都算)
|
|
559
|
+
['丑', '戌'], ['戌', '未'], ['丑', '未']
|
|
560
|
+
];
|
|
561
|
+
// Check all positions for punishments
|
|
562
|
+
for (let i = 0; i < positions.length; i++) {
|
|
563
|
+
for (let j = i + 1; j < positions.length; j++) {
|
|
564
|
+
const pos1 = positions[i];
|
|
565
|
+
const pos2 = positions[j];
|
|
566
|
+
for (const punishment of punishments) {
|
|
567
|
+
if ((punishment[0] === pos1.branch && punishment[1] === pos2.branch) ||
|
|
568
|
+
(punishment[1] === pos1.branch && punishment[0] === pos2.branch)) {
|
|
569
|
+
// Apply punishment with distance decay
|
|
570
|
+
const distance = Math.abs(pos1.index - pos2.index);
|
|
571
|
+
const decay = distance === 1 ? DISTANCE_DECAY.adjacent :
|
|
572
|
+
distance === 2 ? DISTANCE_DECAY.oneApart :
|
|
573
|
+
DISTANCE_DECAY.twoApart;
|
|
574
|
+
// Determine punishment type and reduction
|
|
575
|
+
let reduction = 0.3; // Default 30%
|
|
576
|
+
let punishmentType = '相刑';
|
|
577
|
+
if ((pos1.branch === '子' && pos2.branch === '卯') ||
|
|
578
|
+
(pos1.branch === '卯' && pos2.branch === '子')) {
|
|
579
|
+
punishmentType = '无恩之刑';
|
|
580
|
+
reduction = 0.35;
|
|
581
|
+
}
|
|
582
|
+
else if (['寅', '巳', '申'].includes(pos1.branch) &&
|
|
583
|
+
['寅', '巳', '申'].includes(pos2.branch)) {
|
|
584
|
+
punishmentType = '恃势之刑';
|
|
585
|
+
reduction = 0.4;
|
|
586
|
+
}
|
|
587
|
+
else if (['丑', '戌', '未'].includes(pos1.branch) &&
|
|
588
|
+
['丑', '戌', '未'].includes(pos2.branch)) {
|
|
589
|
+
punishmentType = '无礼之刑';
|
|
590
|
+
reduction = 0.4;
|
|
591
|
+
}
|
|
592
|
+
// Apply reduction with decay
|
|
593
|
+
const finalReduction = reduction * decay;
|
|
594
|
+
this.reduceBranchScores(pos1.branch, scores, finalReduction, chart);
|
|
595
|
+
this.reduceBranchScores(pos2.branch, scores, finalReduction, chart);
|
|
596
|
+
adjustments.push({
|
|
597
|
+
type: punishmentType,
|
|
598
|
+
description: `${pos1.name}${pos1.branch}与${pos2.name}${pos2.branch}${punishmentType}`,
|
|
599
|
+
scoreChange: 0
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Check for Harms (害)
|
|
608
|
+
*/
|
|
609
|
+
static checkHarms(chart, scores, adjustments, breakdown) {
|
|
610
|
+
const harms = [
|
|
611
|
+
['子', '未'], ['丑', '午'], ['寅', '巳'],
|
|
612
|
+
['卯', '辰'], ['申', '亥'], ['酉', '戌']
|
|
613
|
+
];
|
|
614
|
+
const positions = [
|
|
615
|
+
{ branch: chart.year.branch, name: '年支', index: 0 },
|
|
616
|
+
{ branch: chart.month.branch, name: '月支', index: 1 },
|
|
617
|
+
{ branch: chart.day.branch, name: '日支', index: 2 },
|
|
618
|
+
{ branch: chart.hour.branch, name: '时支', index: 3 }
|
|
619
|
+
];
|
|
620
|
+
// Check all positions for harms
|
|
621
|
+
for (let i = 0; i < positions.length; i++) {
|
|
622
|
+
for (let j = i + 1; j < positions.length; j++) {
|
|
623
|
+
const pos1 = positions[i];
|
|
624
|
+
const pos2 = positions[j];
|
|
625
|
+
for (const harm of harms) {
|
|
626
|
+
if ((harm[0] === pos1.branch && harm[1] === pos2.branch) ||
|
|
627
|
+
(harm[1] === pos1.branch && harm[0] === pos2.branch)) {
|
|
628
|
+
// Apply harm with distance decay
|
|
629
|
+
const distance = Math.abs(pos1.index - pos2.index);
|
|
630
|
+
const decay = distance === 1 ? DISTANCE_DECAY.adjacent :
|
|
631
|
+
distance === 2 ? DISTANCE_DECAY.oneApart :
|
|
632
|
+
DISTANCE_DECAY.twoApart;
|
|
633
|
+
// Harm reduces by 20% with decay
|
|
634
|
+
const reduction = 0.2 * decay;
|
|
635
|
+
this.reduceBranchScores(pos1.branch, scores, reduction, chart);
|
|
636
|
+
this.reduceBranchScores(pos2.branch, scores, reduction, chart);
|
|
637
|
+
adjustments.push({
|
|
638
|
+
type: '地支相害',
|
|
639
|
+
description: `${pos1.name}${pos1.branch}与${pos2.name}${pos2.branch}相害`,
|
|
640
|
+
scoreChange: 0
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Apply generating and overcoming cycles
|
|
649
|
+
*/
|
|
650
|
+
static applyGeneratingOvercoming(chart, scores, adjustments, breakdown) {
|
|
651
|
+
// Basic five element interactions (生克)
|
|
652
|
+
// This is the lowest priority and applies to remaining energy
|
|
653
|
+
const elements = ['wood', 'fire', 'earth', 'metal', 'water'];
|
|
654
|
+
const elementNames = { wood: '木', fire: '火', earth: '土', metal: '金', water: '水' };
|
|
655
|
+
// Apply generating cycle (生) - 10% transfer
|
|
656
|
+
elements.forEach(element => {
|
|
657
|
+
const generated = this.getElementKey(this.getGeneratedElement(elementNames[element]));
|
|
658
|
+
if (scores[element] > 0 && generated !== element) {
|
|
659
|
+
const transfer = Math.round(scores[element] * 0.1);
|
|
660
|
+
scores[element] -= transfer;
|
|
661
|
+
scores[generated] += transfer;
|
|
662
|
+
if (transfer > 0) {
|
|
663
|
+
adjustments.push({
|
|
664
|
+
type: '五行相生',
|
|
665
|
+
description: `${elementNames[element]}生${elementNames[generated]}`,
|
|
666
|
+
scoreChange: transfer
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
// Apply overcoming cycle (克) - 20% reduction
|
|
672
|
+
elements.forEach(element => {
|
|
673
|
+
const controlled = this.getElementKey(this.getControlledElement(elementNames[element]));
|
|
674
|
+
if (scores[element] > 0 && controlled !== element) {
|
|
675
|
+
const reduction = Math.round(scores[controlled] * 0.2);
|
|
676
|
+
scores[controlled] = Math.max(0, scores[controlled] - reduction);
|
|
677
|
+
if (reduction > 0) {
|
|
678
|
+
adjustments.push({
|
|
679
|
+
type: '五行相克',
|
|
680
|
+
description: `${elementNames[element]}克${elementNames[controlled]}`,
|
|
681
|
+
scoreChange: -reduction
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Helper method to get element key from Chinese name
|
|
689
|
+
*/
|
|
690
|
+
static getElementKey(element) {
|
|
691
|
+
const map = {
|
|
692
|
+
'木': 'wood',
|
|
693
|
+
'火': 'fire',
|
|
694
|
+
'土': 'earth',
|
|
695
|
+
'金': 'metal',
|
|
696
|
+
'水': 'water',
|
|
697
|
+
'甲': 'wood', '乙': 'wood',
|
|
698
|
+
'丙': 'fire', '丁': 'fire',
|
|
699
|
+
'戊': 'earth', '己': 'earth',
|
|
700
|
+
'庚': 'metal', '辛': 'metal',
|
|
701
|
+
'壬': 'water', '癸': 'water'
|
|
702
|
+
};
|
|
703
|
+
return map[element] || 'earth';
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Helper method to get Chinese element name
|
|
707
|
+
*/
|
|
708
|
+
static getElementName(element) {
|
|
709
|
+
const map = {
|
|
710
|
+
'木': '木',
|
|
711
|
+
'火': '火',
|
|
712
|
+
'土': '土',
|
|
713
|
+
'金': '金',
|
|
714
|
+
'水': '水'
|
|
715
|
+
};
|
|
716
|
+
return map[element] || element;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Get generating element (the one that generates this element)
|
|
720
|
+
*/
|
|
721
|
+
static getGeneratingElement(element) {
|
|
722
|
+
const map = {
|
|
723
|
+
'木': '水',
|
|
724
|
+
'火': '木',
|
|
725
|
+
'土': '火',
|
|
726
|
+
'金': '土',
|
|
727
|
+
'水': '金'
|
|
728
|
+
};
|
|
729
|
+
return map[element] || '土';
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Get controlling element (the one that controls this element)
|
|
733
|
+
*/
|
|
734
|
+
static getControllingElement(element) {
|
|
735
|
+
const map = {
|
|
736
|
+
'木': '金',
|
|
737
|
+
'火': '水',
|
|
738
|
+
'土': '木',
|
|
739
|
+
'金': '火',
|
|
740
|
+
'水': '土'
|
|
741
|
+
};
|
|
742
|
+
return map[element] || '木';
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Get generated element (the one this element generates)
|
|
746
|
+
*/
|
|
747
|
+
static getGeneratedElement(element) {
|
|
748
|
+
const map = {
|
|
749
|
+
'木': '火',
|
|
750
|
+
'火': '土',
|
|
751
|
+
'土': '金',
|
|
752
|
+
'金': '水',
|
|
753
|
+
'水': '木'
|
|
754
|
+
};
|
|
755
|
+
return map[element] || '金';
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Get controlled element (the one this element controls)
|
|
759
|
+
*/
|
|
760
|
+
static getControlledElement(element) {
|
|
761
|
+
const map = {
|
|
762
|
+
'木': '土',
|
|
763
|
+
'火': '金',
|
|
764
|
+
'土': '水',
|
|
765
|
+
'金': '木',
|
|
766
|
+
'水': '火'
|
|
767
|
+
};
|
|
768
|
+
return map[element] || '水';
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Calculate total energy in branches
|
|
772
|
+
*/
|
|
773
|
+
static calculateBranchEnergy(branches, chart, scores) {
|
|
774
|
+
let totalEnergy = 0;
|
|
775
|
+
// Get positions of branches in chart
|
|
776
|
+
const positions = [
|
|
777
|
+
{ branch: chart.year.branch, weight: POSITION_WEIGHTS.yearBranch },
|
|
778
|
+
{ branch: chart.month.branch, weight: 0 }, // Month branch handled separately
|
|
779
|
+
{ branch: chart.day.branch, weight: POSITION_WEIGHTS.dayBranch },
|
|
780
|
+
{ branch: chart.hour.branch, weight: POSITION_WEIGHTS.hourBranch }
|
|
781
|
+
];
|
|
782
|
+
branches.forEach(targetBranch => {
|
|
783
|
+
// Find this branch in the chart
|
|
784
|
+
const pos = positions.find(p => p.branch === targetBranch);
|
|
785
|
+
if (pos && pos.weight > 0) {
|
|
786
|
+
// Get energy from hidden stems
|
|
787
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[targetBranch];
|
|
788
|
+
if (hiddenStems) {
|
|
789
|
+
hiddenStems.forEach(({ stem, power }) => {
|
|
790
|
+
const element = this.getStemElement(stem);
|
|
791
|
+
const elementKey = this.getElementKey(element);
|
|
792
|
+
const energy = Math.round(pos.weight * power);
|
|
793
|
+
totalEnergy += energy;
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
return totalEnergy;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Clear scores for specified branches
|
|
802
|
+
*/
|
|
803
|
+
static clearBranchScores(branches, chart, scores) {
|
|
804
|
+
branches.forEach(targetBranch => {
|
|
805
|
+
// Clear scores from hidden stems of this branch
|
|
806
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[targetBranch];
|
|
807
|
+
if (hiddenStems) {
|
|
808
|
+
hiddenStems.forEach(({ stem }) => {
|
|
809
|
+
const element = this.getStemElement(stem);
|
|
810
|
+
const elementKey = this.getElementKey(element);
|
|
811
|
+
// Find how much this branch contributed and subtract it
|
|
812
|
+
// This is a simplified approach - in reality we'd need to track contributions
|
|
813
|
+
const positions = [
|
|
814
|
+
{ branch: chart.year.branch, weight: POSITION_WEIGHTS.yearBranch },
|
|
815
|
+
{ branch: chart.day.branch, weight: POSITION_WEIGHTS.dayBranch },
|
|
816
|
+
{ branch: chart.hour.branch, weight: POSITION_WEIGHTS.hourBranch }
|
|
817
|
+
];
|
|
818
|
+
const pos = positions.find(p => p.branch === targetBranch);
|
|
819
|
+
if (pos) {
|
|
820
|
+
hiddenStems.forEach(({ stem: hs, power }) => {
|
|
821
|
+
if (hs === stem) {
|
|
822
|
+
const deduction = Math.round(pos.weight * power);
|
|
823
|
+
scores[elementKey] = Math.max(0, scores[elementKey] - deduction);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Get branch element scores
|
|
833
|
+
*/
|
|
834
|
+
static getBranchElementScores(branch, chart, scores) {
|
|
835
|
+
const result = {};
|
|
836
|
+
// Get position weight
|
|
837
|
+
let weight = 0;
|
|
838
|
+
if (chart.year.branch === branch)
|
|
839
|
+
weight = POSITION_WEIGHTS.yearBranch;
|
|
840
|
+
else if (chart.day.branch === branch)
|
|
841
|
+
weight = POSITION_WEIGHTS.dayBranch;
|
|
842
|
+
else if (chart.hour.branch === branch)
|
|
843
|
+
weight = POSITION_WEIGHTS.hourBranch;
|
|
844
|
+
else if (chart.month.branch === branch)
|
|
845
|
+
weight = MONTH_BRANCH_ENERGY;
|
|
846
|
+
// Get scores from hidden stems
|
|
847
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[branch];
|
|
848
|
+
if (hiddenStems && weight > 0) {
|
|
849
|
+
hiddenStems.forEach(({ stem, power }) => {
|
|
850
|
+
const element = this.getStemElement(stem);
|
|
851
|
+
const elementKey = this.getElementKey(element);
|
|
852
|
+
result[elementKey] = Math.round(weight * power);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
return result;
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Get total score for a branch
|
|
859
|
+
*/
|
|
860
|
+
static getBranchTotalScore(branch, chart, scores) {
|
|
861
|
+
const branchScores = this.getBranchElementScores(branch, chart, scores);
|
|
862
|
+
return Object.values(branchScores).reduce((sum, score) => sum + score, 0);
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Reduce branch scores by percentage
|
|
866
|
+
*/
|
|
867
|
+
static reduceBranchScores(branch, scores, percentage, chart) {
|
|
868
|
+
// Find the position weight for this branch
|
|
869
|
+
let positionWeight = 0;
|
|
870
|
+
if (chart.year.branch === branch) {
|
|
871
|
+
positionWeight = POSITION_WEIGHTS.yearBranch;
|
|
872
|
+
}
|
|
873
|
+
else if (chart.day.branch === branch) {
|
|
874
|
+
positionWeight = POSITION_WEIGHTS.dayBranch;
|
|
875
|
+
}
|
|
876
|
+
else if (chart.hour.branch === branch) {
|
|
877
|
+
positionWeight = POSITION_WEIGHTS.hourBranch;
|
|
878
|
+
}
|
|
879
|
+
else if (chart.month.branch === branch) {
|
|
880
|
+
// Month branch has special handling - it gets the commanding element's energy
|
|
881
|
+
positionWeight = MONTH_BRANCH_ENERGY;
|
|
882
|
+
}
|
|
883
|
+
// Apply reduction only to the contribution from this specific branch
|
|
884
|
+
const hiddenStems = bazi_1.HIDDEN_STEMS[branch];
|
|
885
|
+
if (hiddenStems && positionWeight > 0) {
|
|
886
|
+
hiddenStems.forEach(({ stem, power }) => {
|
|
887
|
+
const element = this.getStemElement(stem);
|
|
888
|
+
const elementKey = this.getElementKey(element);
|
|
889
|
+
// Calculate the original contribution from this branch
|
|
890
|
+
const originalContribution = Math.round(positionWeight * power);
|
|
891
|
+
const reduction = Math.round(originalContribution * percentage);
|
|
892
|
+
// Reduce the element score by the calculated reduction
|
|
893
|
+
scores[elementKey] = Math.max(0, scores[elementKey] - reduction);
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Check if harmony can transform
|
|
899
|
+
*/
|
|
900
|
+
static checkHarmonyTransformation(element, chart) {
|
|
901
|
+
// Check 1: Seasonal support (得时)
|
|
902
|
+
const monthBranch = chart.month.branch;
|
|
903
|
+
const seasonSupport = this.hasSeasonalSupport(element, monthBranch);
|
|
904
|
+
// Check 2: Stem revelation (透干)
|
|
905
|
+
const stemRevelation = this.hasStemRevelation(element, chart);
|
|
906
|
+
// Both conditions must be met
|
|
907
|
+
return seasonSupport && stemRevelation;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Check if combination can transform
|
|
911
|
+
*/
|
|
912
|
+
static checkCombinationTransformation(element, chart) {
|
|
913
|
+
// Similar to harmony transformation
|
|
914
|
+
return this.checkHarmonyTransformation(element, chart);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Check if element has seasonal support
|
|
918
|
+
*/
|
|
919
|
+
static hasSeasonalSupport(element, monthBranch) {
|
|
920
|
+
// Seasonal support mapping
|
|
921
|
+
const seasonalSupport = {
|
|
922
|
+
'木': ['寅', '卯', '辰'], // Spring supports wood
|
|
923
|
+
'火': ['巳', '午', '未'], // Summer supports fire
|
|
924
|
+
'金': ['申', '酉', '戌'], // Autumn supports metal
|
|
925
|
+
'水': ['亥', '子', '丑'], // Winter supports water
|
|
926
|
+
'土': ['辰', '未', '戌', '丑'] // Four seasons support earth
|
|
927
|
+
};
|
|
928
|
+
return seasonalSupport[element]?.includes(monthBranch) || false;
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Check if element is revealed in stems
|
|
932
|
+
*/
|
|
933
|
+
static hasStemRevelation(element, chart) {
|
|
934
|
+
const stems = [
|
|
935
|
+
chart.year.stem,
|
|
936
|
+
chart.month.stem,
|
|
937
|
+
chart.day.stem,
|
|
938
|
+
chart.hour.stem
|
|
939
|
+
];
|
|
940
|
+
// Check if any stem has the same element
|
|
941
|
+
return stems.some(stem => {
|
|
942
|
+
const stemElement = this.getStemElement(stem);
|
|
943
|
+
return this.getElementKey(stemElement) === element;
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Categorize strength based on score
|
|
948
|
+
*/
|
|
949
|
+
static categorizeStrength(score) {
|
|
950
|
+
for (const category of STRENGTH_CATEGORIES) {
|
|
951
|
+
if (score >= category.min && score <= category.max) {
|
|
952
|
+
return category;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return STRENGTH_CATEGORIES.find(c => c.strength === '中和');
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Generate analysis text
|
|
959
|
+
*/
|
|
960
|
+
static generateAnalysis(category, score, element) {
|
|
961
|
+
const scoreDesc = `${score}分`;
|
|
962
|
+
const categoryDesc = category.description;
|
|
963
|
+
const analysisMap = {
|
|
964
|
+
'衰极': {
|
|
965
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),可考虑从弱,需要金火土的制化`,
|
|
966
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),可考虑从弱,需要水土金的制化`,
|
|
967
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),可考虑从弱,需要木水的制化`,
|
|
968
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),可考虑从弱,需要火水木的制化`,
|
|
969
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),可考虑从弱,需要土火木的制化`
|
|
970
|
+
},
|
|
971
|
+
'身弱': {
|
|
972
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),需要大量水木生扶`,
|
|
973
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),需要大量木火生扶`,
|
|
974
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),需要大量火土生扶`,
|
|
975
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),需要大量土金生扶`,
|
|
976
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),需要大量金水生扶`
|
|
977
|
+
},
|
|
978
|
+
'偏弱': {
|
|
979
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),喜水生木助,忌金克火泄`,
|
|
980
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),喜木生火助,忌水克土泄`,
|
|
981
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),喜火生土助,忌木克金泄`,
|
|
982
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),喜土生金助,忌火克水泄`,
|
|
983
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),喜金生水助,忌土克木泄`
|
|
984
|
+
},
|
|
985
|
+
'中和': {
|
|
986
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),五行平衡,宜维持现状`,
|
|
987
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),五行平衡,宜维持现状`,
|
|
988
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),五行平衡,宜维持现状`,
|
|
989
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),五行平衡,宜维持现状`,
|
|
990
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),五行平衡,宜维持现状`
|
|
991
|
+
},
|
|
992
|
+
'偏强': {
|
|
993
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),需要金克火泄土耗`,
|
|
994
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),需要水克土泄金耗`,
|
|
995
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),需要木克金泄水耗`,
|
|
996
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),需要火克水泄木耗`,
|
|
997
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),需要土克木泄火耗`
|
|
998
|
+
},
|
|
999
|
+
'身旺': {
|
|
1000
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),宜泄不宜克,火土为用`,
|
|
1001
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),宜泄不宜克,土金为用`,
|
|
1002
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),宜泄不宜克,金水为用`,
|
|
1003
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),宜泄不宜克,水木为用`,
|
|
1004
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),宜泄不宜克,木火为用`
|
|
1005
|
+
},
|
|
1006
|
+
'旺极': {
|
|
1007
|
+
'木': `日主木${categoryDesc}(${scoreDesc}),一气专旺,顺势而为`,
|
|
1008
|
+
'火': `日主火${categoryDesc}(${scoreDesc}),一气专旺,顺势而为`,
|
|
1009
|
+
'土': `日主土${categoryDesc}(${scoreDesc}),一气专旺,顺势而为`,
|
|
1010
|
+
'金': `日主金${categoryDesc}(${scoreDesc}),一气专旺,顺势而为`,
|
|
1011
|
+
'水': `日主水${categoryDesc}(${scoreDesc}),一气专旺,顺势而为`
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
return analysisMap[categoryDesc]?.[element] || `日主${element}${categoryDesc}(${scoreDesc})`;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Generate suggestions based on strength
|
|
1018
|
+
*/
|
|
1019
|
+
static generateSuggestions(strength, element) {
|
|
1020
|
+
const suggestionMap = {
|
|
1021
|
+
'衰极': [
|
|
1022
|
+
'命局极弱,宜顺从大势,不宜逆流而上',
|
|
1023
|
+
'适合依附他人,借力使力',
|
|
1024
|
+
'避免独自创业,宜合作共赢',
|
|
1025
|
+
'注重人际关系,贵人运佳'
|
|
1026
|
+
],
|
|
1027
|
+
'身弱': [
|
|
1028
|
+
'命局偏弱,需要生扶帮助',
|
|
1029
|
+
'寻找贵人相助,善用外力',
|
|
1030
|
+
'避免过度消耗,注意休息',
|
|
1031
|
+
'选择稳定发展,循序渐进'
|
|
1032
|
+
],
|
|
1033
|
+
'偏弱': [
|
|
1034
|
+
'加强自身能力,提升专业技能',
|
|
1035
|
+
'寻找贵人相助,善用外力',
|
|
1036
|
+
'避免过度消耗,注意休息',
|
|
1037
|
+
'选择稳定发展,循序渐进'
|
|
1038
|
+
],
|
|
1039
|
+
'中和': [
|
|
1040
|
+
'保持现有平衡,稳中求进',
|
|
1041
|
+
'发挥自身优势,把握机会',
|
|
1042
|
+
'注意五行流通,避免偏颇',
|
|
1043
|
+
'中庸之道,进退有度'
|
|
1044
|
+
],
|
|
1045
|
+
'偏强': [
|
|
1046
|
+
'发挥自身优势,积极进取',
|
|
1047
|
+
'适合主动发展,把握机会',
|
|
1048
|
+
'注意适度收敛,避免过度',
|
|
1049
|
+
'善用自身能量,帮助他人'
|
|
1050
|
+
],
|
|
1051
|
+
'身旺': [
|
|
1052
|
+
'发挥领导才能,勇于担当',
|
|
1053
|
+
'适合开创事业,独当一面',
|
|
1054
|
+
'注意谦虚谨慎,避免刚愎',
|
|
1055
|
+
'善用自身能量,造福他人'
|
|
1056
|
+
],
|
|
1057
|
+
'旺极': [
|
|
1058
|
+
'顺势而为,不宜逆转',
|
|
1059
|
+
'专注一个方向深耕',
|
|
1060
|
+
'避免分散精力,集中突破',
|
|
1061
|
+
'以柔克刚,以德服人'
|
|
1062
|
+
]
|
|
1063
|
+
};
|
|
1064
|
+
return suggestionMap[strength] || suggestionMap['中和'];
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Generate characteristics
|
|
1068
|
+
*/
|
|
1069
|
+
static generateCharacteristics(strength, score, factors) {
|
|
1070
|
+
const characteristics = [];
|
|
1071
|
+
if (strength === '衰极') {
|
|
1072
|
+
characteristics.push('日主极弱,可能从弱格');
|
|
1073
|
+
}
|
|
1074
|
+
else if (strength === '身弱') {
|
|
1075
|
+
characteristics.push('日主偏弱,需要生扶');
|
|
1076
|
+
}
|
|
1077
|
+
else if (strength === '中和') {
|
|
1078
|
+
characteristics.push('日主中和,五行平衡');
|
|
1079
|
+
}
|
|
1080
|
+
else if (strength === '身旺') {
|
|
1081
|
+
characteristics.push('日主偏旺,需要制化');
|
|
1082
|
+
}
|
|
1083
|
+
else if (strength === '旺极') {
|
|
1084
|
+
characteristics.push('日主极旺,可能从旺格');
|
|
1085
|
+
}
|
|
1086
|
+
if (factors.supportingForce > factors.opposingForce * 2) {
|
|
1087
|
+
characteristics.push('生扶力量强大');
|
|
1088
|
+
}
|
|
1089
|
+
else if (factors.opposingForce > factors.supportingForce * 2) {
|
|
1090
|
+
characteristics.push('克泄耗力量强大');
|
|
1091
|
+
}
|
|
1092
|
+
return characteristics;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Categorize breakdown item
|
|
1096
|
+
*/
|
|
1097
|
+
static categorizeBreakdownItem(item) {
|
|
1098
|
+
if (item.includes('干')) {
|
|
1099
|
+
return 'stem';
|
|
1100
|
+
}
|
|
1101
|
+
else if (item.includes('支')) {
|
|
1102
|
+
return 'root';
|
|
1103
|
+
}
|
|
1104
|
+
else {
|
|
1105
|
+
return 'interaction';
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
// Basic helper methods
|
|
1109
|
+
static getStemElement(stem) {
|
|
1110
|
+
const stemData = bazi_1.HEAVENLY_STEMS.find(s => s.name === stem);
|
|
1111
|
+
return stemData?.element || '';
|
|
1112
|
+
}
|
|
1113
|
+
static getBranchElement(branch) {
|
|
1114
|
+
const branchData = bazi_1.EARTHLY_BRANCHES.find(b => b.name === branch);
|
|
1115
|
+
return branchData?.element || '';
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
exports.StrengthAnalyzer = StrengthAnalyzer;
|
|
1119
|
+
//# sourceMappingURL=StrengthAnalyzer.js.map
|