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:
小钰 committed 2026-08-03 09:14:12 +08:00
commit 59a5593361
12 files changed
+1078

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
{
"name": "daliuren-calculator",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "daliuren-calculator",
"version": "1.0.0",
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.3.0"
}
},
"node_modules/@types/node": {
"version": "22.20.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
"integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
}
}
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "daliuren-calculator",
"version": "1.0.0",
"description": "大六壬排盘算法层",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/run-liuren.js"
},
"devDependencies": {
"typescript": "^5.3.0",
"@types/node": "^22.0.0"
}
}
+126
View File
@@ -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];
}
+85
View File
@@ -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;
}
+116
View File
@@ -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;
}
+261
View File
@@ -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,
};
}
+115
View File
@@ -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] || '土';
}
+115
View File
@@ -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;
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"declaration": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}