dsh-metaphysics 0.14.3 → 0.16.0

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.
@@ -0,0 +1,133 @@
1
+ // 八字 × 紫微 交叉验证:两套体系各自看同一件事,把「同向 / 有张力 / 只有一边有信号」摆在一起。
2
+ //
3
+ // 注意口径:这不是数学意义上的「一致性检验」,两套体系的取象单位不同(十神 vs 星曜宫位)。
4
+ // 这里只做三件事:把两边对同一维度的说法并列、标出方向、注明各自的依据。
5
+ import { ZIWEI_STARS } from './interpret-data.js';
6
+
7
+ const groupsOf = (bazi) => (bazi && bazi.frame && bazi.frame.godStats && bazi.frame.godStats.groups) || {};
8
+ const topOf = (groups) => Object.entries(groups).sort((a, b) => Number(b[1]) - Number(a[1]))[0] || null;
9
+ const zwPalace = (zw, name) => (zw.palaces || []).find((p) => p.palace === name) || null;
10
+ const zwMain = (p) => (p && p.stars ? p.stars.filter((s) => s.type === '主星').map((s) => s.name) : []);
11
+ const countSha = (p) => (p && p.stars ? p.stars.filter((s) => s.type === '煞星').length : 0);
12
+ const tierOf = (bazi) => {
13
+ const age = Number(bazi.liunian && bazi.liunian[0] ? bazi.liunian[0].age : NaN);
14
+ const list = (bazi.dayun && bazi.dayun.list) || [];
15
+ let cur = null;
16
+ for (const d of list) if (Number.isFinite(age) && Number(d.startAge) <= age) cur = d;
17
+ return cur ? (cur.luck && cur.luck.tier) || '平' : '—';
18
+ };
19
+ const daxianOf = (zw) => {
20
+ const age = Number(zw.liunian && zw.liunian[0] ? zw.liunian[0].age : NaN);
21
+ for (const p of zw.palaces || []) {
22
+ const d = p.daxian || {};
23
+ if (Number.isFinite(age) && Number(d.start) <= age && age <= Number(d.end)) return p;
24
+ }
25
+ return null;
26
+ };
27
+
28
+ /**
29
+ * @param {object} bazi buildBazi 的结果
30
+ * @param {object} zw buildZiwei 的结果
31
+ * @returns {{items: Array<{key:string,label:string,bazi:string,ziwei:string,stance:string,note:string}>}}
32
+ */
33
+ export function crossCheck(bazi, zw) {
34
+ const groups = groupsOf(bazi);
35
+ const top = topOf(groups);
36
+ const items = [];
37
+ const push = (key, label, baziText, ziweiText, stance, note) => items.push({ key, label, bazi: baziText, ziwei: ziweiText, stance, note });
38
+
39
+ // ① 事业:八字看十神里的官杀/食伤,紫微看官禄宫主星
40
+ {
41
+ const career = zwPalace(zw, '官禄');
42
+ const main = zwMain(career);
43
+ const baziStrong = Number(groups['官杀'] || 0) + Number(groups['食伤'] || 0) >= 2;
44
+ const ziweiHas = main.length > 0;
45
+ const stance = baziStrong && ziweiHas ? '同向' : !baziStrong && !ziweiHas ? '同向' : '有张力';
46
+ push('career', '事业主线',
47
+ `${top ? `十神以${top[0]}最重(${top[1]})` : '十神未取到'};官杀+食伤权重 ${(Number(groups['官杀'] || 0) + Number(groups['食伤'] || 0)).toFixed(1)}`,
48
+ main.length ? `官禄宫主星 ${main.join('、')}${ZIWEI_STARS[main[0]] ? `(${ZIWEI_STARS[main[0]].work})` : ''}` : '官禄无正曜',
49
+ stance,
50
+ stance === '同向' ? '两边都指向(或都不强调)事业主线,方向可互参' : '一边强调事业主线、一边信号弱,建议以信号强的一边为主,另一边作补充');
51
+ }
52
+
53
+ // ② 财富:八字看财星权重,紫微看财帛宫主星与煞星
54
+ {
55
+ const wealth = zwPalace(zw, '财帛');
56
+ const main = zwMain(wealth);
57
+ const sha = countSha(wealth);
58
+ const w = Number(groups['财'] || 0);
59
+ const baziStrong = w >= 2;
60
+ const ziweiStrong = main.length > 0;
61
+ const stance = baziStrong && ziweiStrong ? '同向' : !baziStrong && !ziweiStrong ? '同向' : '有张力';
62
+ push('wealth', '财运结构',
63
+ `财星权重 ${w}${baziStrong ? '(偏强)' : '(偏弱)'}`,
64
+ `${main.length ? `财帛主星 ${main.join('、')}` : '财帛无正曜'}${sha ? `;煞星 ${sha} 颗` : ''}`,
65
+ stance,
66
+ '两套体系对「财」的定义不同:八字看十神财星,紫微看财帛宫,只作对照,不作数值合并');
67
+ }
68
+
69
+ // ③ 感情:八字看配偶星,紫微看夫妻宫主星
70
+ {
71
+ const spouse = zwPalace(zw, '夫妻');
72
+ const main = zwMain(spouse);
73
+ const isMale = bazi.input && bazi.input.gender === 'male';
74
+ const key = isMale ? '财' : '官杀';
75
+ const v = Number(groups[key] || 0);
76
+ const baziStrong = v >= 2;
77
+ const ziweiStrong = main.length > 0;
78
+ const stance = baziStrong && ziweiStrong ? '同向' : !baziStrong && !ziweiStrong ? '同向' : '有张力';
79
+ push('love', '感情线索',
80
+ `${isMale ? '妻' : '夫'}星(${key})权重 ${v}${baziStrong ? '(不弱)' : '(偏弱)'}`,
81
+ main.length ? `夫妻宫主星 ${main.join('、')}${ZIWEI_STARS[main[0]] ? `(${ZIWEI_STARS[main[0]].love})` : ''}` : '夫妻宫无正曜',
82
+ stance,
83
+ stance === '同向' ? '两边对感情的强弱判断接近' : '一边说缘分不弱、一边主星信号弱,宜按「多主动创造场景」处理');
84
+ }
85
+
86
+ // ④ 身体:八字看最弱五行,紫微看疾厄宫主星与煞星
87
+ {
88
+ const wx = bazi.wuxing || {};
89
+ const weakest = Object.entries(wx).sort((a, b) => Number(a[1]) - Number(b[1]))[0];
90
+ const health = zwPalace(zw, '疾厄');
91
+ const main = zwMain(health);
92
+ const sha = countSha(health);
93
+ push('health', '身体关注点',
94
+ weakest ? `最弱五行 ${weakest[0]}(${weakest[1]})` : '五行未取到',
95
+ `${main.length ? `疾厄主星 ${main.join('、')}` : '疾厄无正曜'}${sha ? `;煞星 ${sha} 颗` : ''}`,
96
+ '互补',
97
+ '两边指向的器官/系统不一定相同,合并起来看更稳;任何健康问题以体检与医生为准');
98
+ }
99
+
100
+ // ⑤ 节奏:八字当前大运档位 vs 紫微当前大限的煞星密度
101
+ {
102
+ const t = tierOf(bazi);
103
+ const d = daxianOf(zw);
104
+ const sha = d ? countSha(d) : 0;
105
+ const good = ['吉', '大吉'];
106
+ const bad = ['忌', '大忌'];
107
+ const baziGood = good.includes(t);
108
+ const baziBad = bad.includes(t);
109
+ const ziweiHeavy = sha >= 2;
110
+ let stance = '有张力';
111
+ let note = '一边顺、一边压,按「大方向跟顺的一边、具体动作避开压的年份」处理';
112
+ if ((baziGood && !ziweiHeavy) || (baziBad && ziweiHeavy) || (!baziGood && !baziBad && !ziweiHeavy)) {
113
+ stance = '同向';
114
+ note = '两边对当前阶段的松紧判断接近';
115
+ }
116
+ push('rhythm', '当前节奏',
117
+ `大运档位 ${t}`,
118
+ `${d ? `大限在${d.palace}` : '大限未取到'}${sha ? `;煞星 ${sha} 颗` : ';无煞星'}`,
119
+ stance, note);
120
+ }
121
+
122
+ return { items };
123
+ }
124
+
125
+ export default crossCheck;
126
+
127
+ /** 把交叉验证结果拼成可读文本(interpret 的分节与工具输出共用) */
128
+ export function crossText(cross) {
129
+ if (!cross || !Array.isArray(cross.items)) return '';
130
+ return cross.items
131
+ .map((i) => `· ${i.label}:八字——${i.bazi};紫微——${i.ziwei};判断:${i.stance}(${i.note})`)
132
+ .join('\n');
133
+ }