import { AstrolabeData, PalaceData, StaticReport, StarData, RuleEvidence } from './types'; // 基础吉煞星分类 const JI_XING = ['左辅', '右弼', '文昌', '文曲', '天魁', '天钺', '禄存', '天马']; const SHA_XING = ['擎羊', '陀罗', '火星', '铃星', '地空', '地劫']; export class StaticAnalyzer { private astrolabe: AstrolabeData; private version = 'static-v2.0.0'; constructor(astrolabe: AstrolabeData) { this.astrolabe = astrolabe; } public analyze(): StaticReport { return { starsStatus: this.analyzeStarsStatus(), patterns: this.analyzePatterns(), topics: { career: this.analyzeTopic('官禄宫', '事业'), wealth: this.analyzeTopic('财帛宫', '财富'), marriage: this.analyzeTopic('夫妻宫', '婚姻'), health: this.analyzeTopic('疾厄宫', '健康'), property: this.analyzeTopic('田宅宫', '资产'), }, interactions: this.analyzeInteractions(), bodyMindLink: this.analyzeBodyMindLink(), }; } // 1. 星曜状态统计(全盘) private analyzeStarsStatus() { let miaoWangCount = 0; let pingXianCount = 0; let jiXingCount = 0; let shaXingCount = 0; this.astrolabe.palaces.forEach((palace) => { palace.majorStars.forEach((star) => { if (['庙', '旺'].includes(star.brightness || '')) miaoWangCount++; if (['平', '陷', '不'].includes(star.brightness || '')) pingXianCount++; }); palace.minorStars.forEach((star) => { if (JI_XING.includes(star.name)) jiXingCount++; if (SHA_XING.includes(star.name)) shaXingCount++; }); }); return { miaoWangCount, pingXianCount, jiXingCount, shaXingCount }; } // 2. 深度格局识别 (带证据链) private analyzePatterns(): RuleEvidence[] { const patterns: RuleEvidence[] = []; const mingGong = this.getPalaceByName('命宫'); if (!mingGong) return patterns; const sanFangStars = this.getSanFangSiZhengStars(mingGong); const starNames = sanFangStars.map(s => s.name); const mingGongStars = mingGong.majorStars.map(s => s.name); // 机月同梁 if (this.containsAll(starNames, ['天机', '太阴', '天同', '天梁'])) { patterns.push({ ruleId: 'ZW_STATIC_PATTERN_JIYUETONGLIANG_v1', title: '机月同梁格', type: 'static', description: '心思细腻,善于谋划,适合在大企业或政府机关做幕僚、参谋,不利于自己出头做老板。', boardEvidence: ['命宫三方四正凑齐天机、太阴、天同、天梁'], conflicts: this.containsAny(starNames, SHA_XING) ? ['见煞星,心思易生变,多思多虑'] : [], scoreImpact: 15, tags: ['事业', '性格'], version: this.version }); } // 杀破狼 if (this.containsAny(mingGongStars, ['七杀', '破军', '贪狼'])) { patterns.push({ ruleId: 'ZW_STATIC_PATTERN_SHAPOLANG_v1', title: '杀破狼格', type: 'static', description: '主变动、开创,一生起伏较大,不甘人后,适合军警、武职或开创性极强的行业。', boardEvidence: [`命宫主星见${mingGongStars.filter(s => ['七杀', '破军', '贪狼'].includes(s)).join('、')}`], conflicts: this.containsAll(mingGongStars, ['火星']) ? ['逢火星,主横发横破,需见好就收'] : [], scoreImpact: 10, tags: ['事业', '性格'], version: this.version }); } // 紫府同宫 if (this.containsAll(mingGongStars, ['紫微', '天府'])) { patterns.push({ ruleId: 'ZW_STATIC_PATTERN_ZIFUTONGGONG_v1', title: '紫府同宫格', type: 'static', description: '为人清高保守,好面子。主孤高,容易曲高和寡。', boardEvidence: ['命宫同见紫微、天府两大主星'], conflicts: [], scoreImpact: 15, tags: ['性格'], version: this.version }); } // 铃贪/火贪 if (this.containsAll(starNames, ['贪狼', '火星'])) { patterns.push({ ruleId: 'ZW_STATIC_PATTERN_HUOTAN_v1', title: '火贪格', type: 'static', description: '主横发爆发。发家之后需守成置产,切勿持续冒险。', boardEvidence: ['命宫三方四正见贪狼与火星交会'], conflicts: this.containsAny(starNames, ['地空', '地劫']) ? ['遇空劫,爆发力大减'] : [], scoreImpact: 20, tags: ['财富', '事业'], version: this.version }); } else if (this.containsAll(starNames, ['贪狼', '铃星'])) { patterns.push({ ruleId: 'ZW_STATIC_PATTERN_LINGTAN_v1', title: '铃贪格', type: 'static', description: '主暗发,闷声发大财。需保持低调,不可炫耀。', boardEvidence: ['命宫三方四正见贪狼与铃星交会'], conflicts: this.containsAny(starNames, ['地空', '地劫']) ? ['遇空劫,横发变虚花'] : [], scoreImpact: 20, tags: ['财富'], version: this.version }); } return patterns; } // 3. 专题宫位深度拆解 private analyzeTopic(palaceName: string, tag: string): RuleEvidence[] { const evidences: RuleEvidence[] = []; const palace = this.getPalaceByName(palaceName); if (!palace) return evidences; const stars = this.getSanFangSiZhengStars(palace); const starNames = stars.map(s => s.name); const jiCount = stars.filter(s => JI_XING.includes(s.name)).length; const shaCount = stars.filter(s => SHA_XING.includes(s.name)).length; if (jiCount >= 3) { evidences.push({ ruleId: `ZW_STATIC_TOPIC_JI_${tag.toUpperCase()}_v1`, title: `${tag}得力 (三方吉星云集)`, type: 'static', description: `在${tag}领域能获得极大外界助力,事半功倍。`, boardEvidence: [`${palaceName}三方四正汇聚${jiCount}颗吉星`], scoreImpact: 10, tags: [tag], version: this.version }); } if (shaCount >= 3) { evidences.push({ ruleId: `ZW_STATIC_TOPIC_SHA_${tag.toUpperCase()}_v1`, title: `${tag}波折 (三方煞星交冲)`, type: 'static', description: `在${tag}领域阻碍颇多,需付出数倍努力方能有成。`, boardEvidence: [`${palaceName}三方四正逢${shaCount}颗煞星冲破`], scoreImpact: -15, tags: [tag], version: this.version }); } // 特定星曜组合 (举例) if (tag === '财富' && this.containsAll(starNames, ['武曲', '贪狼'])) { evidences.push({ ruleId: `ZW_STATIC_TOPIC_WU_TAN_CAI_v1`, title: `武贪照财帛`, type: 'static', description: `武曲贪狼临财,主晚发,三十岁后财运渐入佳境。`, boardEvidence: [`财帛宫三方见武曲、贪狼`], scoreImpact: 10, tags: [tag], version: this.version }); } return evidences; } // 4. 夹拱对拱特征 private analyzeInteractions(): RuleEvidence[] { const interactions: RuleEvidence[] = []; const mingGong = this.getPalaceByName('命宫'); if (!mingGong) return interactions; const prevIndex = (mingGong.index + 11) % 12; const nextIndex = (mingGong.index + 1) % 12; const prevPalace = this.astrolabe.palaces.find(p => p.index === prevIndex); const nextPalace = this.astrolabe.palaces.find(p => p.index === nextIndex); if (prevPalace && nextPalace) { const prevStars = [...prevPalace.majorStars, ...prevPalace.minorStars].map(s => s.name); const nextStars = [...nextPalace.majorStars, ...nextPalace.minorStars].map(s => s.name); // 双禄夹命 if ( (prevStars.includes('禄存') && nextStars.some(s => this.hasMutagen(nextPalace, '禄'))) || (nextStars.includes('禄存') && prevStars.some(s => this.hasMutagen(prevPalace, '禄'))) ) { interactions.push({ ruleId: 'ZW_STATIC_JIA_SHUANGLU_v1', title: '双禄夹命', type: 'static', description: '生来带有极好的财运与资源背景,左右逢源。', boardEvidence: [`${prevPalace.name}与${nextPalace.name}见禄存与化禄夹命`], scoreImpact: 20, tags: ['财富', '事业'], version: this.version }); } // 羊陀夹命 if ((prevStars.includes('擎羊') && nextStars.includes('陀罗')) || (prevStars.includes('陀罗') && nextStars.includes('擎羊'))) { interactions.push({ ruleId: 'ZW_STATIC_JIA_YANGTUO_v1', title: '羊陀夹命', type: 'static', description: '命局易受环境或他人掣肘,发展常感受限。', boardEvidence: [`${prevPalace.name}与${nextPalace.name}见擎羊与陀罗夹命`], scoreImpact: -10, tags: ['事业', '性格'], version: this.version }); } } return interactions; } // 5. 身命联动 private analyzeBodyMindLink(): RuleEvidence[] { const evidences: RuleEvidence[] = []; const shenGong = this.astrolabe.palaces.find(p => p.name.includes('身宫')); if (shenGong) { const isMingShenSame = shenGong.name.includes('命宫'); if (isMingShenSame) { evidences.push({ ruleId: 'ZW_STATIC_LINK_MINGSHEN_SAME_v1', title: '命身同宫', type: 'static', description: '先天禀赋与后天追求高度一致,性格执着,不易受外界改变。', boardEvidence: ['身宫与命宫同度'], scoreImpact: 0, tags: ['性格'], version: this.version }); } else { const baseName = shenGong.name.replace('(身宫)', '').trim(); evidences.push({ ruleId: `ZW_STATIC_LINK_SHEN_${baseName}_v1`, title: `身入${baseName}`, type: 'static', description: `后天(三十岁后)的发展重心与价值观强烈倾向于${baseName}相关的领域。`, boardEvidence: [`身宫落在${baseName}`], scoreImpact: 0, tags: ['性格', '事业'], version: this.version }); } } return evidences; } // Helper 方法 private getPalaceByName(name: string): PalaceData | undefined { return this.astrolabe.palaces.find(p => p.name.startsWith(name)); } private getSanFangSiZhengStars(palace: PalaceData): StarData[] { const idx = palace.index; const indices = [ idx, (idx + 4) % 12, // 三合1 (idx + 8) % 12, // 三合2 (idx + 6) % 12, // 对宫 ]; const stars: StarData[] = []; indices.forEach(i => { const p = this.astrolabe.palaces.find(p => p.index === i); if (p) { stars.push(...p.majorStars, ...p.minorStars); } }); return stars; } private containsAll(arr: string[], targets: string[]): boolean { return targets.every(t => arr.includes(t)); } private containsAny(arr: string[], targets: string[]): boolean { return targets.some(t => arr.includes(t)); } private hasMutagen(palace: PalaceData, mutagen: string): boolean { return [...palace.majorStars, ...palace.minorStars].some(s => s.mutagen === mutagen); } }