commit 59a5593361646ee7d8bc0e888e854bbbbe54413e Author: 小钰 Date: Mon Aug 3 09:14:12 2026 +0800 feat: 大六壬排盘算法层 v1.0 - ganzhi.ts: 天干地支/五行/藏干/合冲刑害/旬空 - plate.ts: 天地盘排布(月将加时旋转法) - tianjiang.ts: 十二天将(贵人起法/昼夜分/顺逆排布) - sike.ts: 四课算法(天干寄宫→干上神/支上神→四课结构) - sanchuan.ts: 三传算法(九宗门:贼克/比用/涉害/遥克/昴星/别责等) - run-liuren.ts: CLI入口(JSON/文本双格式输出) - duangua-prompt.md: 断课分析提示词 - SKILL.md: 完整文档 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b947077 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..34fe790 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,105 @@ +--- +name: daliuren +description: 大六壬排盘与断课。天盘/四课/三传/十二天将/旬空/神煞,输出JSON+文本+HTML海报。 +--- + +# 大六壬 Skill + +## 何时触发 + +用户场景: +- "帮我起个大六壬课" / "六壬排盘" / "大六壬问事" +- 提供日干支和时辰要求排盘 +- 询问大六壬相关问题 + +**不触发**:单纯的八字/紫微(见 bazi-ziwei)、六爻(见 liuyao-skill)、梅花易数(见 meihua-yishu)。 + +--- + +## 必需输入 + +``` +日干支: 天干+地支(如"甲子") +时辰: 地支时辰(如"子时") +月份: 数字 1-12(用于确定月将) +问事: 事业/财运/感情/健康/出行 等(可选) +``` + +如果用户只给了公历日期,需先换算为干支日(可用万年历或计算工具)。 + +--- + +## 执行流程 + +### Step 0 — 确认信息 + +> "大六壬排盘需要以下信息: +> 1. **日干支** — 如'甲子日'(干支日) +> 2. **时辰** — 如'午时'(地支时辰) +> 3. **月份** — 如'8月'(用于确定月将) +> 4. **问事** — 你想问什么?(可选)" + +### Step 1 — 排盘(算法层) + +```bash +cd calculator +node dist/run-liuren.js --dayStem=甲 --dayBranch=子 --hourBranch=午 --month=8 --question="事业" > liuren.json +node dist/run-liuren.js --dayStem=甲 --dayBranch=子 --hourBranch=午 --month=8 --output=text > liuren.txt +``` + +### Step 2 — 断课分析 + +读取 `prompts/duangua-prompt.md`,喂入 `liuren.txt` + `liuren.json`,输出断课长文。 + +### Step 3 — 海报输出(可选) + +调用渲染脚本生成 HTML 海报。 + +--- + +## 关键约束 + +1. **排盘必须走算法层**:不要徒手算天地盘、四课、三传 +2. **一事一课**:每次只问一件事 +3. **三传是核心**:初传发用→中传过程→末传结果 +4. **旬空要标出**:旬空地支在分析中必须标注 +5. **不替用户做决策**:给信号不给指令 +6. **免责声明**:分析末尾必带 + +--- + +## 文件清单 + +``` +daliuren/ +├── SKILL.md ← 本文件 +├── calculator/ +│ ├── src/ +│ │ ├── ganzhi.ts ← 天干地支/五行/藏干/合冲刑害/旬空 +│ │ ├── plate.ts ← 天地盘排布(月将加时) +│ │ ├── tianjiang.ts ← 十二天将(贵人起法/顺逆排布) +│ │ ├── sike.ts ← 四课算法(干支寄宫/上下神) +│ │ ├── sanchuan.ts ← 三传算法(九宗门:贼克/比用/涉害/遥克/昴星等) +│ │ └── run-liuren.ts ← CLI 入口 +│ ├── package.json +│ └── tsconfig.json +├── prompts/ +│ ├── duangua-prompt.md ← 断课分析提示词 +│ └── duangua-poster.md ← 海报版 JSON 输出提示词 +├── templates/ +│ └── daliuren-poster.html ← 海报 HTML 模板 +└── fixtures/ ← 验证案例 +``` + +--- + +## 报告部署 + +```bash +cp <报告名>.html /root/.openclaw/workspace/reports/daliuren/<报告名>.html +``` +访问地址:`https://report.zhaidk.xyz/daliuren/<报告名>.html` + +--- + +*本分析基于传统大六壬理论框架,仅供文化研究与娱乐参考,不构成任何决策依据。* diff --git a/calculator/package-lock.json b/calculator/package-lock.json new file mode 100644 index 0000000..b6e6462 --- /dev/null +++ b/calculator/package-lock.json @@ -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" + } + } +} diff --git a/calculator/package.json b/calculator/package.json new file mode 100644 index 0000000..9249846 --- /dev/null +++ b/calculator/package.json @@ -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" + } +} diff --git a/calculator/src/ganzhi.ts b/calculator/src/ganzhi.ts new file mode 100644 index 0000000..13a9c69 --- /dev/null +++ b/calculator/src/ganzhi.ts @@ -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 = { + '甲':'木','乙':'木','丙':'火','丁':'火','戊':'土','己':'土','庚':'金','辛':'金','壬':'水','癸':'水' +}; + +// 地支五行 +export const BRANCH_ELEMENT: Record = { + '子':'水','丑':'土','寅':'木','卯':'木','辰':'土','巳':'火','午':'火','未':'土','申':'金','酉':'金','戌':'土','亥':'水' +}; + +// 天干阴阳 +export const STEM_YINYANG: Record = { + '甲':'阳','乙':'阴','丙':'阳','丁':'阴','戊':'阳','己':'阴','庚':'阳','辛':'阴','壬':'阳','癸':'阴' +}; + +// 地支阴阳 +export const BRANCH_YINYANG: Record = { + '子':'阳','丑':'阴','寅':'阳','卯':'阴','辰':'阳','巳':'阴','午':'阳','未':'阴','申':'阳','酉':'阴','戌':'阳','亥':'阴' +}; + +// 地支藏干 +export const BRANCH_HIDDEN_STEMS: Record = { + '子': ['癸'], + '丑': ['己','癸','辛'], + '寅': ['甲','丙','戊'], + '卯': ['乙'], + '辰': ['戊','乙','癸'], + '巳': ['丙','庚','戊'], + '午': ['丁','己'], + '未': ['己','丁','乙'], + '申': ['庚','壬','戊'], + '酉': ['辛'], + '戌': ['戊','辛','丁'], + '亥': ['壬','甲'], +}; + +// 天干合 +export const STEM_HE: Record = { + '甲':'己','乙':'庚','丙':'辛','丁':'壬','戊':'癸', + '己':'甲','庚':'乙','辛':'丙','壬':'丁','癸':'戊' +}; + +// 地支六合 +export const BRANCH_LIUHE: Record = { + '子':'丑','丑':'子','寅':'亥','亥':'寅','卯':'戌','戌':'卯', + '辰':'酉','酉':'辰','巳':'申','申':'巳','午':'未','未':'午' +}; + +// 地支三合 +export const BRANCH_SANHE: Record = { + '申子辰':'水','寅午戌':'火','巳酉丑':'金','亥卯未':'木' +}; + +// 地支六冲 +export const BRANCH_CHONG: Record = { + '子':'午','午':'子','丑':'未','未':'丑','寅':'申','申':'寅', + '卯':'酉','酉':'卯','辰':'戌','戌':'辰','巳':'亥','亥':'巳' +}; + +// 地支六害 +export const BRANCH_HAI: Record = { + '子':'未','未':'子','丑':'午','午':'丑','寅':'巳','巳':'寅', + '卯':'辰','辰':'卯','申':'亥','亥':'申','酉':'戌','戌':'酉' +}; + +// 地支相刑 +export const BRANCH_XING: Record = { + '子':['卯'], '卯':['子'], // 无礼之刑 + '寅':['巳'], '巳':['申'], '申':['寅'], // 无恩之刑 + '丑':['戌'], '戌':['未'], '未':['丑'], // 恃势之刑 + '辰':['辰'], '午':['午'], '酉':['酉'], '亥':['亥'], // 自刑 +}; + +// 五行生克 +export const WUXING_SHENG: Record = { '木':'火','火':'土','土':'金','金':'水','水':'木' }; +export const WUXING_KE: Record = { '木':'土','土':'水','水':'火','火':'金','金':'木' }; + +// 地支索引(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 = { + '春': ['木'], '夏': ['火'], '秋': ['金'], '冬': ['水'], + '四季末': ['土'], // 辰戌丑未月 +}; + +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]; +} diff --git a/calculator/src/plate.ts b/calculator/src/plate.ts new file mode 100644 index 0000000..2346e62 --- /dev/null +++ b/calculator/src/plate.ts @@ -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 = { + '登明': '亥', // 正月 + '河魁': '戌', // 二月 + '从魁': '酉', // 三月 + '传送': '申', // 四月 + '小吉': '未', // 五月 + '胜光': '午', // 六月 + '太乙': '巳', // 七月 + '天罡': '辰', // 八月 + '太冲': '卯', // 九月 + '功曹': '寅', // 十月 + '大吉': '丑', // 十一月 + '神后': '子', // 十二月 +}; + +// 节气→月将映射(简化版:按月份) +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; +} diff --git a/calculator/src/run-liuren.ts b/calculator/src/run-liuren.ts new file mode 100644 index 0000000..c8eb195 --- /dev/null +++ b/calculator/src/run-liuren.ts @@ -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, + 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; +} diff --git a/calculator/src/sanchuan.ts b/calculator/src/sanchuan.ts new file mode 100644 index 0000000..eff1e52 --- /dev/null +++ b/calculator/src/sanchuan.ts @@ -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, + }; +} diff --git a/calculator/src/sike.ts b/calculator/src/sike.ts new file mode 100644 index 0000000..bd543ac --- /dev/null +++ b/calculator/src/sike.ts @@ -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 = { + '甲': '寅', '乙': '辰', '丙': '巳', '丁': '未', '戊': '巳', + '己': '未', '庚': '申', '辛': '戌', '壬': '亥', '癸': '丑', +}; + +// 排四课 +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 = { + '子':'水','丑':'土','寅':'木','卯':'木','辰':'土','巳':'火', + '午':'火','未':'土','申':'金','酉':'金','戌':'土','亥':'水' + }; + return map[branch] || '土'; +} diff --git a/calculator/src/tianjiang.ts b/calculator/src/tianjiang.ts new file mode 100644 index 0000000..2fa84d4 --- /dev/null +++ b/calculator/src/tianjiang.ts @@ -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 = { + '甲': '丑', '乙': '子', '丙': '亥', '丁': '酉', '戊': '丑', + '己': '子', '庚': '丑', '辛': '午', '壬': '卯', '癸': '巳', +}; + +// 日干→阴贵地支 +const YINGUI_MAP: Record = { + '甲': '未', '乙': '申', '丙': '酉', '丁': '亥', '戊': '未', + '己': '申', '庚': '未', '辛': '寅', '壬': '巳', '癸': '卯', +}; + +// 判断昼夜(卯时到酉时为昼,其余为夜) +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 { + const noblemanBranch = getNoblemanBranch(dayStem, hourBranch); + const clockwise = isNoblemanClockwise(noblemanBranch); + + // 找到贵人在天盘上的位置 + const noblemanPos = plate.findIndex(p => p.heavenBranch === noblemanBranch); + + const result = new Map(); + + 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: Branch +): TianJiang | undefined { + return generals.get(branch); +} + +// 格式化天将排布 +export function formatGenerals(generals: Map): 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; +} diff --git a/calculator/tsconfig.json b/calculator/tsconfig.json new file mode 100644 index 0000000..7e44c8e --- /dev/null +++ b/calculator/tsconfig.json @@ -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/**/*"] +} diff --git a/prompts/duangua-prompt.md b/prompts/duangua-prompt.md new file mode 100644 index 0000000..438a1d7 --- /dev/null +++ b/prompts/duangua-prompt.md @@ -0,0 +1,78 @@ +# 大六壬 · 断课分析提示词 + +你是一位精通大六壬的命理分析师。请根据以下排盘结果,进行专业断课分析。 + +## 分析框架 + +### 一、起盘概述 +- 占时四柱(年月日时) +- 月将与昼夜贵人 +- 旬空地支 + +### 二、天地盘分析 +- 天盘旋转后各位置的天盘支与地盘支关系 +- 天盘支代表外在环境、动态变化 +- 地盘支代表内在根基、静态状况 + +### 三、四课分析(核心) +- **第一课(干阳)**:日干寄宫→干上神,代表求测者本人的外在表现 +- **第二课(干阴)**:干上神→干上上神,代表求测者的内在状态 +- **第三课(支阳)**:日支→支上神,代表对方或事情的外在表现 +- **第四课(支阴)**:支上神→支上上神,代表对方或事情的内在状态 +- **干支关系**:干上神与支上神的五行关系 → 判断双方互动 + +### 四、三传分析(关键) +- **初传(发用)**:事情的起因、开始,是关键转折点 +- **中传(过程)**:事情的发展、变化过程 +- **末传(结果)**:事情的最终走向 +- **取传规则**:说明用了哪种九宗门方法,为什么 +- **三传推进**:初→中→末的五行关系链 + +### 五、十二天将分析 +- 贵人所在位置:贵人助力方向 +- 腾蛇:惊恐、怪异 +- 朱雀:文书、口舌 +- 六合:合作、婚姻 +- 勾陈:田土、争斗 +- 青龙:财喜、升迁 +- 天空:虚空、欺骗 +- 白虎:凶险、丧事 +- 太常:饮食、宴会 +- 玄武:盗贼、暗昧 +- 太阴:阴私、暗助 +- 天后:女性、阴事 + +### 六、类神分析 +根据问事类型,选取对应的类神: +- 事业:青龙(财)、贵人(助) +- 感情:六合(婚恋)、天后(女性) +- 财运:青龙(财)、太常(利) +- 健康:白虎(病)、天后(医药) +- 出行:传送(行)、天马(动) +- 官讼:勾陈(讼)、朱雀(文书) + +### 七、反证分析 +- 旬空:事有虚象 +- 休囚:力量不足 +- 冲克:矛盾冲突 +- 白虎临课:有凶险信号 + +### 八、应期分析 +- 初传旺相时应验快 +- 旬空待填实 +- 冲合时机 +- 不给固定日期,给相对条件 + +### 九、综合断语 +- 明确回答用户的问题 +- 给出具体建议 +- 标注置信度 + +## 输出格式 +请以 Markdown 格式输出,结构清晰,语言通俗但不失专业。 + +## 注意事项 +- 大六壬重"课体",需从四课结构中读取信息 +- 三传是事情的主线,重点关注 +- 不替用户做决策,给信号和建议 +- 末尾附免责声明