Spaces:
Sleeping
Sleeping
| import { DynamicReport, StaticReport, SynthesisReport, DimensionScores, RuleEvidence, ScopeSynthesisReport, TimeLayerScope } from './types'; | |
| import { CONFLICT_RESOLUTION, BONUS_RULES, PENALTY_RULES } from './scoring-tables'; | |
| import { RuleAuditor } from './rule-auditor'; | |
| export class SynthesisLayer { | |
| private staticReport: StaticReport; | |
| private dynamicReport: DynamicReport; | |
| private auditor: RuleAuditor; | |
| private version = 'synthesis-v2.0.0'; | |
| constructor(staticReport: StaticReport, dynamicReport: DynamicReport, auditor: RuleAuditor) { | |
| this.staticReport = staticReport; | |
| this.dynamicReport = dynamicReport; | |
| this.auditor = auditor; | |
| } | |
| public analyze(): SynthesisReport { | |
| const scopes: TimeLayerScope[] = ['original', 'daXian', 'liuNian', 'liuYue', 'liuRi', 'liuShi']; | |
| const scopedReports: Record<string, ScopeSynthesisReport> = {}; | |
| scopes.forEach(scope => { | |
| scopedReports[scope] = this.analyzeScope(scope); | |
| }); | |
| return { | |
| global: scopedReports['original'], | |
| scoped: scopedReports, | |
| }; | |
| } | |
| private analyzeScope(scope: TimeLayerScope): ScopeSynthesisReport { | |
| // 1. 提取所有规则证据 (这里可以根据scope进行筛选,目前简化为全部) | |
| const allEvidences: RuleEvidence[] = this.auditor.getEvidencesByScope(scope); | |
| // 2. 基础底分配置 | |
| let totalScore = 50; | |
| const dimensionScores: DimensionScores = { | |
| career: 50, | |
| wealth: 50, | |
| marriage: 50, | |
| health: 50, | |
| personality: 50, | |
| }; | |
| // 3. 星曜状态基础加减分 (透明化权重) | |
| totalScore += this.staticReport.starsStatus.miaoWangCount * 2; | |
| totalScore -= this.staticReport.starsStatus.pingXianCount * 2; | |
| totalScore += this.staticReport.starsStatus.jiXingCount * 3; | |
| totalScore -= this.staticReport.starsStatus.shaXingCount * 3; | |
| // 4. 累加各个规则的影响分 | |
| let rawBonus = 0; | |
| let rawPenalty = 0; | |
| allEvidences.forEach(ev => { | |
| if (ev.scoreImpact > 0) { | |
| rawBonus += ev.scoreImpact; | |
| } else if (ev.scoreImpact < 0) { | |
| rawPenalty += ev.scoreImpact; | |
| } | |
| this.auditor.collectScoreBreakdown(scope, { | |
| ruleId: ev.ruleId, | |
| title: ev.title, | |
| scoreImpact: ev.scoreImpact, | |
| tags: ev.tags, | |
| }); | |
| // 分项雷达图得分累计 | |
| if (ev.tags.includes('事业')) dimensionScores.career += ev.scoreImpact; | |
| if (ev.tags.includes('财富')) dimensionScores.wealth += ev.scoreImpact; | |
| if (ev.tags.includes('婚姻')) dimensionScores.marriage += ev.scoreImpact; | |
| if (ev.tags.includes('健康')) dimensionScores.health += ev.scoreImpact; | |
| if (ev.tags.includes('性格')) dimensionScores.personality += ev.scoreImpact; | |
| }); | |
| // 5. 静动交涉:冲突与增强 | |
| const synthesisEvidences: RuleEvidence[] = []; | |
| // TODO: Need scope-specific sihua facts, here we use original for simplicity | |
| const shengNianJiPalace = this.dynamicReport.sihua.shengNian['忌']; | |
| const shengNianLuPalace = this.dynamicReport.sihua.shengNian['禄']; | |
| let hasLu = false; | |
| let hasJi = false; | |
| if (shengNianJiPalace && ['命宫', '财帛宫', '官禄宫', '迁移宫'].includes(shengNianJiPalace)) { | |
| hasJi = true; | |
| rawPenalty -= 15; // 追加惩罚 | |
| if (this.staticReport.patterns.length > 0) { | |
| const ev: RuleEvidence = { | |
| ruleId: 'ZW_SYN_CONFLICT_JI_BREAK_v1', | |
| title: '吉格遇忌冲', | |
| type: 'synthesis', | |
| description: `静态命盘有成格,但生年忌落入【${shengNianJiPalace}】冲克,主吉处藏凶,成败起伏大。`, | |
| boardEvidence: ['静态有格局', `动态生年忌入${shengNianJiPalace}`], | |
| scoreImpact: -15, | |
| tags: ['风险', '事业', '财富'], | |
| version: this.version, | |
| scope | |
| }; | |
| synthesisEvidences.push(ev); | |
| this.auditor.collectEvidence(ev); | |
| } | |
| } | |
| if (shengNianLuPalace && ['命宫', '财帛宫', '官禄宫', '迁移宫'].includes(shengNianLuPalace)) { | |
| hasLu = true; | |
| rawBonus += 15; // 追加奖励 | |
| if (this.staticReport.patterns.length > 0) { | |
| const ev: RuleEvidence = { | |
| ruleId: 'ZW_SYN_REINFORCE_LU_BOOST_v1', | |
| title: '吉格逢禄引动', | |
| type: 'synthesis', | |
| description: `静态成格且生年禄入【${shengNianLuPalace}】,静动态高度一致,大吉,此生必有建树。`, | |
| boardEvidence: ['静态有格局', `动态生年禄入${shengNianLuPalace}`], | |
| scoreImpact: 15, | |
| tags: ['机遇', '事业', '财富'], | |
| version: this.version, | |
| scope | |
| }; | |
| synthesisEvidences.push(ev); | |
| this.auditor.collectEvidence(ev); | |
| } | |
| } | |
| // 6. 冲突解决逻辑 | |
| const hasGoodPattern = this.staticReport.patterns.length > 0; | |
| const hasBadInteraction = this.staticReport.interactions.some(e => e.scoreImpact < 0); | |
| let finalBonus = rawBonus; | |
| let finalPenalty = rawPenalty; | |
| // 遍历优先级解决冲突 | |
| for (const resolution of CONFLICT_RESOLUTION) { | |
| if (resolution.name === '禄忌交战' && resolution.condition(hasLu, hasJi)) { | |
| const adj = { | |
| resolutionId: 'CONFLICT_LU_JI', | |
| description: resolution.action, | |
| originalScore: finalBonus, | |
| adjustedScore: finalBonus / 2 | |
| }; | |
| finalBonus = finalBonus / 2; | |
| this.auditor.collectConflictAdjustment(scope, adj); | |
| const ev: RuleEvidence = { | |
| ruleId: 'ZW_SYN_CONFLICT_LU_JI_v1', | |
| title: '禄忌交战', | |
| type: 'synthesis', | |
| description: resolution.action, | |
| boardEvidence: ['同时逢生年禄与生年忌入核心宫位'], | |
| scoreImpact: 0, // 仅作说明 | |
| tags: ['冲突'], | |
| version: this.version, | |
| scope | |
| }; | |
| synthesisEvidences.push(ev); | |
| this.auditor.collectEvidence(ev); | |
| } | |
| if (resolution.name === '破格优先' && resolution.condition(hasGoodPattern, hasBadInteraction)) { | |
| const adj = { | |
| resolutionId: 'CONFLICT_BROKEN_PATTERN', | |
| description: resolution.action, | |
| originalScore: finalPenalty, | |
| adjustedScore: finalPenalty - 10 | |
| }; | |
| finalPenalty -= 10; // 向下修正 | |
| this.auditor.collectConflictAdjustment(scope, adj); | |
| const ev: RuleEvidence = { | |
| ruleId: 'ZW_SYN_CONFLICT_BROKEN_PATTERN_v1', | |
| title: '破格优先', | |
| type: 'synthesis', | |
| description: resolution.action, | |
| boardEvidence: ['静态有吉格,但同时存在凶格夹冲'], | |
| scoreImpact: -10, | |
| tags: ['冲突', '风险'], | |
| version: this.version, | |
| scope | |
| }; | |
| synthesisEvidences.push(ev); | |
| this.auditor.collectEvidence(ev); | |
| } | |
| } | |
| totalScore += finalBonus + finalPenalty; | |
| // 约束分数范围 | |
| const clamp = (val: number) => Math.max(0, Math.min(100, val)); | |
| totalScore = clamp(totalScore); | |
| dimensionScores.career = clamp(dimensionScores.career); | |
| dimensionScores.wealth = clamp(dimensionScores.wealth); | |
| dimensionScores.marriage = clamp(dimensionScores.marriage); | |
| dimensionScores.health = clamp(dimensionScores.health); | |
| dimensionScores.personality = clamp(dimensionScores.personality); | |
| // 评估置信度 | |
| let confidence: 'High' | 'Medium' | 'Low' = 'Medium'; | |
| if (this.staticReport.starsStatus.shaXingCount >= 4 && synthesisEvidences.some(e => e.scoreImpact < 0)) { | |
| confidence = 'Low'; // 煞星多且有冲突,命盘波动极大,断语可信度下降 | |
| } else if (this.staticReport.starsStatus.miaoWangCount >= 6 && this.staticReport.starsStatus.shaXingCount <= 2) { | |
| confidence = 'High'; // 命盘稳定,特征明显 | |
| } | |
| return { | |
| scope, | |
| totalScore, | |
| dimensionScores, | |
| confidence, | |
| evidences: synthesisEvidences, | |
| scoreBreakdown: this.auditor.getScoreBreakdown(scope), | |
| conflictAdjustments: this.auditor.getConflictAdjustments(scope), | |
| }; | |
| } | |
| } | |