/**
* 易经计算工具
* 用于易经卦象的生成和计算
*/
const Logger = require('./logger.js');
class YijingCalculator {
constructor() {
this.logger = new Logger();
}
/**
* 使用铜钱法生成卦象
* @param {string} question - 问题
* @param {string} seed - 随机种子
* @returns {Object} 卦象数据
*/
generateByCoin(question, seed = null) {
this.logger.info('使用铜钱法生成卦象', { question });
const lines = [];
const random = this.createSeededRandom(seed || question + Date.now());
for (let i = 0; i < 6; i++) {
// 模拟投掷三枚铜钱
const coin1 = random() > 0.5 ? 3 : 2; // 正面3,反面2
const coin2 = random() > 0.5 ? 3 : 2;
const coin3 = random() > 0.5 ? 3 : 2;
const sum = coin1 + coin2 + coin3;
// 根据总和确定爻的性质
let lineType, isChanging;
switch (sum) {
case 6: // 三个反面 - 老阴
lineType = 'yin';
isChanging = true;
break;
case 7: // 两反一正 - 少阳
lineType = 'yang';
isChanging = false;
break;
case 8: // 两正一反 - 少阴
lineType = 'yin';
isChanging = false;
break;
case 9: // 三个正面 - 老阳
lineType = 'yang';
isChanging = true;
break;
}
lines.push({
position: i + 1,
type: lineType,
changing: isChanging,
value: sum
});
}
return this.buildHexagram(lines, 'coin', question);
}
/**
* 使用蓍草法生成卦象
* @param {string} question - 问题
* @param {string} seed - 随机种子
* @returns {Object} 卦象数据
*/
generateByYarrow(question, seed = null) {
this.logger.info('使用蓍草法生成卦象', { question });
const lines = [];
const random = this.createSeededRandom(seed || question + Date.now());
for (let i = 0; i < 6; i++) {
// 模拟蓍草分组过程(简化版)
let stalks = 49; // 蓍草总数
let operations = [];
for (let op = 0; op < 3; op++) {
// 第一次分组
const leftGroup = Math.floor(random() * (stalks - 1)) + 1;
const rightGroup = stalks - leftGroup;
// 计算余数
const leftRemainder = leftGroup % 4 || 4;
const rightRemainder = rightGroup % 4 || 4;
const totalRemainder = leftRemainder + rightRemainder;
operations.push(totalRemainder);
stalks -= totalRemainder;
}
// 根据操作结果确定爻的性质
const finalValue = stalks / 4;
let lineType, isChanging;
if (finalValue === 6) {
lineType = 'yin';
isChanging = false;
} else if (finalValue === 7) {
lineType = 'yang';
isChanging = false;
} else if (finalValue === 8) {
lineType = 'yin';
isChanging = true;
} else if (finalValue === 9) {
lineType = 'yang';
isChanging = true;
}
lines.push({
position: i + 1,
type: lineType,
changing: isChanging,
value: finalValue,
operations: operations
});
}
return this.buildHexagram(lines, 'yarrow', question);
}
/**
* 使用梅花易数法生成卦象
* @param {string} question - 问题
* @param {string} seed - 随机种子
* @returns {Object} 卦象数据
*/
generateByPlumBlossom(question, seed = null) {
this.logger.info('使用梅花易数法生成卦象', { question });
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;
const day = now.getDate();
const hour = now.getHours();
const minute = now.getMinutes();
// 计算上卦
const upperSum = (year + month + day) % 8;
const upperTrigram = this.getTrigramByNumber(upperSum || 8);
// 计算下卦
const lowerSum = (year + month + day + hour) % 8;
const lowerTrigram = this.getTrigramByNumber(lowerSum || 8);
// 计算动爻
const changingLine = (year + month + day + hour + minute) % 6 || 6;
// 构建卦象
const lines = [];
const upperLines = upperTrigram.lines;
const lowerLines = lowerTrigram.lines;
// 下卦在下(1-3爻),上卦在上(4-6爻)
for (let i = 0; i < 3; i++) {
lines.push({
position: i + 1,
type: lowerLines[i],
changing: (i + 1) === changingLine,
value: (i + 1) === changingLine ? 9 : 7
});
}
for (let i = 0; i < 3; i++) {
lines.push({
position: i + 4,
type: upperLines[i],
changing: (i + 4) === changingLine,
value: (i + 4) === changingLine ? 9 : 7
});
}
const hexagram = this.buildHexagram(lines, 'plum_blossom', question);
hexagram.calculation_details = {
year, month, day, hour, minute,
upper_sum: upperSum,
lower_sum: lowerSum,
changing_line: changingLine,
upper_trigram: upperTrigram.name,
lower_trigram: lowerTrigram.name
};
return hexagram;
}
/**
* 使用时间起卦法生成卦象
* @param {string} question - 问题
* @param {string} seed - 随机种子
* @returns {Object} 卦象数据
*/
generateByTime(question, seed = null) {
this.logger.info('使用时间起卦法生成卦象', { question });
const now = new Date();
const year = now.getFullYear() % 12; // 地支
const month = now.getMonth() + 1;
const day = now.getDate();
const hour = Math.floor(now.getHours() / 2); // 时辰
// 计算上卦(年月日之和除以8)
const upperSum = (year + month + day) % 8;
const upperTrigram = this.getTrigramByNumber(upperSum || 8);
// 计算下卦(年月日时之和除以8)
const lowerSum = (year + month + day + hour) % 8;
const lowerTrigram = this.getTrigramByNumber(lowerSum || 8);
// 计算动爻(年月日时之和除以6)
const changingLine = (year + month + day + hour) % 6 || 6;
// 构建卦象
const lines = [];
const upperLines = upperTrigram.lines;
const lowerLines = lowerTrigram.lines;
// 下卦在下(1-3爻),上卦在上(4-6爻)
for (let i = 0; i < 3; i++) {
lines.push({
position: i + 1,
type: lowerLines[i],
changing: (i + 1) === changingLine,
value: (i + 1) === changingLine ? 9 : 7
});
}
for (let i = 0; i < 3; i++) {
lines.push({
position: i + 4,
type: upperLines[i],
changing: (i + 4) === changingLine,
value: (i + 4) === changingLine ? 9 : 7
});
}
const hexagram = this.buildHexagram(lines, 'time', question);
hexagram.calculation_details = {
year, month, day, hour,
upper_sum: upperSum,
lower_sum: lowerSum,
changing_line: changingLine,
upper_trigram: upperTrigram.name,
lower_trigram: lowerTrigram.name
};
return hexagram;
}
/**
* 构建卦象对象
* @param {Array} lines - 爻线数组
* @param {string} method - 生成方法
* @param {string} question - 问题
* @returns {Object} 卦象对象
*/
buildHexagram(lines, method, question) {
// 获取上下卦
const lowerTrigram = this.getTrigramFromLines(lines.slice(0, 3));
const upperTrigram = this.getTrigramFromLines(lines.slice(3, 6));
// 计算卦象编号
const hexagramNumber = this.calculateHexagramNumber(upperTrigram.number, lowerTrigram.number);
// 生成变卦(如果有变爻)
const changingLines = lines.filter(line => line.changing);
let changingHexagram = null;
if (changingLines.length > 0) {
const changedLines = lines.map(line => ({
...line,
type: line.changing ? (line.type === 'yang' ? 'yin' : 'yang') : line.type,
changing: false
}));
const changedLowerTrigram = this.getTrigramFromLines(changedLines.slice(0, 3));
const changedUpperTrigram = this.getTrigramFromLines(changedLines.slice(3, 6));
const changedHexagramNumber = this.calculateHexagramNumber(changedUpperTrigram.number, changedLowerTrigram.number);
changingHexagram = {
number: changedHexagramNumber,
upper_trigram: changedUpperTrigram,
lower_trigram: changedLowerTrigram,
lines: changedLines
};
}
return {
number: hexagramNumber,
upper_trigram: upperTrigram,
lower_trigram: lowerTrigram,
lines: lines,
changing_lines: changingLines,
changing_hexagram: changingHexagram,
method: method,
question: question,
timestamp: new Date().toISOString()
};
}
/**
* 根据数字获取八卦
* @param {number} number - 数字(1-8)
* @returns {Object} 八卦信息
*/
getTrigramByNumber(number) {
const trigrams = {
1: { name: '乾', symbol: '☰', lines: ['yang', 'yang', 'yang'], number: 1, element: '金', direction: '西北' },
2: { name: '兑', symbol: '☱', lines: ['yin', 'yang', 'yang'], number: 2, element: '金', direction: '西' },
3: { name: '离', symbol: '☲', lines: ['yang', 'yin', 'yang'], number: 3, element: '火', direction: '南' },
4: { name: '震', symbol: '☳', lines: ['yin', 'yin', 'yang'], number: 4, element: '木', direction: '东' },
5: { name: '巽', symbol: '☴', lines: ['yang', 'yin', 'yin'], number: 5, element: '木', direction: '东南' },
6: { name: '坎', symbol: '☵', lines: ['yin', 'yang', 'yin'], number: 6, element: '水', direction: '北' },
7: { name: '艮', symbol: '☶', lines: ['yang', 'yin', 'yin'], number: 7, element: '土', direction: '东北' },
8: { name: '坤', symbol: '☷', lines: ['yin', 'yin', 'yin'], number: 8, element: '土', direction: '西南' }
};
return trigrams[number] || trigrams[1];
}
/**
* 从爻线获取八卦
* @param {Array} lines - 三个爻线
* @returns {Object} 八卦信息
*/
getTrigramFromLines(lines) {
const pattern = lines.map(line => line.type).join('');
const patterns = {
'yangyangyang': 1, // 乾
'yinyangyang': 2, // 兑
'yangyinyang': 3, // 离
'yinyinyang': 4, // 震
'yangyinyin': 5, // 巽
'yinyangyin': 6, // 坎
'yangyinyin': 7, // 艮
'yinyinyin': 8 // 坤
};
const number = patterns[pattern] || 1;
return this.getTrigramByNumber(number);
}
/**
* 计算卦象编号
* @param {number} upperNumber - 上卦编号
* @param {number} lowerNumber - 下卦编号
* @returns {number} 卦象编号(1-64)
*/
calculateHexagramNumber(upperNumber, lowerNumber) {
// 简化的卦象编号计算
// 实际应用中应该使用标准的64卦编号表
return ((upperNumber - 1) * 8 + lowerNumber);
}
/**
* 创建带种子的随机数生成器
* @param {string} seed - 种子
* @returns {Function} 随机数生成函数
*/
createSeededRandom(seed) {
let hash = 0;
if (seed.length === 0) return Math.random;
for (let i = 0; i < seed.length; i++) {
const char = seed.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // 转换为32位整数
}
return function () {
hash = (hash * 9301 + 49297) % 233280;
return hash / 233280;
};
}
/**
* 随机生成卦象
* @param {string} question - 问题
* @param {string} seed - 随机种子
* @returns {Object} 卦象数据
*/
generateRandom(question = '随机起卦', seed = null) {
this.logger.info('使用随机方法生成卦象', { question });
const random = this.createSeededRandom(seed || question + Date.now());
const lines = [];
for (let i = 0; i < 6; i++) {
// 随机生成阴阳
const isYang = random() > 0.5;
// 10%的概率为变爻
const isChanging = random() < 0.1;
lines.push({
position: i + 1,
type: isYang ? 'yang' : 'yin',
changing: isChanging,
value: isChanging ? (isYang ? 9 : 6) : (isYang ? 7 : 8)
});
}
return this.buildHexagram(lines, 'random', question);
}
/**
* 使用数字生成卦象
* @param {string} seed - 数字种子
* @returns {Object} 卦象数据
*/
generateFromNumber(seed) {
this.logger.info('使用数字方法生成卦象', { seed });
const random = this.createSeededRandom(seed.toString());
const lines = [];
for (let i = 0; i < 6; i++) {
const isYang = random() > 0.5;
const isChanging = random() < 0.1;
lines.push({
position: i + 1,
type: isYang ? 'yang' : 'yin',
changing: isChanging,
value: isChanging ? (isYang ? 9 : 6) : (isYang ? 7 : 8)
});
}
return this.buildHexagram(lines, 'number', seed);
}
/**
* 使用时间生成卦象
* @param {Date} date - 时间对象
* @returns {Object} 卦象数据
*/
generateFromTime(date) {
this.logger.info('使用时间方法生成卦象', { date });
const seed = date.getTime().toString();
const random = this.createSeededRandom(seed);
const lines = [];
for (let i = 0; i < 6; i++) {
const isYang = random() > 0.5;
const isChanging = random() < 0.1;
lines.push({
position: i + 1,
type: isYang ? 'yang' : 'yin',
changing: isChanging,
value: isChanging ? (isYang ? 9 : 6) : (isYang ? 7 : 8)
});
}
return this.buildHexagram(lines, 'time', date.toISOString());
}
/**
* 使用梅花易数生成卦象
* @param {string} seed - 种子
* @returns {Object} 卦象数据
*/
generateFromPlumBlossom(seed) {
this.logger.info('使用梅花易数方法生成卦象', { seed });
const now = new Date();
const timeSeed = now.getFullYear() + now.getMonth() + now.getDate() + now.getHours();
const combinedSeed = seed + timeSeed.toString();
const random = this.createSeededRandom(combinedSeed);
const lines = [];
for (let i = 0; i < 6; i++) {
const isYang = random() > 0.5;
const isChanging = random() < 0.1;
lines.push({
position: i + 1,
type: isYang ? 'yang' : 'yin',
changing: isChanging,
value: isChanging ? (isYang ? 9 : 6) : (isYang ? 7 : 8)
});
}
return this.buildHexagram(lines, 'plum_blossom', seed);
}
/**
* 验证卦象数据
* @param {Object} hexagram - 卦象数据
* @returns {boolean} 是否有效
*/
validateHexagram(hexagram) {
if (!hexagram || typeof hexagram !== 'object') {
return false;
}
// 检查必要字段
const requiredFields = ['number', 'upper_trigram', 'lower_trigram', 'lines'];
for (const field of requiredFields) {
if (!hexagram[field]) {
return false;
}
}
// 检查爻线数量
if (!Array.isArray(hexagram.lines) || hexagram.lines.length !== 6) {
return false;
}
// 检查每个爻线
for (let i = 0; i < 6; i++) {
const line = hexagram.lines[i];
if (!line || line.position !== i + 1 || !['yang', 'yin'].includes(line.type)) {
return false;
}
}
return true;
}
}
module.exports = YijingCalculator;