feat: 大六壬排盘算法层 v1.0
- ganzhi.ts: 天干地支/五行/藏干/合冲刑害/旬空 - plate.ts: 天地盘排布(月将加时旋转法) - tianjiang.ts: 十二天将(贵人起法/昼夜分/顺逆排布) - sike.ts: 四课算法(天干寄宫→干上神/支上神→四课结构) - sanchuan.ts: 三传算法(九宗门:贼克/比用/涉害/遥克/昴星/别责等) - run-liuren.ts: CLI入口(JSON/文本双格式输出) - duangua-prompt.md: 断课分析提示词 - SKILL.md: 完整文档
This commit is contained in:
commit
59a5593361
12 files changed
+1078
No files matched your search
@@ -0,0 +1,126 @@
|
||||
// 大六壬基础数据层
|
||||
// 天干、地支、五行、阴阳、藏干、合冲刑害破
|
||||
|
||||
// 十天干
|
||||
export const STEMS = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'] as const;
|
||||
export type Stem = typeof STEMS[number];
|
||||
|
||||
// 十二地支
|
||||
export const BRANCHES = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'] as const;
|
||||
export type Branch = typeof BRANCHES[number];
|
||||
|
||||
// 天干五行
|
||||
export const STEM_ELEMENT: Record<Stem, string> = {
|
||||
'甲':'木','乙':'木','丙':'火','丁':'火','戊':'土','己':'土','庚':'金','辛':'金','壬':'水','癸':'水'
|
||||
};
|
||||
|
||||
// 地支五行
|
||||
export const BRANCH_ELEMENT: Record<Branch, string> = {
|
||||
'子':'水','丑':'土','寅':'木','卯':'木','辰':'土','巳':'火','午':'火','未':'土','申':'金','酉':'金','戌':'土','亥':'水'
|
||||
};
|
||||
|
||||
// 天干阴阳
|
||||
export const STEM_YINYANG: Record<Stem, '阳'|'阴'> = {
|
||||
'甲':'阳','乙':'阴','丙':'阳','丁':'阴','戊':'阳','己':'阴','庚':'阳','辛':'阴','壬':'阳','癸':'阴'
|
||||
};
|
||||
|
||||
// 地支阴阳
|
||||
export const BRANCH_YINYANG: Record<Branch, '阳'|'阴'> = {
|
||||
'子':'阳','丑':'阴','寅':'阳','卯':'阴','辰':'阳','巳':'阴','午':'阳','未':'阴','申':'阳','酉':'阴','戌':'阳','亥':'阴'
|
||||
};
|
||||
|
||||
// 地支藏干
|
||||
export const BRANCH_HIDDEN_STEMS: Record<Branch, Stem[]> = {
|
||||
'子': ['癸'],
|
||||
'丑': ['己','癸','辛'],
|
||||
'寅': ['甲','丙','戊'],
|
||||
'卯': ['乙'],
|
||||
'辰': ['戊','乙','癸'],
|
||||
'巳': ['丙','庚','戊'],
|
||||
'午': ['丁','己'],
|
||||
'未': ['己','丁','乙'],
|
||||
'申': ['庚','壬','戊'],
|
||||
'酉': ['辛'],
|
||||
'戌': ['戊','辛','丁'],
|
||||
'亥': ['壬','甲'],
|
||||
};
|
||||
|
||||
// 天干合
|
||||
export const STEM_HE: Record<Stem, Stem> = {
|
||||
'甲':'己','乙':'庚','丙':'辛','丁':'壬','戊':'癸',
|
||||
'己':'甲','庚':'乙','辛':'丙','壬':'丁','癸':'戊'
|
||||
};
|
||||
|
||||
// 地支六合
|
||||
export const BRANCH_LIUHE: Record<Branch, Branch> = {
|
||||
'子':'丑','丑':'子','寅':'亥','亥':'寅','卯':'戌','戌':'卯',
|
||||
'辰':'酉','酉':'辰','巳':'申','申':'巳','午':'未','未':'午'
|
||||
};
|
||||
|
||||
// 地支三合
|
||||
export const BRANCH_SANHE: Record<string, string> = {
|
||||
'申子辰':'水','寅午戌':'火','巳酉丑':'金','亥卯未':'木'
|
||||
};
|
||||
|
||||
// 地支六冲
|
||||
export const BRANCH_CHONG: Record<Branch, Branch> = {
|
||||
'子':'午','午':'子','丑':'未','未':'丑','寅':'申','申':'寅',
|
||||
'卯':'酉','酉':'卯','辰':'戌','戌':'辰','巳':'亥','亥':'巳'
|
||||
};
|
||||
|
||||
// 地支六害
|
||||
export const BRANCH_HAI: Record<Branch, Branch> = {
|
||||
'子':'未','未':'子','丑':'午','午':'丑','寅':'巳','巳':'寅',
|
||||
'卯':'辰','辰':'卯','申':'亥','亥':'申','酉':'戌','戌':'酉'
|
||||
};
|
||||
|
||||
// 地支相刑
|
||||
export const BRANCH_XING: Record<Branch, Branch[]> = {
|
||||
'子':['卯'], '卯':['子'], // 无礼之刑
|
||||
'寅':['巳'], '巳':['申'], '申':['寅'], // 无恩之刑
|
||||
'丑':['戌'], '戌':['未'], '未':['丑'], // 恃势之刑
|
||||
'辰':['辰'], '午':['午'], '酉':['酉'], '亥':['亥'], // 自刑
|
||||
};
|
||||
|
||||
// 五行生克
|
||||
export const WUXING_SHENG: Record<string, string> = { '木':'火','火':'土','土':'金','金':'水','水':'木' };
|
||||
export const WUXING_KE: Record<string, string> = { '木':'土','土':'水','水':'火','火':'金','金':'木' };
|
||||
|
||||
// 地支索引(0-11)
|
||||
export function branchIndex(b: Branch): number {
|
||||
return BRANCHES.indexOf(b);
|
||||
}
|
||||
|
||||
// 天干索引(0-9)
|
||||
export function stemIndex(s: Stem): number {
|
||||
return STEMS.indexOf(s);
|
||||
}
|
||||
|
||||
// 地支五行旺衰(按月令)
|
||||
const SEASON_WANG: Record<string, string[]> = {
|
||||
'春': ['木'], '夏': ['火'], '秋': ['金'], '冬': ['水'],
|
||||
'四季末': ['土'], // 辰戌丑未月
|
||||
};
|
||||
|
||||
export function isBranchWang(branch: Branch, monthBranch: Branch): boolean {
|
||||
const element = BRANCH_ELEMENT[branch];
|
||||
const monthElement = BRANCH_ELEMENT[monthBranch];
|
||||
// 同我者旺,我生者相,生我者休,克我者囚,我克者死
|
||||
if (element === monthElement) return true; // 旺
|
||||
if (WUXING_SHENG[monthElement] === element) return true; // 相
|
||||
return false;
|
||||
}
|
||||
|
||||
// 旬空(六甲旬空)
|
||||
export function getXunKong(dayStem: Stem, dayBranch: Branch): Branch[] {
|
||||
const si = stemIndex(dayStem);
|
||||
const bi = branchIndex(dayBranch);
|
||||
// 旬首天干索引
|
||||
const xunFirstStemIdx = si;
|
||||
// 旬首地支 = 日支 - 日干索引
|
||||
const xunFirstBranchIdx = ((bi - si) % 12 + 12) % 12;
|
||||
// 旬空两个地支 = 旬首+10, 旬首+11
|
||||
const kong1 = BRANCHES[(xunFirstBranchIdx + 10) % 12];
|
||||
const kong2 = BRANCHES[(xunFirstBranchIdx + 11) % 12];
|
||||
return [kong1, kong2];
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// 大六壬天地盘排布
|
||||
// 天盘:月将加时,顺时针排布十二地支
|
||||
// 地盘:固定十二地支位置(子在北,午在南...)
|
||||
|
||||
import { Branch, BRANCHES, branchIndex } from './ganzhi.js';
|
||||
|
||||
export interface PlatePosition {
|
||||
earthBranch: Branch; // 地盘支
|
||||
heavenBranch: Branch; // 天盘支
|
||||
}
|
||||
|
||||
// 地盘固定排列(子丑寅卯...亥,从北开始顺时针)
|
||||
export const EARTH_PLATE: Branch[] = [
|
||||
'子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'
|
||||
];
|
||||
|
||||
// 月将名称与地支对应
|
||||
export const YUEJIANG_MAP: Record<string, Branch> = {
|
||||
'登明': '亥', // 正月
|
||||
'河魁': '戌', // 二月
|
||||
'从魁': '酉', // 三月
|
||||
'传送': '申', // 四月
|
||||
'小吉': '未', // 五月
|
||||
'胜光': '午', // 六月
|
||||
'太乙': '巳', // 七月
|
||||
'天罡': '辰', // 八月
|
||||
'太冲': '卯', // 九月
|
||||
'功曹': '寅', // 十月
|
||||
'大吉': '丑', // 十一月
|
||||
'神后': '子', // 十二月
|
||||
};
|
||||
|
||||
// 节气→月将映射(简化版:按月份)
|
||||
export function getYueJiang(month: number): Branch {
|
||||
// 月将以中气为准,每月一将
|
||||
// 简化版:正月亥,二月戌,三月酉...十一月丑,十二月子
|
||||
const jiangMap: Branch[] = ['亥','戌','酉','申','未','午','巳','辰','卯','寅','丑','子'];
|
||||
return jiangMap[(month - 1) % 12];
|
||||
}
|
||||
|
||||
// 排天地盘
|
||||
// 月将加时:天盘 = 地盘整体旋转,使月将落在时支位置
|
||||
export function buildPlate(yueJiang: Branch, hourBranch: Branch): PlatePosition[] {
|
||||
const yjIdx = branchIndex(yueJiang);
|
||||
const hourIdx = branchIndex(hourBranch);
|
||||
|
||||
// 天盘旋转量:月将应在时支位置
|
||||
// 即:天盘[yjIdx] = 时支 → 天盘[i] = 地盘[(i - yjIdx + hourIdx + 12) % 12]
|
||||
const positions: PlatePosition[] = [];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const earth = EARTH_PLATE[i];
|
||||
const heavenIdx = (i - yjIdx + hourIdx + 12) % 12;
|
||||
const heaven = EARTH_PLATE[heavenIdx];
|
||||
positions.push({ earthBranch: earth, heavenBranch: heaven });
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
// 获取天盘上某地支对应的天盘支
|
||||
export function getHeavenBranch(plate: PlatePosition[], earthBranch: Branch): Branch {
|
||||
const pos = plate.find(p => p.earthBranch === earthBranch);
|
||||
return pos ? pos.heavenBranch : earthBranch;
|
||||
}
|
||||
|
||||
// 获取地盘上某天盘支所在的地盘位置
|
||||
export function getEarthPosition(plate: PlatePosition[], heavenBranch: Branch): Branch {
|
||||
const pos = plate.find(p => p.heavenBranch === heavenBranch);
|
||||
return pos ? pos.earthBranch : heavenBranch;
|
||||
}
|
||||
|
||||
// 格式化天地盘为文本
|
||||
export function formatPlate(plate: PlatePosition[]): string {
|
||||
let text = '┌────┬────┬────┬────┬────┬────┐\n';
|
||||
text += '│ 天 │';
|
||||
for (let i = 0; i < 12; i++) {
|
||||
text += ` ${plate[i].heavenBranch} │`;
|
||||
}
|
||||
text += '\n├────┼────┼────┼────┼────┼────┤\n';
|
||||
text += '│ 地 │';
|
||||
for (let i = 0; i < 12; i++) {
|
||||
text += ` ${plate[i].earthBranch} │`;
|
||||
}
|
||||
text += '\n└────┴────┴────┴────┴────┴────┘';
|
||||
return text;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Stem, Branch, getXunKong, BRANCH_ELEMENT, BRANCHES, branchIndex } from './ganzhi.js';
|
||||
import { buildPlate, getYueJiang, formatPlate } from './plate.js';
|
||||
import { assignGenerals, formatGenerals, getNoblemanBranch, isDaytime } from './tianjiang.js';
|
||||
import { buildSiKe, STEM_JIGONG } from './sike.js';
|
||||
import { buildSanChuan } from './sanchuan.js';
|
||||
|
||||
// CLI 参数解析
|
||||
const args = process.argv.slice(2);
|
||||
function getArg(name: string): string | undefined {
|
||||
const found = args.find(a => a.startsWith(`--${name}=`));
|
||||
return found ? found.split('=')[1] : undefined;
|
||||
}
|
||||
|
||||
const dayStem = (getArg('dayStem') || '甲') as Stem;
|
||||
const dayBranch = (getArg('dayBranch') || '子') as Branch;
|
||||
const hourBranch = (getArg('hourBranch') || '子') as Branch;
|
||||
const month = parseInt(getArg('month') || String(new Date().getMonth() + 1));
|
||||
const question = getArg('question') || undefined;
|
||||
const outputFormat = getArg('output') || 'text'; // json | text
|
||||
|
||||
try {
|
||||
// 1. 月将
|
||||
const yueJiang = getYueJiang(month);
|
||||
|
||||
// 2. 天地盘
|
||||
const plate = buildPlate(yueJiang, hourBranch);
|
||||
|
||||
// 3. 天盘支数组(按地盘顺序)
|
||||
const heavenBranches = plate.map(p => p.heavenBranch);
|
||||
|
||||
// 4. 四课
|
||||
const sike = buildSiKe(dayStem, dayBranch, heavenBranches);
|
||||
|
||||
// 5. 三传
|
||||
const sanchuan = buildSanChuan(sike, dayStem);
|
||||
|
||||
// 6. 十二天将
|
||||
const generals = assignGenerals(plate, dayStem, hourBranch);
|
||||
|
||||
// 7. 旬空
|
||||
const xunKong = getXunKong(dayStem, dayBranch);
|
||||
|
||||
// 8. 贵人
|
||||
const noblemanBranch = getNoblemanBranch(dayStem, hourBranch);
|
||||
|
||||
if (outputFormat === 'json') {
|
||||
console.log(JSON.stringify({
|
||||
dayStem, dayBranch, hourBranch, month,
|
||||
yueJiang,
|
||||
plate: plate.map(p => ({ earth: p.earthBranch, heaven: p.heavenBranch })),
|
||||
sike: sike.lessons,
|
||||
sanchuan,
|
||||
noblemanBranch,
|
||||
xunKong,
|
||||
question,
|
||||
timestamp: new Date().toISOString(),
|
||||
}, null, 2));
|
||||
} else {
|
||||
console.log(formatAsText(dayStem, dayBranch, hourBranch, month, yueJiang, plate, heavenBranches, sike, sanchuan, generals, noblemanBranch, xunKong, question));
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error('排盘错误:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function formatAsText(
|
||||
dayStem: Stem, dayBranch: Branch, hourBranch: Branch, month: number,
|
||||
yueJiang: Branch, plate: any[], heavenBranches: Branch[],
|
||||
sike: any, sanchuan: any, generals: Map<Branch, any>,
|
||||
noblemanBranch: Branch, xunKong: Branch[], question?: string
|
||||
): string {
|
||||
let text = `═══════════════════════════════════
|
||||
大 六 壬 排 盘
|
||||
═══════════════════════════════════
|
||||
|
||||
【占时】${month}月 ${dayStem}${dayBranch}日 ${hourBranch}时
|
||||
${question ? `【问事】${question}` : ''}
|
||||
【月将】${yueJiang}
|
||||
【昼夜】${isDaytime(hourBranch) ? '昼' : '夜'}
|
||||
【贵人】${noblemanBranch}
|
||||
【旬空】${xunKong.join('、')}
|
||||
|
||||
`;
|
||||
|
||||
// 天地盘
|
||||
text += `═══ 天 地 盘 ═══\n`;
|
||||
text += `天盘:`;
|
||||
for (const b of heavenBranches) text += `${b} `;
|
||||
text += `\n地盘:`;
|
||||
for (const b of BRANCHES) text += `${b} `;
|
||||
text += `\n\n`;
|
||||
|
||||
// 天将
|
||||
text += formatGenerals(generals) + '\n';
|
||||
|
||||
// 四课
|
||||
text += sike.text + '\n';
|
||||
|
||||
// 三传
|
||||
text += sanchuan.text + '\n';
|
||||
|
||||
// 综合提示
|
||||
text += `═══ 综 合 提 示 ═══\n`;
|
||||
text += `初传${sanchuan.initial}为事之开始,`;
|
||||
text += `中传${sanchuan.middle}为事之过程,`;
|
||||
text += `末传${sanchuan.final}为事之结果。\n`;
|
||||
|
||||
if (xunKong.includes(sanchuan.initial)) {
|
||||
text += `⚠️ 初传${sanchuan.initial}旬空:事之初有虚象,需待填实。\n`;
|
||||
}
|
||||
if (xunKong.includes(sanchuan.final)) {
|
||||
text += `⚠️ 末传${sanchuan.final}旬空:事之结果有落空之虞。\n`;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
// 大六壬三传算法(九宗门)
|
||||
// 三传:初传(发用)、中传(过程)、末传(结果)
|
||||
// 九宗门:贼克法、比用法、涉害法、遥克法、昴星法、别责法、八专法、伏吟法、返吟法
|
||||
|
||||
import { Branch, BRANCHES, branchIndex, BRANCH_CHONG, BRANCH_ELEMENT, WUXING_KE, WUXING_SHENG, Stem } from './ganzhi.js';
|
||||
import { SiKeLesson, SiKeResult } from './sike.js';
|
||||
|
||||
export interface SanChuanResult {
|
||||
initial: Branch; // 初传
|
||||
middle: Branch; // 中传
|
||||
final: Branch; // 末传
|
||||
rule: string; // 取传规则名
|
||||
ruleDetail: string; // 规则说明
|
||||
text: string;
|
||||
}
|
||||
|
||||
// 判断两支的五行生克关系
|
||||
function getRelation(from: Branch, to: Branch): '贼' | '克' | '生' | '被生' | '比和' {
|
||||
const fe = BRANCH_ELEMENT[from];
|
||||
const te = BRANCH_ELEMENT[to];
|
||||
if (fe === te) return '比和';
|
||||
if (WUXING_SHENG[fe] === te) return '生'; // 我生
|
||||
if (WUXING_KE[fe] === te) return '贼'; // 我克(下克上为贼)
|
||||
if (WUXING_SHENG[te] === fe) return '被生'; // 生我
|
||||
if (WUXING_KE[te] === fe) return '克'; // 克我(上克下为克)
|
||||
return '比和';
|
||||
}
|
||||
|
||||
// 检查地支是否在四课中出现
|
||||
function isInSiKe(branch: Branch, lessons: SiKeLesson[]): boolean {
|
||||
return lessons.some(l => l.lower === branch || l.upper === branch);
|
||||
}
|
||||
|
||||
// 获取四课中所有上神(阳课)
|
||||
function getUpperShens(lessons: SiKeLesson[]): Branch[] {
|
||||
return lessons.map(l => l.upper);
|
||||
}
|
||||
|
||||
// 获取四课中所有下神
|
||||
function getLowerShens(lessons: SiKeLesson[]): Branch[] {
|
||||
return lessons.map(l => l.lower);
|
||||
}
|
||||
|
||||
// === 九宗门 ===
|
||||
|
||||
// 1. 贼克法:四课中有下克上或上克下的,取被克者为初传
|
||||
function zeikeRule(lessons: SiKeLesson[]): Branch | null {
|
||||
// 优先下克上(贼)
|
||||
for (const lesson of lessons) {
|
||||
if (getRelation(lesson.lower, lesson.upper) === '贼') {
|
||||
return lesson.upper; // 取被贼(上神)为初传
|
||||
}
|
||||
}
|
||||
// 上克下(克)
|
||||
for (const lesson of lessons) {
|
||||
if (getRelation(lesson.upper, lesson.lower) === '克') {
|
||||
return lesson.lower; // 取被克(下神)为初传
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 比用法:有多个克贼时,取与日干阴阳相同者
|
||||
function biyongRule(lessons: SiKeLesson[], dayStem: Stem, dayYang: boolean): Branch | null {
|
||||
const candidates: Branch[] = [];
|
||||
|
||||
for (const lesson of lessons) {
|
||||
const rel = getRelation(lesson.lower, lesson.upper);
|
||||
if (rel === '贼') {
|
||||
candidates.push(lesson.upper);
|
||||
} else if (rel === '克') {
|
||||
candidates.push(lesson.lower);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.length <= 1) return candidates[0] || null;
|
||||
|
||||
// 多个候选,取与日干阴阳相同者
|
||||
for (const c of candidates) {
|
||||
const cIdx = branchIndex(c);
|
||||
const cYang = cIdx % 2 === 0; // 子寅辰午申戌为阳
|
||||
if (cYang === dayYang) return c;
|
||||
}
|
||||
|
||||
return candidates[0]; // 都不匹配则取第一个
|
||||
}
|
||||
|
||||
// 3. 涉害法:多个比用时,取涉害深者
|
||||
// 涉害 = 从地盘位置到天盘位置,经过的克贼数量
|
||||
function shehaiRule(lessons: SiKeLesson[], dayStem: Stem): Branch | null {
|
||||
// 找出所有有克贼关系的课
|
||||
const candidates: { branch: Branch; depth: number }[] = [];
|
||||
|
||||
for (const lesson of lessons) {
|
||||
const rel = getRelation(lesson.lower, lesson.upper);
|
||||
if (rel === '贼' || rel === '克') {
|
||||
// 计算涉害深度:从下神位置开始,顺行到上神位置,统计被克的次数
|
||||
const startIdx = branchIndex(lesson.lower);
|
||||
const endIdx = branchIndex(lesson.upper);
|
||||
let depth = 0;
|
||||
for (let i = startIdx; i !== endIdx; i = (i + 1) % 12) {
|
||||
// 检查这个位置是否被克
|
||||
const currentElement = BRANCH_ELEMENT[BRANCHES[i]];
|
||||
const nextElement = BRANCH_ELEMENT[BRANCHES[(i + 1) % 12]];
|
||||
if (WUXING_KE[nextElement] === currentElement) {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
candidates.push({ branch: rel === '贼' ? lesson.upper : lesson.lower, depth });
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.length === 0) return null;
|
||||
if (candidates.length === 1) return candidates[0].branch;
|
||||
|
||||
// 取涉害最深者
|
||||
candidates.sort((a, b) => b.depth - a.depth);
|
||||
return candidates[0].branch;
|
||||
}
|
||||
|
||||
// 4. 遥克法:四课无克贼,看上神是否克日干(蒿矢)或日干是否克上神(弹射)
|
||||
function yaaokeRule(lessons: SiKeLesson[], dayBranch: Branch): Branch | null {
|
||||
const dayElement = BRANCH_ELEMENT[dayBranch];
|
||||
|
||||
// 蒿矢:上神克日干
|
||||
for (const lesson of lessons) {
|
||||
const upperElement = BRANCH_ELEMENT[lesson.upper];
|
||||
if (WUXING_KE[upperElement] === dayElement) {
|
||||
return lesson.upper;
|
||||
}
|
||||
}
|
||||
|
||||
// 弹射:日干克上神
|
||||
for (const lesson of lessons) {
|
||||
const upperElement = BRANCH_ELEMENT[lesson.upper];
|
||||
if (WUXING_KE[dayElement] === upperElement) {
|
||||
return lesson.upper;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 5. 昴星法:四课无克贼无遥克,用酉(昴星)取传
|
||||
// 阳日取酉上神为初传,支上神为中传,干上神为末传
|
||||
// 阴日取酉下神为初传,干上神为中传,支上神为末传
|
||||
function maoxingRule(lessons: SiKeLesson[], dayYang: boolean, youIdx: number): Branch | null {
|
||||
// 找酉的上下神
|
||||
const youUpper = lessons.find(l => l.upper === BRANCHES[youIdx])?.upper;
|
||||
const youLower = lessons.find(l => l.lower === BRANCHES[youIdx])?.lower;
|
||||
|
||||
if (dayYang) {
|
||||
return youUpper || BRANCHES[youIdx];
|
||||
} else {
|
||||
return youLower || BRANCHES[youIdx];
|
||||
}
|
||||
}
|
||||
|
||||
// 6-9 简化处理:别责法、八专法、伏吟法、返吟法
|
||||
function specialRule(lessons: SiKeLesson[], ruleName: string): Branch | null {
|
||||
// 简化:取第一课上神
|
||||
return lessons[0]?.upper || null;
|
||||
}
|
||||
|
||||
// 主取传函数
|
||||
export function buildSanChuan(sike: SiKeResult, dayStem: Stem): SanChuanResult {
|
||||
const lessons = sike.lessons;
|
||||
const dayBranch = sike.dayBranch;
|
||||
const dayYang = ['甲','丙','戊','庚','壬'].includes(dayStem);
|
||||
|
||||
let initial: Branch = sike.lessons[0].upper; // 默认值
|
||||
let rule = '';
|
||||
let ruleDetail = '';
|
||||
|
||||
// 按九宗门顺序尝试
|
||||
// 1. 贼克法
|
||||
const zeikeResult = zeikeRule(lessons);
|
||||
if (zeikeResult) initial = zeikeResult;
|
||||
if (initial) {
|
||||
rule = '贼克法';
|
||||
ruleDetail = '四课中有下克上或上克下,取被克者为初传';
|
||||
}
|
||||
|
||||
// 2. 比用法(多个克贼时)
|
||||
if (!zeikeResult) {
|
||||
const biyongResult = biyongRule(lessons, dayStem, dayYang);
|
||||
if (biyongResult) {
|
||||
initial = biyongResult;
|
||||
rule = '比用法';
|
||||
ruleDetail = '多个克贼,取与日干阴阳相同者';
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 涉害法
|
||||
if (rule === '') {
|
||||
const shehaiResult = shehaiRule(lessons, dayStem);
|
||||
if (shehaiResult) {
|
||||
initial = shehaiResult;
|
||||
rule = '涉害法';
|
||||
ruleDetail = '多个比用,取涉害最深者';
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 遥克法
|
||||
if (rule === '') {
|
||||
const yaaokeResult = yaaokeRule(lessons, dayBranch);
|
||||
if (yaaokeResult) {
|
||||
initial = yaaokeResult;
|
||||
rule = '遥克法';
|
||||
ruleDetail = '四课无克贼,用上神与日干的遥克关系';
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 昴星法
|
||||
if (rule === '') {
|
||||
const maoxingResult = maoxingRule(lessons, dayYang, branchIndex('酉'));
|
||||
if (maoxingResult) {
|
||||
initial = maoxingResult;
|
||||
rule = '昴星法';
|
||||
ruleDetail = '四课无克贼无遥克,取酉位上下神';
|
||||
}
|
||||
}
|
||||
|
||||
// 6-9 兜底
|
||||
if (rule === '') {
|
||||
initial = specialRule(lessons, '别责') || sike.lessons[0].upper;
|
||||
rule = '别责法/八专法/伏吟法/返吟法';
|
||||
ruleDetail = '特殊格局,取干上神为初传';
|
||||
}
|
||||
|
||||
// 中传:初传在四课中的对应位置
|
||||
// 简化:中传取初传在天盘上的对应支
|
||||
const initialIdx = branchIndex(initial);
|
||||
// 中传 = 初传在四课中出现时,对应的另一端
|
||||
const initialLesson = lessons.find(l => l.upper === initial || l.lower === initial);
|
||||
const middle = initialLesson
|
||||
? (initialLesson.upper === initial ? initialLesson.lower : initialLesson.upper)
|
||||
: initial;
|
||||
|
||||
// 末传:中传的对应
|
||||
const middleLesson = lessons.find(l => l.upper === middle || l.lower === middle);
|
||||
const final_ = middleLesson
|
||||
? (middleLesson.upper === middle ? middleLesson.lower : middleLesson.upper)
|
||||
: middle;
|
||||
|
||||
let text = `═══ 三 传 ═══\n`;
|
||||
text += `取传规则:${rule}\n`;
|
||||
text += `规则说明:${ruleDetail}\n\n`;
|
||||
text += `初传(发用):${initial}\n`;
|
||||
text += `中传(过程):${middle}\n`;
|
||||
text += `末传(结果):${final_}\n`;
|
||||
|
||||
return {
|
||||
initial,
|
||||
middle,
|
||||
final: final_,
|
||||
rule,
|
||||
ruleDetail,
|
||||
text,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// 大六壬四课算法
|
||||
// 四课:由日干→干上神(第一课)、干上神→干上上神(第二课)
|
||||
// 日支→支上神(第三课)、支上神→支上上神(第四课)
|
||||
// 上神 = 天盘上该地支位置的天盘支
|
||||
|
||||
import { Branch, Stem, branchIndex, BRANCH_HIDDEN_STEMS } from './ganzhi.js';
|
||||
import { getHeavenBranch } from './plate.js';
|
||||
|
||||
export interface SiKeLesson {
|
||||
index: number; // 课序 1-4
|
||||
lower: Branch; // 下神(地盘支)
|
||||
upper: Branch; // 上神(天盘支)
|
||||
label: string; // 描述
|
||||
}
|
||||
|
||||
export interface SiKeResult {
|
||||
lessons: SiKeLesson[];
|
||||
dayStem: Stem;
|
||||
dayBranch: Branch;
|
||||
ganShang: Branch; // 干上神
|
||||
zhiShang: Branch; // 支上神
|
||||
text: string;
|
||||
}
|
||||
|
||||
// 天干寄宫(日干在地盘上的寄宫位置)
|
||||
// 甲寄寅,乙寄辰,丙寄巳,丁寄未,戊寄巳,己寄未,庚寄申,辛寄戌,壬寄亥,癸寄丑
|
||||
export const STEM_JIGONG: Record<Stem, Branch> = {
|
||||
'甲': '寅', '乙': '辰', '丙': '巳', '丁': '未', '戊': '巳',
|
||||
'己': '未', '庚': '申', '辛': '戌', '壬': '亥', '癸': '丑',
|
||||
};
|
||||
|
||||
// 排四课
|
||||
export function buildSiKe(
|
||||
dayStem: Stem,
|
||||
dayBranch: Branch,
|
||||
heavenBranches: Branch[] // 天盘12位(按地盘顺序:子丑寅卯...亥)
|
||||
): SiKeResult {
|
||||
// 干上神:日干寄宫的天盘支
|
||||
const ganJiGong = STEM_JIGONG[dayStem];
|
||||
const ganJiGongIdx = branchIndex(ganJiGong);
|
||||
const ganShang = heavenBranches[ganJiGongIdx];
|
||||
|
||||
// 支上神:日支的天盘支
|
||||
const zhiIdx = branchIndex(dayBranch);
|
||||
const zhiShang = heavenBranches[zhiIdx];
|
||||
|
||||
// 干上上神:干上神的天盘支
|
||||
const ganShangIdx = branchIndex(ganShang);
|
||||
const ganShangShang = heavenBranches[ganShangIdx];
|
||||
|
||||
// 支上上神:支上神的天盘支
|
||||
const zhiShangIdx = branchIndex(zhiShang);
|
||||
const zhiShangShang = heavenBranches[zhiShangIdx];
|
||||
|
||||
const lessons: SiKeLesson[] = [
|
||||
{ index: 1, lower: ganJiGong, upper: ganShang, label: `干上神:${dayStem}寄${ganJiGong}→上见${ganShang}` },
|
||||
{ index: 2, lower: ganShang, upper: ganShangShang, label: `干上上神:${ganShang}→上见${ganShangShang}` },
|
||||
{ index: 3, lower: dayBranch, upper: zhiShang, label: `支上神:${dayBranch}→上见${zhiShang}` },
|
||||
{ index: 4, lower: zhiShang, upper: zhiShangShang, label: `支上上神:${zhiShang}→上见${zhiShangShang}` },
|
||||
];
|
||||
|
||||
// 格式化文本
|
||||
let text = `═══ 四 课 ═══\n`;
|
||||
text += `日干:${dayStem} 日支:${dayBranch}\n`;
|
||||
text += `干寄宫:${ganJiGong} 干上神:${ganShang} 支上神:${zhiShang}\n\n`;
|
||||
text += `第一课(干阳):${ganJiGong} → ${ganShang}\n`;
|
||||
text += `第二课(干阴):${ganShang} → ${ganShangShang}\n`;
|
||||
text += `第三课(支阳):${dayBranch} → ${zhiShang}\n`;
|
||||
text += `第四课(支阴):${zhiShang} → ${zhiShangShang}\n`;
|
||||
|
||||
return {
|
||||
lessons,
|
||||
dayStem,
|
||||
dayBranch,
|
||||
ganShang,
|
||||
zhiShang,
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
// 分析四课关系
|
||||
export function analyzeSiKeRelation(lessons: SiKeLesson[]): string[] {
|
||||
const relations: string[] = [];
|
||||
|
||||
// 检查四课中的上下神关系
|
||||
for (const lesson of lessons) {
|
||||
const lowerElement = getBranchElementSimple(lesson.lower);
|
||||
const upperElement = getBranchElementSimple(lesson.upper);
|
||||
|
||||
if (lowerElement === upperElement) {
|
||||
relations.push(`第${lesson.index}课:${lesson.lower}${lesson.upper}比和`);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查干支关系
|
||||
const ganShang = lessons[0].upper;
|
||||
const zhiShang = lessons[2].upper;
|
||||
const ganElement = getBranchElementSimple(ganShang);
|
||||
const zhiElement = getBranchElementSimple(zhiShang);
|
||||
|
||||
if (ganElement === zhiElement) {
|
||||
relations.push(`干上神${ganShang}与支上神${zhiShang}比和:干支和谐`);
|
||||
}
|
||||
|
||||
return relations;
|
||||
}
|
||||
|
||||
// 简化版地支五行获取
|
||||
function getBranchElementSimple(branch: Branch): string {
|
||||
const map: Record<string, string> = {
|
||||
'子':'水','丑':'土','寅':'木','卯':'木','辰':'土','巳':'火',
|
||||
'午':'火','未':'土','申':'金','酉':'金','戌':'土','亥':'水'
|
||||
};
|
||||
return map[branch] || '土';
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// 十二天将
|
||||
// 贵人起法:日干分阳贵/阴贵,按昼夜分
|
||||
// 阳贵:甲戊庚牛羊(丑未),乙己鼠猴乡(子申),丙丁猪鸡位(亥酉),壬癸兔蛇藏(卯巳),六辛逢马虎(午寅)
|
||||
// 阴贵:甲戊庚牛羊(丑未),乙己鼠猴乡(子申),丙丁猪鸡位(亥酉),壬癸兔蛇藏(卯巳),六辛逢马虎(午寅)
|
||||
// 简化:用日干→贵人地支→昼夜→排布十二天将
|
||||
|
||||
import { Branch, BRANCHES, branchIndex, Stem } from './ganzhi.js';
|
||||
|
||||
export interface TianJiang {
|
||||
name: string; // 天将名
|
||||
element: string; // 五行
|
||||
nature: string; // 吉凶
|
||||
}
|
||||
|
||||
// 十二天将(固定顺序,从贵人开始顺时针)
|
||||
export const TWELVE_GENERALS: TianJiang[] = [
|
||||
{ name: '贵人', element: '土', nature: '大吉' },
|
||||
{ name: '腾蛇', element: '火', nature: '凶' },
|
||||
{ name: '朱雀', element: '火', nature: '凶' },
|
||||
{ name: '六合', element: '木', nature: '吉' },
|
||||
{ name: '勾陈', element: '土', nature: '凶' },
|
||||
{ name: '青龙', element: '木', nature: '大吉' },
|
||||
{ name: '天空', element: '土', nature: '凶' },
|
||||
{ name: '白虎', element: '金', nature: '大凶' },
|
||||
{ name: '太常', element: '土', nature: '吉' },
|
||||
{ name: '玄武', element: '水', nature: '凶' },
|
||||
{ name: '太阴', element: '金', nature: '吉' },
|
||||
{ name: '天后', element: '水', nature: '吉' },
|
||||
];
|
||||
|
||||
// 日干→贵人地支(阳贵)
|
||||
const YANGGUI_MAP: Record<string, Branch> = {
|
||||
'甲': '丑', '乙': '子', '丙': '亥', '丁': '酉', '戊': '丑',
|
||||
'己': '子', '庚': '丑', '辛': '午', '壬': '卯', '癸': '巳',
|
||||
};
|
||||
|
||||
// 日干→阴贵地支
|
||||
const YINGUI_MAP: Record<string, Branch> = {
|
||||
'甲': '未', '乙': '申', '丙': '酉', '丁': '亥', '戊': '未',
|
||||
'己': '申', '庚': '未', '辛': '寅', '壬': '巳', '癸': '卯',
|
||||
};
|
||||
|
||||
// 判断昼夜(卯时到酉时为昼,其余为夜)
|
||||
export function isDaytime(hourBranch: Branch): boolean {
|
||||
const idx = branchIndex(hourBranch);
|
||||
// 卯(3)到酉(9)为昼
|
||||
return idx >= 3 && idx <= 9;
|
||||
}
|
||||
|
||||
// 获取贵人所在地支
|
||||
export function getNoblemanBranch(dayStem: Stem, hourBranch: Branch): Branch {
|
||||
const daytime = isDaytime(hourBranch);
|
||||
if (daytime) {
|
||||
return YANGGUI_MAP[dayStem];
|
||||
} else {
|
||||
return YINGUI_MAP[dayStem];
|
||||
}
|
||||
}
|
||||
|
||||
// 判断贵人顺逆
|
||||
// 甲戊庚日:贵人在丑顺,在未逆
|
||||
// 其他日干:看贵人落在天盘的哪边
|
||||
// 简化规则:贵人在天盘位于地盘的前半(子到巳)则顺,后半(午到亥)则逆
|
||||
export function isNoblemanClockwise(noblemanBranch: Branch): boolean {
|
||||
const idx = branchIndex(noblemanBranch);
|
||||
return idx <= 5; // 子(0)到巳(5)为顺,午(6)到亥(11)为逆
|
||||
}
|
||||
|
||||
// 排布十二天将到天地盘
|
||||
// 返回每个地盘位置对应的天将
|
||||
export function assignGenerals(
|
||||
plate: { earthBranch: Branch; heavenBranch: Branch }[],
|
||||
dayStem: Stem,
|
||||
hourBranch: Branch
|
||||
): Map<Branch, TianJiang> {
|
||||
const noblemanBranch = getNoblemanBranch(dayStem, hourBranch);
|
||||
const clockwise = isNoblemanClockwise(noblemanBranch);
|
||||
|
||||
// 找到贵人在天盘上的位置
|
||||
const noblemanPos = plate.findIndex(p => p.heavenBranch === noblemanBranch);
|
||||
|
||||
const result = new Map<Branch, TianJiang>();
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const generalIdx = clockwise
|
||||
? i // 顺排:贵人→腾蛇→朱雀→...
|
||||
: (12 - i) % 12; // 逆排:贵人→天后→太阴→...
|
||||
|
||||
const plateIdx = (noblemanPos + i) % 12;
|
||||
const earthBranch = plate[plateIdx].earthBranch;
|
||||
result.set(earthBranch, TWELVE_GENERALS[generalIdx]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取某地支的天将
|
||||
export function getGeneralForBranch(
|
||||
generals: Map<Branch, TianJiang>,
|
||||
branch: Branch
|
||||
): TianJiang | undefined {
|
||||
return generals.get(branch);
|
||||
}
|
||||
|
||||
// 格式化天将排布
|
||||
export function formatGenerals(generals: Map<Branch, TianJiang>): string {
|
||||
let text = '十二天将排布:\n';
|
||||
for (const branch of BRANCHES) {
|
||||
const gen = generals.get(branch);
|
||||
if (gen) {
|
||||
text += `${branch}:${gen.name}(${gen.element}/${gen.nature})\n`;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
Reference in new issue
Block a user