ziweidoushu / src /core-engine /dynamic-analyzer.ts
luoly2026
Deploy: Fresh initial commit for Hugging Face
631a7d3
Raw
History Blame Contribute Delete
16.3 kB
import { DynamicCore, FlyingFact } from './dynamic-core';
import { AstrolabeData, DynamicChain, DynamicReport, HoroscopeScopeData, MutagenKey, PalaceData, RuleEvidence, TimeLayerData, TimeLayerScope } from './types';
export class DynamicAnalyzer {
private timeLayerData: TimeLayerData;
private astrolabe: AstrolabeData;
private core: DynamicCore;
private engineType: 'qintian' | 'zhuang';
private version = 'dynamic-v2.1.0';
constructor(timeLayerData: TimeLayerData, engineType: 'qintian' | 'zhuang' = 'qintian') {
this.timeLayerData = timeLayerData;
this.astrolabe = timeLayerData.original;
this.core = new DynamicCore(timeLayerData);
this.engineType = engineType;
}
public analyze(): DynamicReport {
const chains = this.getDynamicChains();
return {
laiYinGong: this.getLaiYinGong(),
timeContext: this.getTimeContext(),
chains,
timingHighlights: this.getTimingHighlights(chains),
sihua: {
shengNian: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('original')) || {},
daXian: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('daXian')),
liuNian: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('liuNian')),
liuYue: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('liuYue')),
liuRi: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('liuRi')),
liuShi: this.getSihuaMapFromFacts(this.core.getScopeMutagenFacts('liuShi')),
},
ziHua: this.getZiHua(),
interactions: [
...this.getTimeLayerInteractions(),
...this.getMutagenChainInteractions(chains),
...this.getCrossScopeClashes(),
...this.getJiChongInteractions(),
],
};
}
private getLaiYinGong(): string {
const shengNianGan = this.astrolabe.chineseDate.split(' ')[0][0];
const laiYinPalace = this.astrolabe.palaces.find((palace) => palace.heavenlyStem === shengNianGan);
return laiYinPalace ? this.cleanPalaceName(laiYinPalace.name) : '未知';
}
private getTimeContext(): DynamicReport['timeContext'] {
return {
targetDate: this.timeLayerData.horoscopeMeta?.targetDate,
daXian: this.timeLayerData.daXian
? {
name: this.timeLayerData.daXian.name,
heavenlyStem: this.timeLayerData.daXian.heavenlyStem,
earthlyBranch: this.timeLayerData.daXian.earthlyBranch,
targetPalaceName: this.timeLayerData.daXian.targetPalaceName,
}
: undefined,
liuNian: this.timeLayerData.liuNian
? {
name: this.timeLayerData.liuNian.name,
heavenlyStem: this.timeLayerData.liuNian.heavenlyStem,
earthlyBranch: this.timeLayerData.liuNian.earthlyBranch,
targetPalaceName: this.timeLayerData.liuNian.targetPalaceName,
}
: undefined,
liuYue: this.timeLayerData.liuYue
? {
name: this.timeLayerData.liuYue.name,
heavenlyStem: this.timeLayerData.liuYue.heavenlyStem,
earthlyBranch: this.timeLayerData.liuYue.earthlyBranch,
targetPalaceName: this.timeLayerData.liuYue.targetPalaceName,
}
: undefined,
liuRi: this.timeLayerData.liuRi
? {
name: this.timeLayerData.liuRi.name,
heavenlyStem: this.timeLayerData.liuRi.heavenlyStem,
earthlyBranch: this.timeLayerData.liuRi.earthlyBranch,
targetPalaceName: this.timeLayerData.liuRi.targetPalaceName,
}
: undefined,
liuShi: this.timeLayerData.liuShi
? {
name: this.timeLayerData.liuShi.name,
heavenlyStem: this.timeLayerData.liuShi.heavenlyStem,
earthlyBranch: this.timeLayerData.liuShi.earthlyBranch,
targetPalaceName: this.timeLayerData.liuShi.targetPalaceName,
}
: undefined,
};
}
private getSihuaMapFromFacts(facts: FlyingFact[]): Record<string, string> | undefined {
if (facts.length === 0) {
return undefined;
}
return facts.reduce((result, fact) => {
result[fact.mutagen] = fact.toPalaceName;
return result;
}, {} as Record<string, string>);
}
private getTimeLayerInteractions(): RuleEvidence[] {
const evidences: RuleEvidence[] = [];
if (this.timeLayerData.daXian) {
evidences.push(this.buildTimeLayerEvidence(this.timeLayerData.daXian, '大限'));
}
if (this.timeLayerData.liuNian) {
evidences.push(this.buildTimeLayerEvidence(this.timeLayerData.liuNian, '流年'));
}
if (this.timeLayerData.liuYue) {
evidences.push(this.buildTimeLayerEvidence(this.timeLayerData.liuYue, '流月'));
}
if (this.timeLayerData.liuRi) {
evidences.push(this.buildTimeLayerEvidence(this.timeLayerData.liuRi, '流日'));
}
if (this.timeLayerData.liuShi) {
evidences.push(this.buildTimeLayerEvidence(this.timeLayerData.liuShi, '流时'));
}
return evidences;
}
private buildTimeLayerEvidence(scopeData: HoroscopeScopeData, scopeLabel: string): RuleEvidence {
const mutagenSummary = Object.entries(scopeData.mutagenPalaces)
.map(([mutagen, palaceName]) => `${mutagen}${palaceName}`)
.join('、');
return {
ruleId: `ZW_DYNAMIC_${scopeData.scope.toUpperCase()}_POSITION_v1`,
title: `当前${scopeLabel}${scopeData.name}】落本命${scopeData.targetPalaceName}`,
type: 'dynamic',
description: `${scopeLabel}命宫当前落在本命${scopeData.targetPalaceName},可作为后续应期与飞化链推演的时间层锚点。`,
boardEvidence: [
`${scopeLabel}天干地支为${scopeData.heavenlyStem}${scopeData.earthlyBranch}`,
`${scopeLabel}索引为${scopeData.index},映射本命宫位为${scopeData.targetPalaceName}`,
mutagenSummary ? `${scopeLabel}四化分布:${mutagenSummary}` : `${scopeLabel}四化分布:未取到有效落宫`,
],
scoreImpact: 0,
tags: ['动态', '时间层'],
version: this.version,
};
}
private getZiHua(): RuleEvidence[] {
return this.core.getZiHuaFacts().map((fact) => {
const scoreMap: Record<MutagenKey, number> = { 禄: -5, 权: -5, 科: 5, 忌: -10 };
const descMap: Record<MutagenKey, string> = {
禄: '自化禄,主该宫位的人事物看似美好,但容易流失不长久。',
权: '自化权,主该宫位易起争执,多变动与摩擦。',
科: '自化科,主表面斯文,逢凶化吉。',
忌: '自化忌,主该宫位的人事物易流失或不长久,有消耗之象。',
};
return {
ruleId: `ZW_DYNAMIC_ZIHUA_${fact.mutagen}_v2`,
title: `【${fact.fromPalaceName}】自化${fact.mutagen}`,
type: 'dynamic',
description: descMap[fact.mutagen],
boardEvidence: [`${fact.fromPalaceName}宫干为${fact.sourceStem},使同宫内的${fact.star}${fact.mutagen}`],
scoreImpact: scoreMap[fact.mutagen],
tags: ['动态', '自化'],
version: this.version,
};
});
}
private getDynamicChains(): DynamicChain[] {
const chainConfigs: Array<{ scope: TimeLayerScope; label: string }> = [
{ scope: 'original', label: '本命' },
{ scope: 'daXian', label: '大限' },
{ scope: 'liuNian', label: '流年' },
{ scope: 'liuYue', label: '流月' },
{ scope: 'liuRi', label: '流日' },
{ scope: 'liuShi', label: '流时' },
];
const chains = chainConfigs
.map<DynamicChain | undefined>(({ scope, label }) => {
const steps = this.core.traceMutagenChain(scope, '忌', 3);
if (steps.length === 0) {
return undefined;
}
const impactPalaceName = steps[steps.length - 1].toPalaceName;
const route = steps.map((step) => `${step.fromPalaceName}${step.toPalaceName}`).join(' → ');
return {
scope,
label,
mutagen: '忌' as MutagenKey,
impactPalaceName,
summary: `${label}化忌链由${route},最终落点在【${impactPalaceName}】。`,
steps,
};
});
return chains.filter((chain): chain is DynamicChain => !!chain);
}
private getMutagenChainInteractions(chains: DynamicChain[]): RuleEvidence[] {
return chains.map((chain) => {
const impactIsSelfPalace = this.isWoGong(chain.impactPalaceName);
return {
ruleId: `ZW_DYNAMIC_${chain.scope.toUpperCase()}_TRANSFER_JI_v1`,
title: `${chain.label}转忌链落【${chain.impactPalaceName}】`,
type: 'dynamic',
description: `${chain.summary}${impactIsSelfPalace ? ' 该落点属于我宫,应事更直接。' : ' 该落点偏他宫,多体现为外部人事与环境牵动。'}`,
boardEvidence: chain.steps.map((step, index) => `第${index + 1}跳:${step.fromPalaceName}宫干${step.sourceStem}使${step.star}${step.mutagen}${step.toPalaceName}`),
dynamicEvidence: [`应期层级:${chain.label}`, `最终落点:${chain.impactPalaceName}`],
scoreImpact: impactIsSelfPalace ? -18 : -8,
tags: ['动态', '风险', '转忌链', '时间层'],
version: this.version,
};
});
}
private getCrossScopeClashes(): RuleEvidence[] {
const scopes: Array<{ scope: TimeLayerScope; label: string }> = [
{ scope: 'original', label: '本命' },
{ scope: 'daXian', label: '大限' },
{ scope: 'liuNian', label: '流年' },
{ scope: 'liuYue', label: '流月' },
{ scope: 'liuRi', label: '流日' },
{ scope: 'liuShi', label: '流时' },
];
const scopeFacts = scopes.map((item) => ({ ...item, facts: this.core.getScopeMutagenFacts(item.scope) })).filter((item) => item.facts.length > 0);
const evidences: RuleEvidence[] = [];
const seen = new Set<string>();
for (let i = 0; i < scopeFacts.length; i += 1) {
for (let j = i + 1; j < scopeFacts.length; j += 1) {
const left = scopeFacts[i];
const right = scopeFacts[j];
const rightJi = right.facts.find((fact) => fact.mutagen === '忌');
const leftJi = left.facts.find((fact) => fact.mutagen === '忌');
left.facts
.filter((fact) => fact.mutagen !== '忌' && rightJi && fact.toPalaceName === rightJi.toPalaceName)
.forEach((fact) => {
const key = `${left.scope}-${fact.mutagen}-${right.scope}-忌-${fact.toPalaceName}`;
if (seen.has(key) || !rightJi) {
return;
}
seen.add(key);
evidences.push(this.buildClashEvidence(left.label, fact, right.label, rightJi));
});
right.facts
.filter((fact) => fact.mutagen !== '忌' && leftJi && fact.toPalaceName === leftJi.toPalaceName)
.forEach((fact) => {
const key = `${right.scope}-${fact.mutagen}-${left.scope}-忌-${fact.toPalaceName}`;
if (seen.has(key) || !leftJi) {
return;
}
seen.add(key);
evidences.push(this.buildClashEvidence(right.label, fact, left.label, leftJi));
});
}
}
return evidences;
}
private buildClashEvidence(leftLabel: string, leftFact: FlyingFact, rightLabel: string, rightJi: FlyingFact): RuleEvidence {
const isHeavyImpact = this.isWoGong(leftFact.toPalaceName);
return {
ruleId: `ZW_DYNAMIC_CLASH_${leftLabel}_${rightLabel}_${leftFact.toPalaceName}_v1`,
title: `${leftLabel}${leftFact.mutagen}${rightLabel}忌在【${leftFact.toPalaceName}】交战`,
type: 'dynamic',
description: `${leftLabel}${leftFact.mutagen}${rightLabel}忌同落【${leftFact.toPalaceName}】,形成跨层交战链,主吉象受阻、推进反复。`,
boardEvidence: [
`${leftLabel}${leftFact.mutagen}${leftFact.fromPalaceName}飞入${leftFact.toPalaceName}`,
`${rightLabel}忌由${rightJi.fromPalaceName}飞入${rightJi.toPalaceName}`,
],
conflicts: [`交战宫位:${leftFact.toPalaceName}`, isHeavyImpact ? '该宫为我宫,冲击更直接。' : '该宫偏他宫,更多体现为环境阻滞。'],
scoreImpact: isHeavyImpact ? -22 : -12,
tags: ['动态', '风险', '交战链'],
version: this.version,
};
}
private getJiChongInteractions(): RuleEvidence[] {
const scopes: Array<{ scope: TimeLayerScope; label: string }> = [
{ scope: 'original', label: '本命' },
{ scope: 'daXian', label: '大限' },
{ scope: 'liuNian', label: '流年' },
{ scope: 'liuYue', label: '流月' },
{ scope: 'liuRi', label: '流日' },
{ scope: 'liuShi', label: '流时' },
];
const evidences = scopes.map<RuleEvidence | undefined>(({ scope, label }) => {
const jiFact = this.core.getScopeMutagenFacts(scope).find((fact) => fact.mutagen === '忌');
if (!jiFact) {
return undefined;
}
const jiPalace = this.core.findPalaceByName(jiFact.toPalaceName);
if (!jiPalace) {
return undefined;
}
const oppIndex = (jiPalace.index + 6) % 12;
const oppPalace = this.astrolabe.palaces.find((palace) => palace.index === oppIndex);
if (!oppPalace) {
return undefined;
}
const cleanOppPalaceName = this.cleanPalaceName(oppPalace.name);
const isWoGong = this.isWoGong(cleanOppPalaceName);
let desc = `${label}忌在【${jiFact.toPalaceName}】,冲【${cleanOppPalaceName}】。`;
if (this.engineType === 'qintian') {
desc += isWoGong
? `[钦天门] 冲宫为我宫,破败力更强,应事会直接落在本人核心领域。`
: `[钦天门] 冲宫为他宫,偏向外缘关系与环境消耗。`;
} else {
desc += `[庄氏] 需观察体用关系,当前表现为冲${isWoGong ? '我宫(偏重)' : '他宫(偏外应)'}。`;
}
return {
ruleId: `ZW_DYNAMIC_${scope.toUpperCase()}_JICHONG_v2`,
title: `${label}忌冲【${cleanOppPalaceName}】`,
type: 'dynamic' as const,
description: desc,
boardEvidence: [`${label}忌由${jiFact.fromPalaceName}飞入${jiFact.toPalaceName}`, `对宫为${cleanOppPalaceName}`],
dynamicEvidence: [`应期层级:${label}`],
scoreImpact: isWoGong ? -20 : -10,
tags: ['动态', '风险', '忌冲'],
version: this.version,
};
});
return evidences.filter((item): item is RuleEvidence => !!item);
}
private getTimingHighlights(chains: DynamicChain[]): string[] {
const highlights: string[] = [];
const liuShiChain = chains.find((chain) => chain.scope === 'liuShi');
const liuRiChain = chains.find((chain) => chain.scope === 'liuRi');
const liuYueChain = chains.find((chain) => chain.scope === 'liuYue');
const liuNianChain = chains.find((chain) => chain.scope === 'liuNian');
const daXianChain = chains.find((chain) => chain.scope === 'daXian');
const originalChain = chains.find((chain) => chain.scope === 'original');
if (this.timeLayerData.horoscopeMeta?.targetDate) {
highlights.push(`解析日期锁定为 ${this.timeLayerData.horoscopeMeta.targetDate}`);
}
if (liuShiChain) {
highlights.push(`流时应期优先看【${liuShiChain.impactPalaceName}】`);
}
if (liuRiChain) {
highlights.push(`流日应期优先看【${liuRiChain.impactPalaceName}】`);
}
if (liuYueChain) {
highlights.push(`流月应期优先看【${liuYueChain.impactPalaceName}】`);
}
if (liuNianChain) {
highlights.push(`流年应期优先看【${liuNianChain.impactPalaceName}】`);
}
if (daXianChain) {
highlights.push(`大限背景主轴落在【${daXianChain.impactPalaceName}】`);
}
if (originalChain) {
highlights.push(`本命长期底层风险位在【${originalChain.impactPalaceName}】`);
}
return highlights;
}
private isWoGong(palaceName: string) {
return ['命宫', '财帛', '官禄', '田宅', '疾厄', '福德'].includes(this.cleanPalaceName(palaceName));
}
private cleanPalaceName(name: string) {
return name.split('(')[0];
}
}