dsh-metaphysics 0.56.0 → 0.58.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.
- package/CHANGELOG.md +103 -1
- package/README.md +26 -9
- package/client.almanac.js +66 -61
- package/client.bazi.js +98 -91
- package/client.chenggu.js +68 -63
- package/client.convert.js +68 -63
- package/client.daliuren.js +104 -97
- package/client.fengshui.js +65 -60
- package/client.hepan.js +99 -92
- package/client.js +392 -267
- package/client.liuyao.js +101 -94
- package/client.mbti.js +66 -61
- package/client.name.js +68 -63
- package/client.numerology.js +66 -61
- package/client.qimen.js +104 -97
- package/client.star.js +66 -61
- package/client.tarot.js +99 -94
- package/client.trend.js +104 -97
- package/client.xiaoliuren.js +66 -61
- package/client.zeri.js +66 -61
- package/client.ziwei.js +98 -91
- package/engine/bridge.js +211 -0
- package/engine/citations.js +603 -320
- package/engine/diff.js +59 -0
- package/engine/fengshui.js +718 -718
- package/engine/geju.js +16 -0
- package/engine/handle.js +192 -0
- package/engine/hepan.js +43 -0
- package/engine/index.js +168 -51
- package/engine/interpret-knowledge.js +3 -2
- package/engine/interpret-plain.js +4 -1
- package/engine/interpret.js +7 -3
- package/engine/qimen-ganying.js +134 -134
- package/engine/qimen-interpret.js +233 -233
- package/engine/revise.js +162 -0
- package/engine/trace.js +493 -456
- package/engine/zeri.js +89 -13
- package/index.js +59 -6
- package/package.json +6 -3
- package//345/221/275/347/220/206/346/216/222/347/233/230.html +3548 -1943
package/engine/trace.js
CHANGED
|
@@ -1,456 +1,493 @@
|
|
|
1
|
-
// A1 推导链:把排盘过程中真正用到的中间层摊开,每层给
|
|
2
|
-
// { field, rule, inputs, result, source }。
|
|
3
|
-
//
|
|
4
|
-
// 只读结果、不重算、不读时间与随机:trace 开着或关掉,盘面必须逐字节一致。
|
|
5
|
-
// 目前覆盖六爻(纳甲→六亲→世应→伏神→旺衰)、八字(旺衰分值、格局取用)、
|
|
6
|
-
// 紫微(格局命中条件)、奇门(盘面事实→用神落宫→门/星/干旺衰→宫位生克)
|
|
7
|
-
// 与大六壬(天地盘→四课→三传);其余体系不产出 trace。
|
|
8
|
-
import { PATTERN_TONE } from './ziwei.js';
|
|
9
|
-
import { yongshenOf, yongshenStrength, fushenAccess } from './liuyao.js';
|
|
10
|
-
import { qimenYongshen } from './qimen-interpret.js';
|
|
11
|
-
import { GAN_JI_GONG } from './daliuren.js';
|
|
12
|
-
|
|
13
|
-
const SYSTEM_LABEL = { liuyao: '六爻', bazi: '八字', ziwei: '紫微', qimen: '奇门', daliuren: '大六壬' };
|
|
14
|
-
|
|
15
|
-
const text = (v, fallback = '—') => {
|
|
16
|
-
if (v === undefined || v === null || v === '') return fallback;
|
|
17
|
-
return String(v);
|
|
18
|
-
};
|
|
19
|
-
const list = (v, fallback = '—') => (Array.isArray(v) ? v.filter((x) => x !== undefined && x !== null && x !== '').join('、') : '') || fallback;
|
|
20
|
-
const pairs = (rows) => rows.map(([label, value]) => ({ label: String(label), value: text(value) }));
|
|
21
|
-
const step = (key, field, rule, inputs, result, source) => ({
|
|
22
|
-
key,
|
|
23
|
-
field,
|
|
24
|
-
rule: text(rule, ''),
|
|
25
|
-
inputs: pairs(inputs),
|
|
26
|
-
result: text(result, ''),
|
|
27
|
-
source: text(source, ''),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
function lineAt(lines, position) {
|
|
31
|
-
return (Array.isArray(lines) ? lines : []).find((l) => l.position === position) || null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function liuyaoTrace(r, opts = {}) {
|
|
35
|
-
const ben = r.ben && typeof r.ben === 'object' ? r.ben : {};
|
|
36
|
-
const lines = Array.isArray(ben.lines) ? ben.lines : [];
|
|
37
|
-
const bian = r.bian && typeof r.bian === 'object' ? r.bian : null;
|
|
38
|
-
const moving = Array.isArray(r.cast && r.cast.movingPositions) ? r.cast.movingPositions : [];
|
|
39
|
-
const ug = r.useGod && typeof r.useGod === 'object' ? r.useGod : null;
|
|
40
|
-
const direction = (ug && ug.direction) || opts.direction || 'general';
|
|
41
|
-
const us = r.useGodStrength && typeof r.useGodStrength === 'object' ? r.useGodStrength : null;
|
|
42
|
-
const hs = r.hexStrength && typeof r.hexStrength === 'object' ? r.hexStrength : null;
|
|
43
|
-
const fa = r.fushenAccess && typeof r.fushenAccess === 'object' ? r.fushenAccess : null;
|
|
44
|
-
const shi = lineAt(lines, ben.shi);
|
|
45
|
-
const ying = lineAt(lines, ben.ying);
|
|
46
|
-
const month = (us && us.month) || (hs && hs.month) || null;
|
|
47
|
-
const day = (us && us.day) || (hs && hs.day) || null;
|
|
48
|
-
|
|
49
|
-
const najia = step(
|
|
50
|
-
'najia',
|
|
51
|
-
'纳甲',
|
|
52
|
-
'京房纳甲:八经卦各配天干与三爻地支,内卦取前三爻、外卦取后三爻;动爻再成变卦。',
|
|
53
|
-
[
|
|
54
|
-
['本卦', `${text(ben.name)}(上${text(ben.upper)}·下${text(ben.lower)})`],
|
|
55
|
-
['动爻', moving.length ? `${moving.join('、')}爻` : '无(静卦)'],
|
|
56
|
-
['变卦', bian ? `${text(bian.name)}(上${text(bian.upper)}·下${text(bian.lower)})` : '无'],
|
|
57
|
-
],
|
|
58
|
-
lines.map((l) => `${l.position}爻 ${text(l.ganzhi)}${text(l.element)}`).join('|'),
|
|
59
|
-
'
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const liuqin = step(
|
|
63
|
-
'liuqin',
|
|
64
|
-
'六亲',
|
|
65
|
-
'以卦宫五行为「我」:同我为兄弟、生我为父母、我生为子孙、克我为官鬼、我克为妻财。',
|
|
66
|
-
[
|
|
67
|
-
['卦宫', `${text(ben.palace)}(${text(ben.palaceElement)})`],
|
|
68
|
-
['爻五行', list([...new Set(lines.map((l) => l.element))])],
|
|
69
|
-
['日干起六神', `${text(r.dayGanZhi && r.dayGanZhi.stem)}日`],
|
|
70
|
-
],
|
|
71
|
-
lines.map((l) => `${l.position}爻 ${text(l.liuqin)}(${text(l.element)})`).join('|'),
|
|
72
|
-
'
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const shiying = step(
|
|
76
|
-
'shiying',
|
|
77
|
-
'世应',
|
|
78
|
-
'八宫首卦世在上爻,一世至五世依次初至五爻,游魂四爻、归魂三爻;应爻与世相隔三位。',
|
|
79
|
-
[
|
|
80
|
-
['卦名', `${text(ben.name)}(${text(ben.palace)})`],
|
|
81
|
-
['世位', `${text(ben.shi)}爻`],
|
|
82
|
-
['应位', `${text(ben.ying)}爻`],
|
|
83
|
-
],
|
|
84
|
-
`${text(ben.shi)}爻${shi ? ` ${text(shi.liuqin)}·${text(shi.ganzhi)}${text(shi.element)}` : ''}为世,`
|
|
85
|
-
+ `${text(ben.ying)}爻${ying ? ` ${text(ying.liuqin)}·${text(ying.ganzhi)}${text(ying.element)}` : ''}为应`,
|
|
86
|
-
'
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
let fushen;
|
|
90
|
-
if (!ug || !ug.liuqin) {
|
|
91
|
-
const why = direction === 'general'
|
|
92
|
-
? '未选询问方向(当前为综合),未取用神'
|
|
93
|
-
: '未取到用神';
|
|
94
|
-
fushen = step(
|
|
95
|
-
'fushen',
|
|
96
|
-
'伏神',
|
|
97
|
-
'用神不上卦时,回本宫首卦的同位取伏神;飞伏之间只判生克与助压。',
|
|
98
|
-
[['用神', ug && ug.ask ? ug.ask : '未取']],
|
|
99
|
-
`${why};本层不适用。`,
|
|
100
|
-
'engine/liuyao.js · yongshenOf()',
|
|
101
|
-
);
|
|
102
|
-
} else if (ug.missing) {
|
|
103
|
-
const hidden = (ug.fushen || []).map((f) => {
|
|
104
|
-
const fei = f.fei ? `${text(f.fei.ganzhi)}${text(f.fei.element)}(${text(f.fei.liuqin)})` : '—';
|
|
105
|
-
return `${f.position}爻 ${text(f.ganzhi)}${text(f.element)}(${text(f.liuqin)}),飞神 ${fei},${text(f.relation)}`;
|
|
106
|
-
}).join(';');
|
|
107
|
-
const access = fa && Array.isArray(fa.items)
|
|
108
|
-
? fa.items.map((i) => `${i.position}爻${text(i.verdict)}`).join('、')
|
|
109
|
-
: '';
|
|
110
|
-
fushen = step(
|
|
111
|
-
'fushen',
|
|
112
|
-
'伏神',
|
|
113
|
-
'用神不上卦时,回本宫首卦的同位取伏神;飞伏之间只判生克,再叠月建日辰给出伏条件,不换算应期。',
|
|
114
|
-
[
|
|
115
|
-
['用神', `${ug.liuqin}(不上卦)`],
|
|
116
|
-
['伏位', list((ug.fushen || []).map((f) => `${f.position}爻`))],
|
|
117
|
-
['月建 / 日辰', `${text(month && month.branch)} / ${text(day && day.branch)}`],
|
|
118
|
-
],
|
|
119
|
-
`${hidden || '本卦无此六亲,首卦同位也未取到伏神'}${access ? `;出伏:${access}` : ''}`,
|
|
120
|
-
'
|
|
121
|
-
);
|
|
122
|
-
} else {
|
|
123
|
-
fushen = step(
|
|
124
|
-
'fushen',
|
|
125
|
-
'伏神',
|
|
126
|
-
'用神已在卦上时不取伏神;伏神层只在本卦找不到用神时启用。',
|
|
127
|
-
[
|
|
128
|
-
['用神', ug.liuqin],
|
|
129
|
-
['在位', list((ug.found || []).map((l) => `${l.position}爻`))],
|
|
130
|
-
],
|
|
131
|
-
`用神 ${ug.liuqin} 已在 ${list((ug.found || []).map((l) => `${l.position}爻`))},无需伏神。`,
|
|
132
|
-
'engine/liuyao.js · yongshenOf()',
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const useStrength = us && Array.isArray(us.lines)
|
|
137
|
-
? us.lines.map((l) => `${l.position}爻${text(l.branch)}${text(l.element)}:月${text(l.monthState)}·${text(l.dayRelation)}`).join(';')
|
|
138
|
-
: '';
|
|
139
|
-
const wangsheng = step(
|
|
140
|
-
'wangsheng',
|
|
141
|
-
'旺衰',
|
|
142
|
-
'月建主这一段的旺衰(旺相休囚死),日辰看当天的生克扶压;只给状态标签,不折分数、不单独断吉凶。',
|
|
143
|
-
[
|
|
144
|
-
['月建', month ? `${text(month.branch)}(${text(month.element)})` : '缺'],
|
|
145
|
-
['日辰', day ? `${text(day.branch)}(${text(day.element)})` : '缺'],
|
|
146
|
-
['用神', ug && ug.liuqin ? ug.liuqin : '未取'],
|
|
147
|
-
['旬空', list(r.xunKong)],
|
|
148
|
-
],
|
|
149
|
-
[
|
|
150
|
-
useStrength ? `用神:${useStrength}${us.labels && us.labels.length ? `(${us.labels.join('、')})` : ''}` : '用神:未取,只看全卦',
|
|
151
|
-
hs && hs.labels && hs.labels.length ? `全卦:${hs.labels.join('、')}` : '',
|
|
152
|
-
].filter(Boolean).join(';'),
|
|
153
|
-
'
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
return [najia, liuqin, shiying, fushen, wangsheng];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function baziTrace(r) {
|
|
160
|
-
const s = r.strength && typeof r.strength === 'object' ? r.strength : {};
|
|
161
|
-
const parts = s.parts && typeof s.parts === 'object' ? s.parts : {};
|
|
162
|
-
const season = parts.season && typeof parts.season === 'object' ? parts.season : {};
|
|
163
|
-
const frame = r.frame && typeof r.frame === 'object' ? r.frame : {};
|
|
164
|
-
const ys = frame.yongshen && typeof frame.yongshen === 'object' ? frame.yongshen : {};
|
|
165
|
-
const primary = frame.primary && typeof frame.primary === 'object' ? frame.primary : null;
|
|
166
|
-
const climate = r.climate && typeof r.climate === 'object' ? r.climate : {};
|
|
167
|
-
const godGroups = frame.godStats && frame.godStats.groups ? frame.godStats.groups : {};
|
|
168
|
-
|
|
169
|
-
const strength = step(
|
|
170
|
-
'strength',
|
|
171
|
-
'旺衰分值',
|
|
172
|
-
text(s.method, '月令权重 + 地支藏干通根 + 天干帮扶,量化后分档。'),
|
|
173
|
-
[
|
|
174
|
-
['日主', r.dayMaster ? `${text(r.dayMaster.stem)}(${text(r.dayMaster.element)})` : '—'],
|
|
175
|
-
['月令', `${text(season.branch)}(${text(season.element)}·${text(season.word)},权重 ${text(season.weight)})`],
|
|
176
|
-
['通根', `${list(parts.roots)}(${text(parts.rootScore)})`],
|
|
177
|
-
['合会折根', list(parts.structure, '无')],
|
|
178
|
-
['天干帮扶 / 耗泄', `帮 ${list(parts.helpers)};泄 ${list(parts.drainers)}(${text(parts.helpScore)})`],
|
|
179
|
-
['虚透', list(parts.virtualHelpers, '无')],
|
|
180
|
-
],
|
|
181
|
-
`${text(s.level)}(${text(s.score)} 分):${text(s.detail)}`,
|
|
182
|
-
'engine/bazi.js ·
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
const primaryName = text(frame.primaryName || (primary && primary.name), '未取格局');
|
|
186
|
-
const extraGeju = list((frame.geju || []).map((g) => g && g.name).filter((name) => name && name !== primaryName), '');
|
|
187
|
-
const favor = list(ys.favor);
|
|
188
|
-
const avoid = list(ys.avoid);
|
|
189
|
-
const disputed = list((ys.disputed || []).map((d) => d && d.element), '');
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
['
|
|
209
|
-
['
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
'
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
['
|
|
226
|
-
['
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
['
|
|
249
|
-
['
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
const
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
'
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
['
|
|
274
|
-
['
|
|
275
|
-
['
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
'
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
['
|
|
293
|
-
['
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
'
|
|
307
|
-
|
|
308
|
-
'
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
['
|
|
313
|
-
['
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
'
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
['
|
|
350
|
-
['
|
|
351
|
-
['
|
|
352
|
-
['
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
'
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
['
|
|
378
|
-
['
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
'
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
['
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
'
|
|
402
|
-
|
|
403
|
-
'
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
['
|
|
408
|
-
['
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
*
|
|
422
|
-
* @
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (result
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
view = { ...result, useGod:
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
else if (result.system === '
|
|
452
|
-
else if (result.system === '
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
1
|
+
// A1 推导链:把排盘过程中真正用到的中间层摊开,每层给
|
|
2
|
+
// { field, rule, inputs, result, source }。
|
|
3
|
+
//
|
|
4
|
+
// 只读结果、不重算、不读时间与随机:trace 开着或关掉,盘面必须逐字节一致。
|
|
5
|
+
// 目前覆盖六爻(纳甲→六亲→世应→伏神→旺衰)、八字(旺衰分值、格局取用)、
|
|
6
|
+
// 紫微(格局命中条件)、奇门(盘面事实→用神落宫→门/星/干旺衰→宫位生克)
|
|
7
|
+
// 与大六壬(天地盘→四课→三传);其余体系不产出 trace。
|
|
8
|
+
import { PATTERN_TONE } from './ziwei.js';
|
|
9
|
+
import { yongshenOf, yongshenStrength, fushenAccess } from './liuyao.js';
|
|
10
|
+
import { qimenYongshen } from './qimen-interpret.js';
|
|
11
|
+
import { GAN_JI_GONG } from './daliuren.js';
|
|
12
|
+
|
|
13
|
+
const SYSTEM_LABEL = { liuyao: '六爻', bazi: '八字', ziwei: '紫微', qimen: '奇门', daliuren: '大六壬' };
|
|
14
|
+
|
|
15
|
+
const text = (v, fallback = '—') => {
|
|
16
|
+
if (v === undefined || v === null || v === '') return fallback;
|
|
17
|
+
return String(v);
|
|
18
|
+
};
|
|
19
|
+
const list = (v, fallback = '—') => (Array.isArray(v) ? v.filter((x) => x !== undefined && x !== null && x !== '').join('、') : '') || fallback;
|
|
20
|
+
const pairs = (rows) => rows.map(([label, value]) => ({ label: String(label), value: text(value) }));
|
|
21
|
+
const step = (key, field, rule, inputs, result, source) => ({
|
|
22
|
+
key,
|
|
23
|
+
field,
|
|
24
|
+
rule: text(rule, ''),
|
|
25
|
+
inputs: pairs(inputs),
|
|
26
|
+
result: text(result, ''),
|
|
27
|
+
source: text(source, ''),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function lineAt(lines, position) {
|
|
31
|
+
return (Array.isArray(lines) ? lines : []).find((l) => l.position === position) || null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function liuyaoTrace(r, opts = {}) {
|
|
35
|
+
const ben = r.ben && typeof r.ben === 'object' ? r.ben : {};
|
|
36
|
+
const lines = Array.isArray(ben.lines) ? ben.lines : [];
|
|
37
|
+
const bian = r.bian && typeof r.bian === 'object' ? r.bian : null;
|
|
38
|
+
const moving = Array.isArray(r.cast && r.cast.movingPositions) ? r.cast.movingPositions : [];
|
|
39
|
+
const ug = r.useGod && typeof r.useGod === 'object' ? r.useGod : null;
|
|
40
|
+
const direction = (ug && ug.direction) || opts.direction || 'general';
|
|
41
|
+
const us = r.useGodStrength && typeof r.useGodStrength === 'object' ? r.useGodStrength : null;
|
|
42
|
+
const hs = r.hexStrength && typeof r.hexStrength === 'object' ? r.hexStrength : null;
|
|
43
|
+
const fa = r.fushenAccess && typeof r.fushenAccess === 'object' ? r.fushenAccess : null;
|
|
44
|
+
const shi = lineAt(lines, ben.shi);
|
|
45
|
+
const ying = lineAt(lines, ben.ying);
|
|
46
|
+
const month = (us && us.month) || (hs && hs.month) || null;
|
|
47
|
+
const day = (us && us.day) || (hs && hs.day) || null;
|
|
48
|
+
|
|
49
|
+
const najia = step(
|
|
50
|
+
'najia',
|
|
51
|
+
'纳甲',
|
|
52
|
+
'京房纳甲:八经卦各配天干与三爻地支,内卦取前三爻、外卦取后三爻;动爻再成变卦。',
|
|
53
|
+
[
|
|
54
|
+
['本卦', `${text(ben.name)}(上${text(ben.upper)}·下${text(ben.lower)})`],
|
|
55
|
+
['动爻', moving.length ? `${moving.join('、')}爻` : '无(静卦)'],
|
|
56
|
+
['变卦', bian ? `${text(bian.name)}(上${text(bian.upper)}·下${text(bian.lower)})` : '无'],
|
|
57
|
+
],
|
|
58
|
+
lines.map((l) => `${l.position}爻 ${text(l.ganzhi)}${text(l.element)}`).join('|'),
|
|
59
|
+
'京房纳甲(八宫纳甲表);实现:engine/liuyao.js · NAJIA(规则表,本仓未录入古籍章页)',
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const liuqin = step(
|
|
63
|
+
'liuqin',
|
|
64
|
+
'六亲',
|
|
65
|
+
'以卦宫五行为「我」:同我为兄弟、生我为父母、我生为子孙、克我为官鬼、我克为妻财。',
|
|
66
|
+
[
|
|
67
|
+
['卦宫', `${text(ben.palace)}(${text(ben.palaceElement)})`],
|
|
68
|
+
['爻五行', list([...new Set(lines.map((l) => l.element))])],
|
|
69
|
+
['日干起六神', `${text(r.dayGanZhi && r.dayGanZhi.stem)}日`],
|
|
70
|
+
],
|
|
71
|
+
lines.map((l) => `${l.position}爻 ${text(l.liuqin)}(${text(l.element)})`).join('|'),
|
|
72
|
+
'五行生克定六亲;取用可对读《增删卜易》卷一·用神章第八;实现:engine/liuyao.js · liuqin()',
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const shiying = step(
|
|
76
|
+
'shiying',
|
|
77
|
+
'世应',
|
|
78
|
+
'八宫首卦世在上爻,一世至五世依次初至五爻,游魂四爻、归魂三爻;应爻与世相隔三位。',
|
|
79
|
+
[
|
|
80
|
+
['卦名', `${text(ben.name)}(${text(ben.palace)})`],
|
|
81
|
+
['世位', `${text(ben.shi)}爻`],
|
|
82
|
+
['应位', `${text(ben.ying)}爻`],
|
|
83
|
+
],
|
|
84
|
+
`${text(ben.shi)}爻${shi ? ` ${text(shi.liuqin)}·${text(shi.ganzhi)}${text(shi.element)}` : ''}为世,`
|
|
85
|
+
+ `${text(ben.ying)}爻${ying ? ` ${text(ying.liuqin)}·${text(ying.ganzhi)}${text(ying.element)}` : ''}为应`,
|
|
86
|
+
'八宫世应诀(世爻序与应爻隔三位);实现:engine/liuyao.js · SHI_POSITION(通行动诀,本仓未录入古籍章页)',
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
let fushen;
|
|
90
|
+
if (!ug || !ug.liuqin) {
|
|
91
|
+
const why = direction === 'general'
|
|
92
|
+
? '未选询问方向(当前为综合),未取用神'
|
|
93
|
+
: '未取到用神';
|
|
94
|
+
fushen = step(
|
|
95
|
+
'fushen',
|
|
96
|
+
'伏神',
|
|
97
|
+
'用神不上卦时,回本宫首卦的同位取伏神;飞伏之间只判生克与助压。',
|
|
98
|
+
[['用神', ug && ug.ask ? ug.ask : '未取']],
|
|
99
|
+
`${why};本层不适用。`,
|
|
100
|
+
'取伏之法参《增删卜易》卷二·飛伏神章第二十八;实现:engine/liuyao.js · yongshenOf()',
|
|
101
|
+
);
|
|
102
|
+
} else if (ug.missing) {
|
|
103
|
+
const hidden = (ug.fushen || []).map((f) => {
|
|
104
|
+
const fei = f.fei ? `${text(f.fei.ganzhi)}${text(f.fei.element)}(${text(f.fei.liuqin)})` : '—';
|
|
105
|
+
return `${f.position}爻 ${text(f.ganzhi)}${text(f.element)}(${text(f.liuqin)}),飞神 ${fei},${text(f.relation)}`;
|
|
106
|
+
}).join(';');
|
|
107
|
+
const access = fa && Array.isArray(fa.items)
|
|
108
|
+
? fa.items.map((i) => `${i.position}爻${text(i.verdict)}`).join('、')
|
|
109
|
+
: '';
|
|
110
|
+
fushen = step(
|
|
111
|
+
'fushen',
|
|
112
|
+
'伏神',
|
|
113
|
+
'用神不上卦时,回本宫首卦的同位取伏神;飞伏之间只判生克,再叠月建日辰给出伏条件,不换算应期。',
|
|
114
|
+
[
|
|
115
|
+
['用神', `${ug.liuqin}(不上卦)`],
|
|
116
|
+
['伏位', list((ug.fushen || []).map((f) => `${f.position}爻`))],
|
|
117
|
+
['月建 / 日辰', `${text(month && month.branch)} / ${text(day && day.branch)}`],
|
|
118
|
+
],
|
|
119
|
+
`${hidden || '本卦无此六亲,首卦同位也未取到伏神'}${access ? `;出伏:${access}` : ''}`,
|
|
120
|
+
'《增删卜易》卷二·飛伏神章第二十八(用神不現,尋得伏神而遇生扶有用);实现:engine/liuyao.js · fushenAccess()',
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
fushen = step(
|
|
124
|
+
'fushen',
|
|
125
|
+
'伏神',
|
|
126
|
+
'用神已在卦上时不取伏神;伏神层只在本卦找不到用神时启用。',
|
|
127
|
+
[
|
|
128
|
+
['用神', ug.liuqin],
|
|
129
|
+
['在位', list((ug.found || []).map((l) => `${l.position}爻`))],
|
|
130
|
+
],
|
|
131
|
+
`用神 ${ug.liuqin} 已在 ${list((ug.found || []).map((l) => `${l.position}爻`))},无需伏神。`,
|
|
132
|
+
'取伏之法参《增删卜易》卷二·飛伏神章第二十八;实现:engine/liuyao.js · yongshenOf()',
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const useStrength = us && Array.isArray(us.lines)
|
|
137
|
+
? us.lines.map((l) => `${l.position}爻${text(l.branch)}${text(l.element)}:月${text(l.monthState)}·${text(l.dayRelation)}`).join(';')
|
|
138
|
+
: '';
|
|
139
|
+
const wangsheng = step(
|
|
140
|
+
'wangsheng',
|
|
141
|
+
'旺衰',
|
|
142
|
+
'月建主这一段的旺衰(旺相休囚死),日辰看当天的生克扶压;只给状态标签,不折分数、不单独断吉凶。',
|
|
143
|
+
[
|
|
144
|
+
['月建', month ? `${text(month.branch)}(${text(month.element)})` : '缺'],
|
|
145
|
+
['日辰', day ? `${text(day.branch)}(${text(day.element)})` : '缺'],
|
|
146
|
+
['用神', ug && ug.liuqin ? ug.liuqin : '未取'],
|
|
147
|
+
['旬空', list(r.xunKong)],
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
useStrength ? `用神:${useStrength}${us.labels && us.labels.length ? `(${us.labels.join('、')})` : ''}` : '用神:未取,只看全卦',
|
|
151
|
+
hs && hs.labels && hs.labels.length ? `全卦:${hs.labels.join('、')}` : '',
|
|
152
|
+
].filter(Boolean).join(';'),
|
|
153
|
+
'《增删卜易》卷一·月將章第十六、日辰章第十七;实现:engine/liuyao.js · yongshenStrength / hexagramStrength',
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
return [najia, liuqin, shiying, fushen, wangsheng];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function baziTrace(r) {
|
|
160
|
+
const s = r.strength && typeof r.strength === 'object' ? r.strength : {};
|
|
161
|
+
const parts = s.parts && typeof s.parts === 'object' ? s.parts : {};
|
|
162
|
+
const season = parts.season && typeof parts.season === 'object' ? parts.season : {};
|
|
163
|
+
const frame = r.frame && typeof r.frame === 'object' ? r.frame : {};
|
|
164
|
+
const ys = frame.yongshen && typeof frame.yongshen === 'object' ? frame.yongshen : {};
|
|
165
|
+
const primary = frame.primary && typeof frame.primary === 'object' ? frame.primary : null;
|
|
166
|
+
const climate = r.climate && typeof r.climate === 'object' ? r.climate : {};
|
|
167
|
+
const godGroups = frame.godStats && frame.godStats.groups ? frame.godStats.groups : {};
|
|
168
|
+
|
|
169
|
+
const strength = step(
|
|
170
|
+
'strength',
|
|
171
|
+
'旺衰分值',
|
|
172
|
+
text(s.method, '月令权重 + 地支藏干通根 + 天干帮扶,量化后分档。'),
|
|
173
|
+
[
|
|
174
|
+
['日主', r.dayMaster ? `${text(r.dayMaster.stem)}(${text(r.dayMaster.element)})` : '—'],
|
|
175
|
+
['月令', `${text(season.branch)}(${text(season.element)}·${text(season.word)},权重 ${text(season.weight)})`],
|
|
176
|
+
['通根', `${list(parts.roots)}(${text(parts.rootScore)})`],
|
|
177
|
+
['合会折根', list(parts.structure, '无')],
|
|
178
|
+
['天干帮扶 / 耗泄', `帮 ${list(parts.helpers)};泄 ${list(parts.drainers)}(${text(parts.helpScore)})`],
|
|
179
|
+
['虚透', list(parts.virtualHelpers, '无')],
|
|
180
|
+
],
|
|
181
|
+
`${text(s.level)}(${text(s.score)} 分):${text(s.detail)}`,
|
|
182
|
+
'本仓量化规则(月令权重 3/2/1/0.5/0、藏干通根、三会/三合/六合折根、虚透减半;非古籍定数);实现:engine/bazi.js · 旺衰量化',
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const primaryName = text(frame.primaryName || (primary && primary.name), '未取格局');
|
|
186
|
+
const extraGeju = list((frame.geju || []).map((g) => g && g.name).filter((name) => name && name !== primaryName), '');
|
|
187
|
+
const favor = list(ys.favor);
|
|
188
|
+
const avoid = list(ys.avoid);
|
|
189
|
+
const disputed = list((ys.disputed || []).map((d) => d && d.element), '');
|
|
190
|
+
const neutral = list((ys.neutral || []).map((n) => (n ? `${n.element}(${n.weight} 分)` : '')), '');
|
|
191
|
+
const tiaohou = ys.tiaohou && typeof ys.tiaohou === 'object' ? ys.tiaohou : climate;
|
|
192
|
+
const need = tiaohou && tiaohou.need ? tiaohou.need : null;
|
|
193
|
+
const resultParts = [
|
|
194
|
+
primaryName === '未取格局' ? primaryName : `主格 ${primaryName}${extraGeju ? `;兼格 ${extraGeju}` : ''}`,
|
|
195
|
+
`喜 ${favor},忌 ${avoid}`,
|
|
196
|
+
neutral ? `中性偏忌 ${neutral}(近零,仍按忌参与行运评分)` : '',
|
|
197
|
+
disputed ? `有争议 ${disputed}` : '',
|
|
198
|
+
tiaohou && tiaohou.kind
|
|
199
|
+
? `调候 ${text(tiaohou.kind)}${need && need.element ? `,取 ${text(need.element)}` : ''}${tiaohou.avoidElement && tiaohou.avoidElement !== '—' ? `,忌 ${text(tiaohou.avoidElement)}` : ''}`
|
|
200
|
+
: '',
|
|
201
|
+
].filter(Boolean).join(';');
|
|
202
|
+
|
|
203
|
+
const geju = step(
|
|
204
|
+
'geju',
|
|
205
|
+
'格局取用',
|
|
206
|
+
text(ys.method, '先按月令与透干取格,再以扶抑为主、调候校验取用。'),
|
|
207
|
+
[
|
|
208
|
+
['月令格', primary ? `${text(primary.name)}(${text(primary.kind)})` : '—'],
|
|
209
|
+
['取格依据', primary ? text(primary.evidence) : '—'],
|
|
210
|
+
['十神分量', Object.entries(godGroups).map(([k, v]) => `${k}${v}`).join(' / ') || '—'],
|
|
211
|
+
['调候', tiaohou && tiaohou.kind ? `${text(tiaohou.kind)}${need && need.element ? ` → ${text(need.element)}` : ''}` : '—'],
|
|
212
|
+
],
|
|
213
|
+
`${resultParts}`,
|
|
214
|
+
'《子平真诠》八、论用神(专求月令);调候参《穷通宝鉴》五行总论;实现:engine/geju.js · yongshenOf()',
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const p = r.palaces && typeof r.palaces === 'object' ? r.palaces : {};
|
|
218
|
+
const monthBranch = r.pillars && r.pillars.month ? text(r.pillars.month.branch) : '—';
|
|
219
|
+
const hourBranch = r.pillars && r.pillars.hour ? text(r.pillars.hour.branch) : '—';
|
|
220
|
+
const palaces = p.taiyuan ? step(
|
|
221
|
+
'palaces',
|
|
222
|
+
'胎元与命身宫',
|
|
223
|
+
'胎元=月干进一、月支进三;胎息=日干五合、日支六合;命宫=27 减生月与生时支、取模后加二;身宫=11 加两支、取模后加二;干支并入六十甲子。',
|
|
224
|
+
[
|
|
225
|
+
['生月 / 生时', `${monthBranch} / ${hourBranch}`],
|
|
226
|
+
['胎元', `${text(p.taiyuan.ganzhi)}(月干进一、月支进三)`],
|
|
227
|
+
['胎息', p.taixi ? `${text(p.taixi.ganzhi)}(日干五合、日支六合)` : '—'],
|
|
228
|
+
['命宫 / 身宫', `${text(p.minggong && p.minggong.ganzhi)} / ${text(p.shengong && p.shengong.ganzhi)}`],
|
|
229
|
+
],
|
|
230
|
+
`胎元 ${text(p.taiyuan.ganzhi)};${p.taixi ? `胎息 ${text(p.taixi.ganzhi)};` : ''}命宫 ${text(p.minggong && p.minggong.ganzhi)};身宫 ${text(p.shengong && p.shengong.ganzhi)}。四宫是辅助坐标,不单独折吉凶。`,
|
|
231
|
+
'Tyme 1.5.4 四宫口径(与 ziwei.pub 704 组日期对拍);本仓未直接照录古籍章页;实现:engine/bazi.js · palaces',
|
|
232
|
+
) : null;
|
|
233
|
+
|
|
234
|
+
return [strength, geju, ...(palaces ? [palaces] : [])];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function ziweiTrace(r) {
|
|
238
|
+
const patterns = Array.isArray(r.patterns) ? r.patterns : [];
|
|
239
|
+
const total = Object.keys(PATTERN_TONE).length;
|
|
240
|
+
const soul = r.soul && typeof r.soul === 'object' ? r.soul : {};
|
|
241
|
+
const bureau = r.bureau && typeof r.bureau === 'object' ? r.bureau : {};
|
|
242
|
+
const hit = patterns.map((p) => `${text(p.name)}:${text(p.evidence)}`).join(';');
|
|
243
|
+
return [step(
|
|
244
|
+
'patterns',
|
|
245
|
+
'格局命中条件',
|
|
246
|
+
`已收录 ${total} 条格局,逐条校验命宫三方四正的星曜组合;只判结构成立与否,不折吉凶。`,
|
|
247
|
+
[
|
|
248
|
+
['命宫', text(soul.ganzhi)],
|
|
249
|
+
['五行局', text(bureau.name)],
|
|
250
|
+
['命主 / 身主', `${text(r.lifeMaster)} / ${text(r.bodyMaster)}`],
|
|
251
|
+
['命中数', `${patterns.length} / ${total}`],
|
|
252
|
+
],
|
|
253
|
+
patterns.length ? `命中 ${patterns.length} 条:${hit}` : '未命中已收录的格局条件(不表示命盘无结构,只是不在已收录清单内)。',
|
|
254
|
+
'《紫微斗数全书》卷三·论人命入格、谈星要论;实现:engine/ziwei.js · detectPatterns()',
|
|
255
|
+
)];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function qimenTrace(r, opts = {}) {
|
|
259
|
+
const palaces = Array.isArray(r.palaces) ? r.palaces : [];
|
|
260
|
+
const month = r.month && typeof r.month === 'object' ? r.month : {};
|
|
261
|
+
const states = r.states && typeof r.states === 'object' ? r.states : {};
|
|
262
|
+
const cond = r.conditions && typeof r.conditions === 'object' ? r.conditions : {};
|
|
263
|
+
const zf = r.zhiFu && typeof r.zhiFu === 'object' ? r.zhiFu : {};
|
|
264
|
+
const zs = r.zhiShi && typeof r.zhiShi === 'object' ? r.zhiShi : {};
|
|
265
|
+
const ma = r.ma && typeof r.ma === 'object' ? r.ma : {};
|
|
266
|
+
const sz = r.siZhu && typeof r.siZhu === 'object' ? r.siZhu : {};
|
|
267
|
+
|
|
268
|
+
const facts = step(
|
|
269
|
+
'facts',
|
|
270
|
+
'盘面事实',
|
|
271
|
+
'时家转盘奇门:节气与三元定阴阳遁与局数,旬首定值符星与值使门;值符随时干落宫,八神按阴阳遁顺布或逆布。',
|
|
272
|
+
[
|
|
273
|
+
['四柱', `${text(sz.year)} ${text(sz.month)} ${text(sz.day)} ${text(sz.time)}`],
|
|
274
|
+
['节气 / 局', `${text(r.jieqi)} · ${text(r.dun)}${text(r.juNumber)}局(${text(r.juMethod)})`],
|
|
275
|
+
['旬首', text(r.xunshou)],
|
|
276
|
+
['值符 / 值使', `${text(zf.star)}落${text(zf.gong)}宫 / ${text(zs.gate)}落${text(zs.gong)}宫`],
|
|
277
|
+
['空亡 / 驿马', `${list(r.kongWang)} / ${text(ma.zhi)}${ma.gong ? `(${ma.gong}宫)` : ''}`],
|
|
278
|
+
],
|
|
279
|
+
palaces.map((p) => `${p.palace}宫 天${text(p.tianPan)}·${text(p.star)}·${text(p.gate)}·${text(p.god)}`).join('|') || '无九宫数据',
|
|
280
|
+
'《奇门遁甲统宗》卷一·奇门秘诀总赋(阴阳二遁、五日换元、超神接气);实现:engine/qimen.js · buildQimen()',
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const ys = qimenYongshen(r, opts.direction);
|
|
284
|
+
const found = ys.rows.filter((x) => x.palace);
|
|
285
|
+
const missing = ys.rows.filter((x) => !x.palace).map((x) => x.key);
|
|
286
|
+
const primary = found[0] || null;
|
|
287
|
+
const yongshen = step(
|
|
288
|
+
'yongshen',
|
|
289
|
+
'用神落宫',
|
|
290
|
+
'按所问之事取用神:先取主用神、再取辅用神;以所落之宫的干、门、星、神整体取象,不单凭门名断事。',
|
|
291
|
+
[
|
|
292
|
+
['询问方向', ys.label],
|
|
293
|
+
['主用神', primary ? `${primary.key} → ${primary.palace.palace}宫` : '未上盘'],
|
|
294
|
+
['辅用神', found.slice(1).map((x) => `${x.key} → ${x.palace.palace}宫`).join(';') || '无'],
|
|
295
|
+
['主用神落宫', primary ? `${text(primary.palace.star)}·${text(primary.palace.gate)}·${text(primary.palace.god)}·天盘${text(primary.palace.tianPan)}` : '—'],
|
|
296
|
+
],
|
|
297
|
+
found.length
|
|
298
|
+
? `${ys.note};${found.map((x) => `${x.key} 落 ${x.palace.palace}宫(${text(x.palace.star)}·${text(x.palace.gate)}·${text(x.palace.god)})`).join(',')}`
|
|
299
|
+
+ (missing.length ? `;${missing.join('、')} 未上盘` : '')
|
|
300
|
+
: `${ys.label}的用神均未上盘,属未决项;先按值符落宫参照。`,
|
|
301
|
+
'本仓用神表(按所问之事取用,非古籍原文);实现:engine/qimen-interpret.js · qimenYongshen()',
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const order = ['旺', '相', '休', '囚', '死'];
|
|
305
|
+
const stateLine = (g) => order.filter((k) => g && Array.isArray(g[k]) && g[k].length)
|
|
306
|
+
.map((k) => `${k} ${g[k].join('、')}`).join(';') || '—';
|
|
307
|
+
const wangshuai = step(
|
|
308
|
+
'states',
|
|
309
|
+
'门/星/干旺衰',
|
|
310
|
+
'月令定五态:同月令之气为旺,月令所生为相,生月令为休,克月令为囚,月令所克为死;只判力量强弱,不合吉凶。',
|
|
311
|
+
[
|
|
312
|
+
['月令', `${text(month.branch)}(${text(month.element)})`],
|
|
313
|
+
['门', stateLine(states.gate)],
|
|
314
|
+
['星', stateLine(states.star)],
|
|
315
|
+
['天盘干', stateLine(states.stem)],
|
|
316
|
+
],
|
|
317
|
+
`门:${stateLine(states.gate)};星:${stateLine(states.star)};天盘干:${stateLine(states.stem)}`,
|
|
318
|
+
'《奇门遁甲统宗》卷三(旺相休囚);实现:engine/qimen.js · groupByState()',
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
const forced = [];
|
|
322
|
+
const controlled = [];
|
|
323
|
+
const stemGroups = new Map();
|
|
324
|
+
for (const p of palaces) {
|
|
325
|
+
const rel = p.gateRelation || {};
|
|
326
|
+
if (rel.type === '门迫') forced.push(`${p.palace}宫${text(p.gate)}`);
|
|
327
|
+
else if (rel.type === '宫制门') controlled.push(`${p.palace}宫${text(p.gate)}`);
|
|
328
|
+
const sr = p.stemRelation || {};
|
|
329
|
+
if (p.tianPan && sr.type && sr.type !== 'unknown') {
|
|
330
|
+
if (!stemGroups.has(sr.type)) stemGroups.set(sr.type, []);
|
|
331
|
+
stemGroups.get(sr.type).push(`${p.palace}宫${p.tianPan}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const stemOrder = ['干克宫', '宫克干', '干生宫', '宫生干', '比和'];
|
|
335
|
+
const stemLine = stemOrder.filter((k) => stemGroups.has(k))
|
|
336
|
+
.map((k) => `${k} ${stemGroups.get(k).join('、')}`).join(';') || '—';
|
|
337
|
+
const jiXing = (cond.jiXing || []).map((x) => `${x.palace}宫${text(x.stem)}`);
|
|
338
|
+
const ruMu = (cond.ruMu || []).map((x) => `${x.palace}宫${text(x.stem)}`);
|
|
339
|
+
const liuYiRuMu = (cond.liuYiRuMu || []).map((x) => `${x.palace}宫${text(x.stem)}`);
|
|
340
|
+
const ganying = palaces.filter((p) => p.ganYing)
|
|
341
|
+
.map((p) => `${p.palace}宫 ${text(p.ganYing.tian)}加${text(p.ganYing.di)} ${text(p.ganYing.name)}`).join(';');
|
|
342
|
+
const kongCells = palaces.filter((p) => p.kong).map((p) => `${p.palace}宫`);
|
|
343
|
+
|
|
344
|
+
const relations = step(
|
|
345
|
+
'relations',
|
|
346
|
+
'宫位生克',
|
|
347
|
+
'门与宫同宫论生克:门克宫为门迫,宫克门为宫制门;天盘干对宫另论生克;击刑、入墓、空亡只作宫位条件,不单独断吉凶。',
|
|
348
|
+
[
|
|
349
|
+
['门迫', forced.join('、') || '无'],
|
|
350
|
+
['宫制门', controlled.join('、') || '无'],
|
|
351
|
+
['天盘干 × 宫', stemLine],
|
|
352
|
+
['击刑 / 三奇入墓 / 六仪入墓', `${jiXing.join('、') || '无'} / ${ruMu.join('、') || '无'} / ${liuYiRuMu.join('、') || '无'}`],
|
|
353
|
+
['十干克应', ganying || '—'],
|
|
354
|
+
['空亡', kongCells.join('、') || '无'],
|
|
355
|
+
],
|
|
356
|
+
`门迫 ${forced.length} 处、宫制门 ${controlled.length} 处;天盘干与宫:${stemLine};击刑 ${jiXing.length} 处、三奇入墓 ${ruMu.length} 处、六仪入墓 ${liuYiRuMu.length} 处、落空 ${kongCells.length} 宫。十干克应:${ganying || '—'}。`,
|
|
357
|
+
'《奇门遁甲统宗》卷二(八门迫制)、卷十一·玄机赋(中)(六仪击刑、三奇入墓);十干克应为本仓表;实现:engine/qimen.js · gatePalaceRelation() / stemPalaceRelation()、engine/qimen-ganying.js',
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
return [facts, yongshen, wangshuai, relations];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function daliurenTrace(r) {
|
|
364
|
+
const pan = Array.isArray(r.pan) ? r.pan : [];
|
|
365
|
+
const ke = Array.isArray(r.siKe) ? r.siKe : [];
|
|
366
|
+
const sc = r.sanChuan && typeof r.sanChuan === 'object' ? r.sanChuan : {};
|
|
367
|
+
const yj = r.yueJiang && typeof r.yueJiang === 'object' ? r.yueJiang : {};
|
|
368
|
+
const gr = r.guiren && typeof r.guiren === 'object' ? r.guiren : {};
|
|
369
|
+
const geju = r.geJu && typeof r.geJu === 'object' ? r.geJu : {};
|
|
370
|
+
const dayGz = text(r.dayGanZhi, '');
|
|
371
|
+
|
|
372
|
+
const tiandipan = step(
|
|
373
|
+
'tiandipan',
|
|
374
|
+
'天地盘',
|
|
375
|
+
'月将加时:中气换将,月将加于占时之上,顺布十二支成天盘;十二天将以日干昼夜贵人为起点,阳顺阴逆布于天盘。',
|
|
376
|
+
[
|
|
377
|
+
['日干支', dayGz],
|
|
378
|
+
['时支', `${text(r.hourZhi)}时`],
|
|
379
|
+
['月将', `${text(yj.zhi)}(${text(yj.name)})`],
|
|
380
|
+
['昼夜 / 贵人', `${text(r.dayNight)} / ${text(gr.zhi)}(${gr.reverse ? '逆布' : '顺布'})`],
|
|
381
|
+
],
|
|
382
|
+
pan.map((p) => `${p.di}→${p.tian}${p.jiang ? `(${text(p.jiang)})` : ''}`).join('|') || '无天地盘数据',
|
|
383
|
+
'《大六壬大全》卷二·神将释(月将为十二支神,登明为首逆布);加时布盘属通行口诀,未标卷次;实现:engine/daliuren.js · tianDiPan()',
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const sike = step(
|
|
387
|
+
'sike',
|
|
388
|
+
'四课',
|
|
389
|
+
'四课:日干寄宫取第一课,日干上神再取第二课;日支取第三课,日支上神再取第四课;每课以上下五行论生克。',
|
|
390
|
+
[
|
|
391
|
+
['日干 / 日支', `${text(dayGz[0])} / ${text(dayGz[1])}`],
|
|
392
|
+
['日干寄宫', text(GAN_JI_GONG[dayGz[0]])],
|
|
393
|
+
['四课', ke.map((k) => `${k.position}课 ${text(k.shang)}上${text(k.xia)}下`).join(';') || '—'],
|
|
394
|
+
],
|
|
395
|
+
ke.map((k) => `${k.position}课 ${text(k.shang)}上${text(k.xia)}下${k.jiang ? `·${text(k.jiang)}` : ''}:${text(k.relation)}`).join(';') || '无四课数据',
|
|
396
|
+
'《大六壬大全》卷一·起例(十干寄宫);四课余下三课按通行口诀;实现:engine/daliuren.js · siKe()',
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const chuanLine = (c) => (c
|
|
400
|
+
? `${text(c.position)}${text(c.zhi)}(${text(c.liuQin)}${c.xunKong ? '·旬空' : ''},${text(c.jiang)}${c.jiangFull ? `·${text(c.jiangFull)}` : ''})`
|
|
401
|
+
: '—');
|
|
402
|
+
const sanchuan = step(
|
|
403
|
+
'sanchuan',
|
|
404
|
+
'三传',
|
|
405
|
+
'三传:先取贼克(下贼上优先),无则比用、涉害、遥克、昴星,再八专、伏吟、返吟;初传既定,中末以天盘依次递取。',
|
|
406
|
+
[
|
|
407
|
+
['课体', `${text(geju.name)}(${text(geju.detail)})`],
|
|
408
|
+
['初传', chuanLine(sc.chu)],
|
|
409
|
+
['中传', chuanLine(sc.zhong)],
|
|
410
|
+
['末传', chuanLine(sc.mo)],
|
|
411
|
+
],
|
|
412
|
+
`${chuanLine(sc.chu)} → ${chuanLine(sc.zhong)} → ${chuanLine(sc.mo)}`,
|
|
413
|
+
'《大六壬大全》卷一·起例(贼克法为首法,比用、涉害、遥克、昴星、八专、伏吟、返吟依次列后);实现:engine/daliuren.js · chuan()',
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
return [tiandipan, sike, sanchuan];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @param {object} result compute 的结果
|
|
422
|
+
* @param {{direction?:string, gender?:string, refresh?:boolean}} [opts]
|
|
423
|
+
* refresh=true 时按当前询问方向重算六爻的用神 / 旺衰 / 伏神层(只重建 trace,不改盘面)
|
|
424
|
+
* @returns {Array<{key:string, field:string, rule:string, inputs:Array<{label:string,value:string}>, result:string, source:string}>|null}
|
|
425
|
+
*/
|
|
426
|
+
export function buildTrace(result, opts = {}) {
|
|
427
|
+
if (!result || typeof result !== 'object') return null;
|
|
428
|
+
let layers = null;
|
|
429
|
+
if (result.system === 'liuyao') {
|
|
430
|
+
let view = result;
|
|
431
|
+
// 面板改了「询问方向」但不想重摇一卦:只按新方向重算用神相关三层
|
|
432
|
+
if (opts.refresh === true) {
|
|
433
|
+
try {
|
|
434
|
+
const ug = yongshenOf(result, { direction: opts.direction, gender: opts.gender });
|
|
435
|
+
const monthBranch = (result.hexStrength && result.hexStrength.month && result.hexStrength.month.branch)
|
|
436
|
+
|| (result.useGodStrength && result.useGodStrength.month && result.useGodStrength.month.branch)
|
|
437
|
+
|| null;
|
|
438
|
+
const dayBranch = result.dayGanZhi ? result.dayGanZhi.branch : null;
|
|
439
|
+
if (ug.liuqin) {
|
|
440
|
+
const us = yongshenStrength(result, ug, { monthBranch, dayBranch });
|
|
441
|
+
const fa = fushenAccess(result, ug, { monthBranch, dayBranch });
|
|
442
|
+
view = { ...result, useGod: ug, useGodStrength: us || undefined, fushenAccess: fa || undefined };
|
|
443
|
+
} else {
|
|
444
|
+
view = { ...result, useGod: undefined, useGodStrength: undefined, fushenAccess: undefined };
|
|
445
|
+
}
|
|
446
|
+
} catch (e) {
|
|
447
|
+
view = result;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
layers = liuyaoTrace(view, opts);
|
|
451
|
+
} else if (result.system === 'bazi') layers = baziTrace(result);
|
|
452
|
+
else if (result.system === 'ziwei') layers = ziweiTrace(result);
|
|
453
|
+
else if (result.system === 'qimen') layers = qimenTrace(result, opts);
|
|
454
|
+
else if (result.system === 'daliuren') layers = daliurenTrace(result);
|
|
455
|
+
return layers && layers.length ? layers : null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* A5 推导链导出:把同一份 layers 渲染成 Markdown,供贴进对话、文档或 issue。
|
|
460
|
+
* 只做排版,不重算、不补字段——导出前后内容必须与 buildTrace 一致。
|
|
461
|
+
* 表格里的 | 与换行必须转义,否则一格写坏整张表。
|
|
462
|
+
*/
|
|
463
|
+
const mdCell = (v) => String(v === undefined || v === null ? '' : v)
|
|
464
|
+
.replace(/\\/g, '\\\\')
|
|
465
|
+
.replace(/\|/g, '\\|')
|
|
466
|
+
.replace(/\r?\n/g, '<br>');
|
|
467
|
+
|
|
468
|
+
export function traceMarkdown(layers, opts = {}) {
|
|
469
|
+
if (!Array.isArray(layers) || !layers.length) return '';
|
|
470
|
+
const system = opts.system || '';
|
|
471
|
+
const sys = SYSTEM_LABEL[system] || '命盘';
|
|
472
|
+
const out = [
|
|
473
|
+
`# 推导链 · ${sys}`,
|
|
474
|
+
'',
|
|
475
|
+
`> ${layers.length} 层;每层给出规则、输入、结果与出处。只读推导,不重算、不改盘面。`,
|
|
476
|
+
];
|
|
477
|
+
layers.forEach((t, i) => {
|
|
478
|
+
if (!t) return;
|
|
479
|
+
out.push('', `## ${i + 1}. ${t.field || '(未命名字段)'}`, '');
|
|
480
|
+
if (t.result) out.push(`**结果**:${t.result}`, '');
|
|
481
|
+
if (t.rule) out.push(`**规则**:${t.rule}`, '');
|
|
482
|
+
const inputs = Array.isArray(t.inputs) ? t.inputs : [];
|
|
483
|
+
if (inputs.length) {
|
|
484
|
+
out.push('| 项 | 值 |', '| --- | --- |');
|
|
485
|
+
for (const x of inputs) out.push(`| ${mdCell(x && x.label)} | ${mdCell(x && x.value)} |`);
|
|
486
|
+
out.push('');
|
|
487
|
+
}
|
|
488
|
+
if (t.source) out.push(`**出处**:${t.source}`, '');
|
|
489
|
+
});
|
|
490
|
+
return `${out.join('\n').trimEnd()}\n`;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export { SYSTEM_LABEL };
|