UNPKG

yijing-bazi-mcp

Version:

易经八字分析 MCP 服务器 - 提供传统命理分析和易经卦象解读的AI工具

1,294 lines (1,131 loc) 41.1 kB
/** * 八字计算工具 * 用于八字的排盘和计算 */ const Logger = require('./logger.js'); const DateUtils = require('./date-utils.js'); class BaziCalculator { constructor() { this.logger = new Logger(); this.dateUtils = new DateUtils(); // 初始化BaziDatabase以支持getTenGod方法 const BaziDatabase = require('../data/bazi-database.js'); this.baziDB = new BaziDatabase(); // 天干 this.heavenlyStems = [ '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸' ]; // 地支 this.earthlyBranches = [ '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥' ]; // 五行属性 this.stemElements = { '甲': '木', '乙': '木', '丙': '火', '丁': '火', '戊': '土', '己': '土', '庚': '金', '辛': '金', '壬': '水', '癸': '水' }; this.branchElements = { '子': '水', '丑': '土', '寅': '木', '卯': '木', '辰': '土', '巳': '火', '午': '火', '未': '土', '申': '金', '酉': '金', '戌': '土', '亥': '水' }; // 阴阳属性 this.stemPolarity = { '甲': '阳', '乙': '阴', '丙': '阳', '丁': '阴', '戊': '阳', '己': '阴', '庚': '阳', '辛': '阴', '壬': '阳', '癸': '阴' }; this.branchPolarity = { '子': '阳', '丑': '阴', '寅': '阳', '卯': '阴', '辰': '阳', '巳': '阴', '午': '阳', '未': '阴', '申': '阳', '酉': '阴', '戌': '阳', '亥': '阴' }; // 十神关系 this.tenGods = { '比肩': '同我', '劫财': '同我', '食神': '我生', '伤官': '我生', '偏财': '我克', '正财': '我克', '七杀': '克我', '正官': '克我', '偏印': '生我', '正印': '生我' }; } /** * 计算八字 * @param {string} birthDate - 出生日期 (YYYY-MM-DD) * @param {string} birthTime - 出生时间 (HH:mm) * @param {string} timezone - 时区 * @param {string} gender - 性别 (male/female) * @param {boolean} isLunar - 是否农历 * @returns {Object} 八字数据 */ calculateBazi(birthDate, birthTime, timezone = 'Asia/Shanghai', gender = 'male', isLunar = false) { this.logger.info('开始计算八字', { birthDate, birthTime, timezone, gender, isLunar }); try { // 转换为公历日期时间 const solarDateTime = isLunar ? this.dateUtils.lunarToSolar(birthDate, birthTime) : new Date(`${birthDate}T${birthTime}:00`); // 计算年柱 const yearPillar = this.calculateYearPillar(solarDateTime); // 计算月柱 const monthPillar = this.calculateMonthPillar(solarDateTime, yearPillar.stem); // 计算日柱 const dayPillar = this.calculateDayPillar(solarDateTime); // 计算时柱 const hourPillar = this.calculateHourPillar(solarDateTime, dayPillar.stem); // 计算大运 const majorLuck = this.calculateMajorLuck(yearPillar, monthPillar, gender, solarDateTime); // 计算流年 const annualLuck = this.calculateAnnualLuck(solarDateTime); // 分析五行强弱 const elementAnalysis = this.analyzeElements([yearPillar, monthPillar, dayPillar, hourPillar]); // 分析十神关系 const tenGodsAnalysis = this.analyzeTenGods(dayPillar.stem, [yearPillar, monthPillar, dayPillar, hourPillar]); // 分析格局 const patternAnalysis = this.analyzePattern([yearPillar, monthPillar, dayPillar, hourPillar], elementAnalysis); const bazi = { birth_info: { solar_date: solarDateTime.toISOString().split('T')[0], solar_time: solarDateTime.toTimeString().split(' ')[0].substring(0, 5), lunar_date: isLunar ? birthDate : this.dateUtils.solarToLunar(solarDateTime), timezone: timezone, gender: gender, is_lunar: isLunar }, four_pillars: { year: yearPillar, month: monthPillar, day: dayPillar, hour: hourPillar }, major_luck: majorLuck, annual_luck: annualLuck, element_analysis: elementAnalysis, ten_gods_analysis: tenGodsAnalysis, pattern_analysis: patternAnalysis, timestamp: new Date().toISOString() }; this.logger.info('八字计算完成', { bazi }); return bazi; } catch (error) { this.logger.error('八字计算失败', { error: error.message, birthDate, birthTime }); throw error; } } /** * 计算年柱 * @param {Date} date - 日期 * @returns {Object} 年柱 */ calculateYearPillar(date) { // 立春为年的分界点 const year = date.getFullYear(); const springStart = this.getSpringStart(year); let actualYear = year; if (date < springStart) { actualYear = year - 1; } // 计算干支 // 甲子年为1984年,每60年一个循环 const baseYear = 1984; const yearOffset = (actualYear - baseYear) % 60; const stemIndex = yearOffset % 10; const branchIndex = yearOffset % 12; const stem = this.heavenlyStems[stemIndex < 0 ? stemIndex + 10 : stemIndex]; const branch = this.earthlyBranches[branchIndex < 0 ? branchIndex + 12 : branchIndex]; return { stem: stem, branch: branch, element: this.stemElements[stem], polarity: this.stemPolarity[stem], branch_element: this.branchElements[branch], branch_polarity: this.branchPolarity[branch], year: actualYear }; } /** * 计算月柱 * @param {Date} date - 日期 * @param {string} yearStem - 年干 * @returns {Object} 月柱 */ calculateMonthPillar(date, yearStem) { const month = date.getMonth() + 1; const day = date.getDate(); // 确定节气月份 const solarMonth = this.getSolarMonth(month, day); // 月支固定:寅月(立春)、卯月(惊蛰)、辰月(清明)... const monthBranches = ['寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥', '子', '丑']; const branchIndex = (solarMonth - 1) % 12; const branch = monthBranches[branchIndex]; // 月干根据年干推算 const yearStemIndex = this.heavenlyStems.indexOf(yearStem); const monthStemIndex = (yearStemIndex * 2 + solarMonth - 1) % 10; const stem = this.heavenlyStems[monthStemIndex]; return { stem: stem, branch: branch, element: this.stemElements[stem], polarity: this.stemPolarity[stem], branch_element: this.branchElements[branch], branch_polarity: this.branchPolarity[branch], solar_month: solarMonth }; } /** * 计算日柱 * @param {Date} date - 日期 * @returns {Object} 日柱 */ calculateDayPillar(date) { // 使用儒略日计算 const julianDay = this.getJulianDay(date); // 甲子日的儒略日为1924681(1900年1月1日) const baseJulianDay = 1924681; const dayOffset = (julianDay - baseJulianDay) % 60; const stemIndex = dayOffset % 10; const branchIndex = dayOffset % 12; const stem = this.heavenlyStems[stemIndex < 0 ? stemIndex + 10 : stemIndex]; const branch = this.earthlyBranches[branchIndex < 0 ? branchIndex + 12 : branchIndex]; return { stem: stem, branch: branch, element: this.stemElements[stem], polarity: this.stemPolarity[stem], branch_element: this.branchElements[branch], branch_polarity: this.branchPolarity[branch], julian_day: julianDay }; } /** * 计算时柱 * @param {Date} date - 日期 * @param {string} dayStem - 日干 * @returns {Object} 时柱 */ calculateHourPillar(date, dayStem) { const hour = date.getHours(); // 确定时辰 const hourBranches = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; let hourIndex; if (hour >= 23 || hour < 1) hourIndex = 0; // 子时 23:00-01:00 else if (hour >= 1 && hour < 3) hourIndex = 1; // 丑时 01:00-03:00 else if (hour >= 3 && hour < 5) hourIndex = 2; // 寅时 03:00-05:00 else if (hour >= 5 && hour < 7) hourIndex = 3; // 卯时 05:00-07:00 else if (hour >= 7 && hour < 9) hourIndex = 4; // 辰时 07:00-09:00 else if (hour >= 9 && hour < 11) hourIndex = 5; // 巳时 09:00-11:00 else if (hour >= 11 && hour < 13) hourIndex = 6; // 午时 11:00-13:00 else if (hour >= 13 && hour < 15) hourIndex = 7; // 未时 13:00-15:00 else if (hour >= 15 && hour < 17) hourIndex = 8; // 申时 15:00-17:00 else if (hour >= 17 && hour < 19) hourIndex = 9; // 酉时 17:00-19:00 else if (hour >= 19 && hour < 21) hourIndex = 10; // 戌时 19:00-21:00 else hourIndex = 11; // 亥时 21:00-23:00 const branch = hourBranches[hourIndex]; // 时干根据日干推算 const dayStemIndex = this.heavenlyStems.indexOf(dayStem); const hourStemIndex = (dayStemIndex * 2 + hourIndex) % 10; const stem = this.heavenlyStems[hourStemIndex]; return { stem: stem, branch: branch, element: this.stemElements[stem], polarity: this.stemPolarity[stem], branch_element: this.branchElements[branch], branch_polarity: this.branchPolarity[branch], hour_index: hourIndex, hour_range: this.getHourRange(hourIndex) }; } /** * 计算大运 * @param {Object} yearPillar - 年柱 * @param {Object} monthPillar - 月柱 * @param {string} gender - 性别 * @param {Date} birthDate - 出生日期 * @returns {Object} 大运信息 */ calculateMajorLuck(yearPillar, monthPillar, gender, birthDate) { // 判断顺逆 const yearStemIndex = this.heavenlyStems.indexOf(yearPillar.stem); const isYangYear = yearStemIndex % 2 === 0; const isMale = gender === 'male'; // 阳年男命、阴年女命顺行,阴年男命、阳年女命逆行 const isForward = (isYangYear && isMale) || (!isYangYear && !isMale); // 计算起运年龄(简化计算) const startAge = this.calculateLuckStartAge(birthDate, monthPillar, isForward); // 生成大运 const majorLuckPeriods = []; const monthStemIndex = this.heavenlyStems.indexOf(monthPillar.stem); const monthBranchIndex = this.earthlyBranches.indexOf(monthPillar.branch); for (let i = 0; i < 8; i++) { const ageStart = startAge + i * 10; const ageEnd = ageStart + 9; let stemIndex, branchIndex; if (isForward) { stemIndex = (monthStemIndex + i + 1) % 10; branchIndex = (monthBranchIndex + i + 1) % 12; } else { stemIndex = (monthStemIndex - i - 1 + 10) % 10; branchIndex = (monthBranchIndex - i - 1 + 12) % 12; } const stem = this.heavenlyStems[stemIndex]; const branch = this.earthlyBranches[branchIndex]; majorLuckPeriods.push({ period: i + 1, age_start: ageStart, age_end: ageEnd, stem: stem, branch: branch, element: this.stemElements[stem], branch_element: this.branchElements[branch] }); } return { is_forward: isForward, start_age: startAge, periods: majorLuckPeriods }; } /** * 获取天干对应的五行 * @param {string} gan - 天干 * @returns {string} 五行 */ getGanElement(gan) { return this.stemElements[gan] || '未知'; } /** * 获取天干的阴阳属性 * @param {string} gan - 天干 * @returns {string} 阴阳属性 */ getGanYinYang(gan) { return this.stemPolarity[gan] || '未知'; } /** * 生成大运序列 * @param {Object} monthPillar - 月柱 * @param {boolean} isForward - 是否顺行 * @param {number} startAge - 起运年龄 * @returns {Array} 大运序列 */ generateMajorLuckSequence(monthPillar, isForward, startAge) { const sequence = []; let currentGan = monthPillar.heavenly_stem; let currentZhi = monthPillar.earthly_branch; for (let i = 0; i < 8; i++) { const age = startAge + i * 10; if (isForward) { currentGan = this.getNextGan(currentGan); currentZhi = this.getNextZhi(currentZhi); } else { currentGan = this.getPrevGan(currentGan); currentZhi = this.getPrevZhi(currentZhi); } sequence.push({ period: i + 1, age_range: `${age}-${age + 9}`, gan: currentGan, zhi: currentZhi, gan_zhi: currentGan + currentZhi, element: this.getGanElement(currentGan), yin_yang: this.getGanYinYang(currentGan) }); } return sequence; } /** * 获取下一个天干 * @param {string} gan - 当前天干 * @returns {string} 下一个天干 */ getNextGan(gan) { const gans = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; const index = gans.indexOf(gan); return gans[(index + 1) % 10]; } /** * 获取上一个天干 * @param {string} gan - 当前天干 * @returns {string} 上一个天干 */ getPrevGan(gan) { const gans = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; const index = gans.indexOf(gan); return gans[(index - 1 + 10) % 10]; } /** * 获取下一个地支 * @param {string} zhi - 当前地支 * @returns {string} 下一个地支 */ getNextZhi(zhi) { const zhis = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; const index = zhis.indexOf(zhi); return zhis[(index + 1) % 12]; } /** * 获取上一个地支 * @param {string} zhi - 当前地支 * @returns {string} 上一个地支 */ getPrevZhi(zhi) { const zhis = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; const index = zhis.indexOf(zhi); return zhis[(index - 1 + 12) % 12]; } /** * 获取年份对应的干支 * @param {number} year - 年份 * @returns {string} 干支 */ getYearGanZhi(year) { // 以1984年甲子年为基准 const baseYear = 1984; const yearDiff = year - baseYear; const gans = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; const zhis = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; const ganIndex = (yearDiff % 10 + 10) % 10; const zhiIndex = (yearDiff % 12 + 12) % 12; return gans[ganIndex] + zhis[zhiIndex]; } /** * 获取贵人星 * @param {string} dayGan - 日干 * @param {Array} zhis - 地支数组 * @returns {Array} 贵人星 */ getNobleStars(dayGan, zhis) { const nobleStarMap = { '甲': ['丑', '未'], '乙': ['子', '申'], '丙': ['亥', '酉'], '丁': ['亥', '酉'], '戊': ['丑', '未'], '己': ['子', '申'], '庚': ['丑', '未'], '辛': ['午', '寅'], '壬': ['卯', '巳'], '癸': ['卯', '巳'] }; const nobleZhis = nobleStarMap[dayGan] || []; return zhis.filter(zhi => nobleZhis.includes(zhi)); } /** * 获取桃花星 * @param {string} dayZhi - 日支 * @param {Array} zhis - 地支数组 * @returns {Array} 桃花星 */ getPeachBlossom(dayZhi, zhis) { const peachBlossomMap = { '子': '酉', '丑': '午', '寅': '卯', '卯': '子', '辰': '酉', '巳': '午', '午': '卯', '未': '子', '申': '酉', '酉': '午', '戌': '卯', '亥': '子' }; const peachBlossom = peachBlossomMap[dayZhi]; return zhis.filter(zhi => zhi === peachBlossom); } /** * 获取文昌星 * @param {string} dayGan - 日干 * @param {Object} fourPillars - 四柱 * @returns {Array} 文昌星 */ getAcademicStars(dayGan, fourPillars) { const academicStarMap = { '甲': '巳', '乙': '午', '丙': '申', '丁': '酉', '戊': '申', '己': '酉', '庚': '亥', '辛': '子', '壬': '寅', '癸': '卯' }; const academicStar = academicStarMap[dayGan]; const zhis = [fourPillars.year.earthly_branch, fourPillars.month.earthly_branch, fourPillars.day.earthly_branch, fourPillars.hour.earthly_branch]; return zhis.filter(zhi => zhi === academicStar); } /** * 获取财星 * @param {string} dayGan - 日干 * @param {Object} fourPillars - 四柱 * @returns {Array} 财星 */ getWealthStars(dayGan, fourPillars) { // 简化实现,返回空数组 return []; } /** * 获取权力星 * @param {string} dayGan - 日干 * @param {Object} fourPillars - 四柱 * @returns {Array} 权力星 */ getPowerStars(dayGan, fourPillars) { // 简化实现,返回空数组 return []; } /** * 获取驿马星 * @param {string} dayZhi - 日支 * @param {Object} fourPillars - 四柱 * @returns {Array} 驿马星 */ getTravelHorse(dayZhi, fourPillars) { const travelHorseMap = { '子': '寅', '丑': '亥', '寅': '申', '卯': '巳', '辰': '寅', '巳': '亥', '午': '申', '未': '巳', '申': '寅', '酉': '亥', '戌': '申', '亥': '巳' }; const travelHorse = travelHorseMap[dayZhi]; const zhis = [fourPillars.year.earthly_branch, fourPillars.month.earthly_branch, fourPillars.day.earthly_branch, fourPillars.hour.earthly_branch]; return zhis.filter(zhi => zhi === travelHorse); } /** * 获取灾煞星 * @param {string} dayGan - 日干 * @param {Object} fourPillars - 四柱 * @returns {Array} 灾煞星 */ getDisasterStars(dayGan, fourPillars) { // 简化实现,返回空数组 return []; } /** * 获取地支对应的五行 * @param {string} zhi - 地支 * @returns {string} 五行 */ getZhiElement(zhi) { const zhiElements = { '子': 'water', '丑': 'earth', '寅': 'wood', '卯': 'wood', '辰': 'earth', '巳': 'fire', '午': 'fire', '未': 'earth', '申': 'metal', '酉': 'metal', '戌': 'earth', '亥': 'water' }; return zhiElements[zhi] || '未知'; } /** * 获取地支藏干 * @param {string} zhi - 地支 * @returns {Array} 藏干数组 */ getZhiHiddenGans(zhi) { const hiddenGans = { '子': [{ gan: '癸', strength: 1.0 }], '丑': [{ gan: '己', strength: 0.6 }, { gan: '癸', strength: 0.3 }, { gan: '辛', strength: 0.1 }], '寅': [{ gan: '甲', strength: 0.6 }, { gan: '丙', strength: 0.3 }, { gan: '戊', strength: 0.1 }], '卯': [{ gan: '乙', strength: 1.0 }], '辰': [{ gan: '戊', strength: 0.6 }, { gan: '乙', strength: 0.3 }, { gan: '癸', strength: 0.1 }], '巳': [{ gan: '丙', strength: 0.6 }, { gan: '戊', strength: 0.3 }, { gan: '庚', strength: 0.1 }], '午': [{ gan: '丁', strength: 0.7 }, { gan: '己', strength: 0.3 }], '未': [{ gan: '己', strength: 0.6 }, { gan: '丁', strength: 0.3 }, { gan: '乙', strength: 0.1 }], '申': [{ gan: '庚', strength: 0.6 }, { gan: '壬', strength: 0.3 }, { gan: '戊', strength: 0.1 }], '酉': [{ gan: '辛', strength: 1.0 }], '戌': [{ gan: '戊', strength: 0.6 }, { gan: '辛', strength: 0.3 }, { gan: '丁', strength: 0.1 }], '亥': [{ gan: '壬', strength: 0.7 }, { gan: '甲', strength: 0.3 }] }; return hiddenGans[zhi] || []; } /** * 分析五行平衡 * @param {Object} elements - 五行统计 * @param {string} dayMasterElement - 日主五行 * @returns {Object} 分析结果 */ analyzeFiveElementBalance(elements, dayMasterElement) { const total = Object.values(elements).reduce((sum, count) => sum + count, 0); const dayMasterStrength = elements[dayMasterElement] / total; let favorable_elements = []; let unfavorable_elements = []; if (dayMasterStrength < 0.2) { // 日主偏弱,需要生扶 favorable_elements = this.getGeneratingElements(dayMasterElement); unfavorable_elements = this.getWeakeningElements(dayMasterElement); } else if (dayMasterStrength > 0.4) { // 日主偏强,需要克泄 favorable_elements = this.getWeakeningElements(dayMasterElement); unfavorable_elements = this.getGeneratingElements(dayMasterElement); } else { // 日主中和 favorable_elements = [dayMasterElement]; unfavorable_elements = []; } return { balance_type: dayMasterStrength < 0.2 ? '偏弱' : dayMasterStrength > 0.4 ? '偏强' : '中和', day_master_strength: (dayMasterStrength * 100).toFixed(1) + '%', favorable_elements, unfavorable_elements }; } /** * 获取生扶元素 * @param {string} element - 五行 * @returns {Array} 生扶元素 */ getGeneratingElements(element) { const generating = { 'wood': ['water', 'wood'], 'fire': ['wood', 'fire'], 'earth': ['fire', 'earth'], 'metal': ['earth', 'metal'], 'water': ['metal', 'water'] }; return generating[element] || []; } /** * 获取克泄元素 * @param {string} element - 五行 * @returns {Array} 克泄元素 */ getWeakeningElements(element) { const weakening = { 'wood': ['metal', 'fire'], 'fire': ['water', 'earth'], 'earth': ['wood', 'metal'], 'metal': ['fire', 'water'], 'water': ['earth', 'wood'] }; return weakening[element] || []; } /** * 根据地支获取季节 * @param {string} zhi - 地支 * @returns {string} 季节 */ getSeasonFromZhi(zhi) { const seasons = { '寅': '春', '卯': '春', '辰': '春', '巳': '夏', '午': '夏', '未': '夏', '申': '秋', '酉': '秋', '戌': '秋', '亥': '冬', '子': '冬', '丑': '冬' }; return seasons[zhi] || '未知'; } /** * 根据日干和时辰计算时干 * @param {string} dayStem - 日干 * @param {number} hour - 小时(0-23) * @returns {string} 时干 */ getHourGan(dayStem, hour) { // 确定时辰索引 let hourIndex; if (hour >= 23 || hour < 1) hourIndex = 0; // 子时 else if (hour >= 1 && hour < 3) hourIndex = 1; // 丑时 else if (hour >= 3 && hour < 5) hourIndex = 2; // 寅时 else if (hour >= 5 && hour < 7) hourIndex = 3; // 卯时 else if (hour >= 7 && hour < 9) hourIndex = 4; // 辰时 else if (hour >= 9 && hour < 11) hourIndex = 5; // 巳时 else if (hour >= 11 && hour < 13) hourIndex = 6; // 午时 else if (hour >= 13 && hour < 15) hourIndex = 7; // 未时 else if (hour >= 15 && hour < 17) hourIndex = 8; // 申时 else if (hour >= 17 && hour < 19) hourIndex = 9; // 酉时 else if (hour >= 19 && hour < 21) hourIndex = 10; // 戌时 else hourIndex = 11; // 亥时 // 根据日干推算时干 const dayStemIndex = this.heavenlyStems.indexOf(dayStem); const hourStemIndex = (dayStemIndex * 2 + hourIndex) % 10; return this.heavenlyStems[hourStemIndex]; } /** * 计算流年 * @param {Date} birthDate - 出生日期 * @returns {Array} 流年信息 */ calculateAnnualLuck(birthDate) { const currentYear = new Date().getFullYear(); const birthYear = birthDate.getFullYear(); const annualLuck = []; // 计算近10年的流年 for (let i = -5; i <= 5; i++) { const year = currentYear + i; const age = year - birthYear; // 计算该年的干支 const baseYear = 1984; // 甲子年 const yearOffset = (year - baseYear) % 60; const stemIndex = yearOffset % 10; const branchIndex = yearOffset % 12; const stem = this.heavenlyStems[stemIndex < 0 ? stemIndex + 10 : stemIndex]; const branch = this.earthlyBranches[branchIndex < 0 ? branchIndex + 12 : branchIndex]; annualLuck.push({ year: year, age: age, stem: stem, branch: branch, element: this.stemElements[stem], branch_element: this.branchElements[branch], is_current: year === currentYear }); } return annualLuck; } /** * 分析五行强弱 * @param {Array} pillars - 四柱 * @returns {Object} 五行分析 */ analyzeElements(pillars) { const elements = { '木': 0, '火': 0, '土': 0, '金': 0, '水': 0 }; // 统计天干地支五行 pillars.forEach(pillar => { elements[pillar.element] += 2; // 天干权重2 elements[pillar.branch_element] += 1; // 地支权重1 }); // 找出最强和最弱的五行 const sortedElements = Object.entries(elements).sort((a, b) => b[1] - a[1]); const strongest = sortedElements[0]; const weakest = sortedElements[sortedElements.length - 1]; // 计算日主强弱 const dayMasterElement = pillars[2].element; // 日柱天干 const dayMasterStrength = elements[dayMasterElement]; const totalStrength = Object.values(elements).reduce((sum, val) => sum + val, 0); const strengthRatio = dayMasterStrength / totalStrength; let dayMasterStatus; if (strengthRatio > 0.4) dayMasterStatus = '偏强'; else if (strengthRatio > 0.25) dayMasterStatus = '中和'; else if (strengthRatio > 0.15) dayMasterStatus = '偏弱'; else dayMasterStatus = '极弱'; return { element_count: elements, strongest_element: { element: strongest[0], count: strongest[1] }, weakest_element: { element: weakest[0], count: weakest[1] }, day_master_element: dayMasterElement, day_master_strength: dayMasterStrength, day_master_status: dayMasterStatus, strength_ratio: strengthRatio, total_strength: totalStrength }; } /** * 分析十神关系 * @param {string} dayMasterStem - 日主天干 * @param {Array} pillars - 四柱 * @returns {Object} 十神分析 */ analyzeTenGods(dayMasterStem, pillars) { const dayMasterElement = this.stemElements[dayMasterStem]; const dayMasterPolarity = this.stemPolarity[dayMasterStem]; const tenGodsCount = {}; const tenGodsPositions = []; pillars.forEach((pillar, index) => { const positions = ['年', '月', '日', '时']; // 分析天干十神 const stemTenGod = this.getStemTenGod(dayMasterStem, pillar.stem); if (stemTenGod) { tenGodsCount[stemTenGod] = (tenGodsCount[stemTenGod] || 0) + 1; tenGodsPositions.push({ position: positions[index], type: '天干', stem: pillar.stem, ten_god: stemTenGod }); } // 分析地支藏干十神(简化处理) const branchHiddenStems = this.getBranchHiddenStems(pillar.branch); branchHiddenStems.forEach(hiddenStem => { const hiddenTenGod = this.getStemTenGod(dayMasterStem, hiddenStem.stem); if (hiddenTenGod) { tenGodsCount[hiddenTenGod] = (tenGodsCount[hiddenTenGod] || 0) + hiddenStem.strength; tenGodsPositions.push({ position: positions[index], type: '地支藏干', branch: pillar.branch, hidden_stem: hiddenStem.stem, ten_god: hiddenTenGod, strength: hiddenStem.strength }); } }); }); return { day_master: { stem: dayMasterStem, element: dayMasterElement, polarity: dayMasterPolarity }, ten_gods_count: tenGodsCount, ten_gods_positions: tenGodsPositions }; } /** * 分析格局 * @param {Array} pillars - 四柱 * @param {Object} elementAnalysis - 五行分析 * @returns {Object} 格局分析 */ analyzePattern(pillars, elementAnalysis) { const dayMaster = pillars[2]; // 日柱 const monthBranch = pillars[1].branch; // 月支 // 判断是否为特殊格局 const specialPattern = this.identifySpecialPattern(pillars, elementAnalysis); if (specialPattern) { return { type: '特殊格局', pattern: specialPattern, description: this.getPatternDescription(specialPattern) }; } // 判断普通格局(以月支为准) const monthElement = this.branchElements[monthBranch]; const dayMasterElement = dayMaster.element; let pattern; if (monthElement === dayMasterElement) { pattern = '建禄格'; } else if (this.isElementGenerating(monthElement, dayMasterElement)) { pattern = '印绶格'; } else if (this.isElementGenerating(dayMasterElement, monthElement)) { pattern = '食伤格'; } else if (this.isElementDestructive(dayMasterElement, monthElement)) { pattern = '财格'; } else if (this.isElementDestructive(monthElement, dayMasterElement)) { pattern = '官杀格'; } else { pattern = '普通格局'; } return { type: '普通格局', pattern: pattern, month_element: monthElement, day_master_element: dayMasterElement, description: this.getPatternDescription(pattern) }; } // 辅助方法 /** * 获取立春时间 * @param {number} year - 年份 * @returns {Date} 立春时间 */ getSpringStart(year) { // 简化计算,实际应该使用精确的节气计算 return new Date(year, 1, 4); // 大约2月4日 } /** * 获取节气月份 * @param {number} month - 月份 * @param {number} day - 日期 * @returns {number} 节气月份 */ getSolarMonth(month, day) { // 简化处理,实际应该根据精确节气计算 const solarMonthStart = [ [2, 4], // 立春 [3, 6], // 惊蛰 [4, 5], // 清明 [5, 6], // 立夏 [6, 6], // 芒种 [7, 7], // 小暑 [8, 8], // 立秋 [9, 8], // 白露 [10, 8], // 寒露 [11, 8], // 立冬 [12, 7], // 大雪 [1, 6] // 小寒 ]; for (let i = 0; i < solarMonthStart.length; i++) { const [startMonth, startDay] = solarMonthStart[i]; if (month === startMonth && day >= startDay) { return (i + 1) % 12 || 12; } } return month; } /** * 获取儒略日 * @param {Date} date - 日期 * @returns {number} 儒略日 */ getJulianDay(date) { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); let a = Math.floor((14 - month) / 12); let y = year + 4800 - a; let m = month + 12 * a - 3; return day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045; } /** * 获取时辰范围 * @param {number} hourIndex - 时辰索引 * @returns {string} 时辰范围 */ getHourRange(hourIndex) { const ranges = [ '23:00-01:00', '01:00-03:00', '03:00-05:00', '05:00-07:00', '07:00-09:00', '09:00-11:00', '11:00-13:00', '13:00-15:00', '15:00-17:00', '17:00-19:00', '19:00-21:00', '21:00-23:00' ]; return ranges[hourIndex]; } /** * 计算起运年龄 * @param {Date} birthDate - 出生日期 * @param {Object} monthPillar - 月柱 * @param {boolean} isForward - 是否顺行 * @returns {number} 起运年龄 */ calculateLuckStartAge(birthDate, monthPillar, isForward) { // 简化计算,实际应该根据节气精确计算 return Math.floor(Math.random() * 8) + 1; // 1-8岁之间 } /** * 获取天干十神 * @param {string} dayMaster - 日主 * @param {string} targetStem - 目标天干 * @returns {string} 十神 */ getStemTenGod(dayMaster, targetStem) { if (dayMaster === targetStem) return null; // 日主本身 const dayElement = this.stemElements[dayMaster]; const dayPolarity = this.stemPolarity[dayMaster]; const targetElement = this.stemElements[targetStem]; const targetPolarity = this.stemPolarity[targetStem]; // 根据五行关系和阴阳确定十神 if (dayElement === targetElement) { return dayPolarity === targetPolarity ? '比肩' : '劫财'; } else if (this.isElementGenerating(dayElement, targetElement)) { return dayPolarity === targetPolarity ? '食神' : '伤官'; } else if (this.isElementDestructive(dayElement, targetElement)) { return dayPolarity === targetPolarity ? '偏财' : '正财'; } else if (this.isElementDestructive(targetElement, dayElement)) { return dayPolarity === targetPolarity ? '七杀' : '正官'; } else if (this.isElementGenerating(targetElement, dayElement)) { return dayPolarity === targetPolarity ? '偏印' : '正印'; } return '未知'; } /** * 获取十神信息 * @param {string} god - 十神名称 * @returns {Object|null} 十神信息 */ getTenGod(god) { return this.baziDB.getTenGod(god); } /** * 统计十神分布 * @param {Object} tenGods - 十神数据 * @returns {Object} 十神分布统计 */ getTenGodDistribution(tenGods) { const distribution = { '比肩': 0, '劫财': 0, '食神': 0, '伤官': 0, '偏财': 0, '正财': 0, '七杀': 0, '正官': 0, '偏印': 0, '正印': 0 }; Object.values(tenGods).forEach(pillar => { if (pillar.gan_ten_god) { distribution[pillar.gan_ten_god] = (distribution[pillar.gan_ten_god] || 0) + 1; } if (pillar.zhi_ten_god) { distribution[pillar.zhi_ten_god] = (distribution[pillar.zhi_ten_god] || 0) + 0.5; } }); return distribution; } /** * 分析十神特点 * @param {Object} distribution - 十神分布 * @param {string} dayGan - 日干 * @returns {Object} 十神特点分析 */ analyzeTenGodCharacteristics(distribution, dayGan) { const characteristics = { dominant_gods: [], personality_traits: [], career_tendencies: [], wealth_potential: '中等', relationship_style: '平和' }; // 找出主要十神 Object.entries(distribution).forEach(([god, count]) => { if (count >= 1) { characteristics.dominant_gods.push(god); } }); // 根据主要十神分析特点 if (distribution['正官'] > 0 || distribution['七杀'] > 0) { characteristics.personality_traits.push('有责任心', '领导能力强'); characteristics.career_tendencies.push('管理', '公务员'); } if (distribution['正财'] > 0 || distribution['偏财'] > 0) { characteristics.wealth_potential = '较强'; characteristics.career_tendencies.push('商业', '金融'); } if (distribution['食神'] > 0 || distribution['伤官'] > 0) { characteristics.personality_traits.push('有创意', '表达能力强'); characteristics.career_tendencies.push('艺术', '创意'); } return characteristics; } /** * 获取年份干支 * @param {number} year - 年份 * @returns {string} 年干支 */ getYearGanZhi(year) { // 甲子年为1984年,每60年一个循环 const baseYear = 1984; const yearOffset = (year - baseYear) % 60; const stemIndex = yearOffset % 10; const branchIndex = yearOffset % 12; const stem = this.heavenlyStems[stemIndex < 0 ? stemIndex + 10 : stemIndex]; const branch = this.earthlyBranches[branchIndex < 0 ? branchIndex + 12 : branchIndex]; return stem + branch; } /** * 获取月份干支 * @param {number} year - 年份 * @param {number} month - 月份(1-12) * @returns {string} 月干支 */ getMonthGanZhi(year, month) { // 月支固定:寅月(立春)、卯月(惊蛰)、辰月(清明)... const monthBranches = ['寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥', '子', '丑']; const branchIndex = (month - 1) % 12; const branch = monthBranches[branchIndex]; // 月干根据年干推算 const yearGanZhi = this.getYearGanZhi(year); const yearStem = yearGanZhi.charAt(0); const yearStemIndex = this.heavenlyStems.indexOf(yearStem); const monthStemIndex = (yearStemIndex * 2 + month - 1) % 10; const stem = this.heavenlyStems[monthStemIndex]; return stem + branch; } /** * 获取地支主气天干 * @param {string} branch - 地支 * @returns {string} 主气天干 */ getZhiMainGan(branch) { const hiddenStems = this.getBranchHiddenStems(branch); return hiddenStems.length > 0 ? hiddenStems[0].stem : null; } /** * 获取地支藏干 * @param {string} branch - 地支 * @returns {Array} 藏干数组 */ getBranchHiddenStems(branch) { const hiddenStems = { '子': [{ stem: '癸', strength: 1.0 }], '丑': [{ stem: '己', strength: 0.6 }, { stem: '癸', strength: 0.3 }, { stem: '辛', strength: 0.1 }], '寅': [{ stem: '甲', strength: 0.6 }, { stem: '丙', strength: 0.3 }, { stem: '戊', strength: 0.1 }], '卯': [{ stem: '乙', strength: 1.0 }], '辰': [{ stem: '戊', strength: 0.6 }, { stem: '乙', strength: 0.3 }, { stem: '癸', strength: 0.1 }], '巳': [{ stem: '丙', strength: 0.6 }, { stem: '戊', strength: 0.3 }, { stem: '庚', strength: 0.1 }], '午': [{ stem: '丁', strength: 0.7 }, { stem: '己', strength: 0.3 }], '未': [{ stem: '己', strength: 0.6 }, { stem: '丁', strength: 0.3 }, { stem: '乙', strength: 0.1 }], '申': [{ stem: '庚', strength: 0.6 }, { stem: '壬', strength: 0.3 }, { stem: '戊', strength: 0.1 }], '酉': [{ stem: '辛', strength: 1.0 }], '戌': [{ stem: '戊', strength: 0.6 }, { stem: '辛', strength: 0.3 }, { stem: '丁', strength: 0.1 }], '亥': [{ stem: '壬', strength: 0.7 }, { stem: '甲', strength: 0.3 }] }; return hiddenStems[branch] || []; } /** * 判断五行相生关系 * @param {string} element1 - 五行1 * @param {string} element2 - 五行2 * @returns {boolean} 是否相生 */ isElementGenerating(element1, element2) { const generatingCycles = { '木': '火', '火': '土', '土': '金', '金': '水', '水': '木' }; return generatingCycles[element1] === element2; } /** * 判断五行相克关系 * @param {string} element1 - 五行1 * @param {string} element2 - 五行2 * @returns {boolean} 是否相克 */ isElementDestructive(element1, element2) { const destructiveCycles = { '木': '土', '火': '金', '土': '水', '金': '木', '水': '火' }; return destructiveCycles[element1] === element2; } /** * 识别特殊格局 * @param {Array} pillars - 四柱 * @param {Object} elementAnalysis - 五行分析 * @returns {string|null} 特殊格局名称 */ identifySpecialPattern(pillars, elementAnalysis) { // 从革格(金旺) if (elementAnalysis.strongest_element.element === '金' && elementAnalysis.strongest_element.count >= 8) { return '从革格'; } // 炎上格(火旺) if (elementAnalysis.strongest_element.element === '火' && elementAnalysis.strongest_element.count >= 8) { return '炎上格'; } // 润下格(水旺) if (elementAnalysis.strongest_element.element === '水' && elementAnalysis.strongest_element.count >= 8) { return '润下格'; } // 曲直格(木旺) if (elementAnalysis.strongest_element.element === '木' && elementAnalysis.strongest_element.count >= 8) { return '曲直格'; } // 稼穑格(土旺) if (elementAnalysis.strongest_element.element === '土' && elementAnalysis.strongest_element.count >= 8) { return '稼穑格'; } return null; } /** * 获取格局描述 * @param {string} pattern - 格局名称 * @returns {string} 格局描述 */ getPatternDescription(pattern) { const descriptions = { '建禄格': '日主与月支同气,身强有力,适合创业发展', '印绶格': '月支生助日主,聪明好学,适合文职工作', '食伤格': '日主生月支,才华横溢,适合创意工作', '财格': '日主克月支,善于理财,适合商业发展', '官杀格': '月支克日主,有责任心,适合管理工作', '从革格': '金气极旺,性格刚强,适合技术工作', '炎上格': '火气极旺,热情积极,适合表演艺术', '润下格': '水气极旺,智慧灵活,适合流动性工作', '曲直格': '木气极旺,仁慈正直,适合教育工作', '稼穑格': '土气极旺,诚实稳重,适合农业地产' }; return descriptions[pattern] || '格局特殊,需要综合分析'; } /** * 验证八字数据 * @param {Object} bazi - 八字数据 * @returns {boolean} 是否有效 */ validateBazi(bazi) { if (!bazi || typeof bazi !== 'object') { return false; } // 检查必要字段 const requiredFields = ['birth_info', 'four_pillars', 'element_analysis']; for (const field of requiredFields) { if (!bazi[field]) { return false; } } // 检查四柱 const pillars = ['year', 'month', 'day', 'hour']; for (const pillar of pillars) { if (!bazi.four_pillars[pillar] || !bazi.four_pillars[pillar].stem || !bazi.four_pillars[pillar].branch) { return false; } } return true; } } module.exports = BaziCalculator;