最近偶有機緣接觸到八卦五行,有個校友在做紫微斗數,於是乎就想做個計算生辰八字五行算法的C#代碼,說到底占卜命理這種理論筆者覺得最終還是基於統計學的,這個可能有很多學派很多師傅有不同的理論,不過算生辰八字還算是通用的,不過不能亂算,筆者最不喜歡的就是搞個不靠譜的誤人子弟,於是乎研究了一圈,發現有篇潘愛民寫的還算比較可靠,但是是基於c語言的,於是筆者在這基礎上寫了個C#版的,本着源於網絡回饋網絡的精神下面是C#改寫的代碼,望大家交流,有其他占卜相關的算法也可以一起研究,其實這和大數據還真的能結合一起。
public class BaziAlgorithm
{
//==================================
//以下爲http://blog.csdn.net/panaimin/article/details/8544489
//計算五行
const string TianGan = "甲乙丙丁戊己庚辛壬癸";
const string DiZhi = "子醜寅卯辰巳午未申酉戌亥";
public bool CheckBazi(string bazi)
{
int baziLen;
int i, j;
baziLen = bazi.Length;
if (baziLen != 6 && baziLen != 8) return false;
for (i = 0; i < baziLen;)
{
char ch = bazi[i];
for (j = 0; j < 10; j++)
if (ch == TianGan[j]) break;
if (j >= 10) return false;
i++;
ch = bazi[i];
for (j = 0; j < 12; j++)
if (ch == DiZhi[j]) break;
if (j >= 12) return false;
i++;
}
return true;
}
/*
根據出生日子的天干,通過下表來查算時辰干支:
時辰干支查算表
時間時辰 五行紀日干支
甲己 乙庚 丙辛 丁壬 戊癸
23-01 子/水 甲子 丙子 戊子 庚子 壬子
01-03 醜/土 乙丑 丁丑 己丑 辛丑 癸丑
03-05 寅/木 丙寅 戊寅 庚寅 壬寅 甲寅
05-07 卯/木 丁卯 己卯 辛卯 癸卯 乙卯
07-09 辰/土 戊辰 庚辰 壬辰 甲辰 丙辰
09-11 巳/火 己巳 辛巳 癸巳 己巳 丁巳
11-13 午/火 庚午 壬午 甲午 丙午 戊午
13-15 未/土 辛未 癸未 乙未 丁未 己未
15-17 申/金 壬申 甲申 丙申 戊申 庚申
17-19 酉/金 癸酉 乙酉 丁酉 己酉 辛酉
19-21 戊/土 甲戌 丙戌 戊戌 庚戌 壬戌
21-23 亥/水 乙亥 丁亥 己亥 辛亥 癸亥
*/
string[][] cTimeGanZhi_Table = new string[12][]
{
new string[] {"甲子","丙子","戊子","庚子","壬子"},
new string[] {"乙丑","丁丑","己丑","辛丑","癸丑"},
new string[] {"丙寅","戊寅","庚寅","壬寅","甲寅"},
new string[] {"丁卯","己卯","辛卯","癸卯","乙卯"},
new string[] {"戊辰","庚辰","壬辰","甲辰","丙辰"},
new string[] {"己巳","辛巳","癸巳","己巳","丁巳"},
new string[] {"庚午","壬午","甲午","丙午","戊午"},
new string[] {"辛未","癸未","乙未","丁未","己未"},
new string[] {"壬申","甲申","丙申","戊申","庚申"},
new string[] {"癸酉","乙酉","丁酉","己酉","辛酉"},
new string[] {"甲戌","丙戌","戊戌","庚戌","壬戌"},
new string[] {"乙亥","丁亥","己亥","辛亥","癸亥"}
};
static string sBuf; // 用作八字結果緩衝區
// 根據出生年月日的干支計算時辰干支
// 輸入參數:bazi,年月日的干支,即八字中的前六個字
// 輸入參數:hour,出生時間的小時數,-1~22
// 輸出結果:八字字符串,Unicode編碼
public string ComputeTimeGan(string bazi, int hour)
{
if (hour > 22) hour -= 24;
char dayGan = bazi[4];
int indexX, indexY;
int i;
for (i = 0; i < 10; i++)
if (dayGan == TianGan[i]) break;
if (i >= 10) return "";
indexX = i;
if (indexX >= 5) indexX -= 5;
indexY = (hour + 1) / 2;
sBuf = bazi;
sBuf += cTimeGanZhi_Table[indexY][indexX];
return sBuf;
}
/*
十二月份天干強度表
生月\四柱天干 甲 乙 丙 丁 戊 己 庚 辛 壬 癸
子月 1.2 1.2 1.0 1.0 1.0 1.0 1.0 1.0 1.2 1.2
丑月 1.06 1.06 1.0 1.0 1.1 1.1 1.14 1.14 1.1 1.1
寅月 1.14 1.14 1.2 1.2 1.06 1.06 1.0 1.0 1.0 1.0
卯月 1.2 1.2 1.2 1.2 1.0 1.0 1.0 1.0 1.0 1.0
辰月 1.1 1.1 1.06 1.06 1.1 1.1 1.1 1.1 1.04 1.04
巳月 1.0 1.0 1.14 1.14 1.14 1.14 1.06 1.06 1.06 1.06
午月 1.0 1.0 1.2 1.2 1.2 1.2 1.0 1.0 1.0 1.0
未月 1.04 1.04 1.1 1.1 1.16 1.16 1.1 1.1 1.0 1.0
申月 1.06 1.06 1.0 1.0 1.0 1.0 1.14 1.14 1.2 1.2
酉月 1.0 1.0 1.0 1.0 1.0 1.0 1.2 1.2 1.2 1.2
戌月 1.0 1.0 1.04 1.04 1.14 1.14 1.16 1.16 1.06 1.06
亥月 1.2 1.2 1.0 1.0 1.0 1.0 1.0 1.0 1.14 1.14
*/
double[][] TianGan_Strength = new double[12][]
{
new double[] {1.2, 1.2, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.2, 1.2},
new double[]{1.06, 1.06, 1.0, 1.0, 1.1, 1.1, 1.14, 1.14, 1.1, 1.1},
new double[] {1.14, 1.14, 1.2, 1.2, 1.06, 1.06, 1.0, 1.0, 1.0, 1.0},
new double[] {1.2, 1.2, 1.2, 1.2, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0},
new double[] {1.1, 1.1, 1.06, 1.06, 1.1, 1.1, 1.1, 1.1, 1.04, 1.04},
new double[] {1.0, 1.0, 1.14, 1.14, 1.14, 1.14, 1.06, 1.06, 1.06, 1.06},
new double[] {1.0, 1.0, 1.2, 1.2, 1.2, 1.2, 1.0, 1.0, 1.0, 1.0},
new double[] {1.04, 1.04, 1.1, 1.1, 1.16, 1.16, 1.1, 1.1, 1.0, 1.0},
new double[] {1.06, 1.06, 1.0, 1.0, 1.0, 1.0, 1.14, 1.14, 1.2, 1.2},
new double[] {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.2, 1.2, 1.2, 1.2},
new double[] {1.0, 1.0, 1.04, 1.04, 1.14, 1.14, 1.16, 1.16, 1.06, 1.06},
new double[] {1.2, 1.2, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.14, 1.14}
};
/*
十二月份地支強度表
生月 子月 丑月 寅月 卯月 辰月 巳月 午月 未月 申月 酉月 戌月 亥月
地支 支藏
子 癸 1.2 1.1 1.0 1.0 1.04 1.06 1.0 1.0 1.2 1.2 1.06 1.14
醜 癸 0.36 0.33 0.3 0.3 0.312 0.318 0.3 0.3 0.36 0.36 0.318 0.342
醜 辛 0.2 0.228 0.2 0.2 0.23 0.212 0.2 0.22 0.228 0.248 0.232 0.2
醜 己 0.5 0.55 0.53 0.5 0.55 0.57 0.6 0.58 0.5 0.5 0.57 0.5
寅 丙 0.3 0.3 0.36 0.36 0.318 0.342 0.36 0.33 0.3 0.3 0.342 0.318
寅 甲 0.84 0.742 0.798 0.84 0.77 0.7 0.7 0.728 0.742 0.7 0.7 0.84
卯 乙 1.2 1.06 1.14 1.2 1.1 1.0 1.0 1.04 1.06 1.0 1.0 1.2
辰 乙 0.36 0.318 0.342 0.36 0.33 0.3 0.3 0.312 0.318 0.3 0.3 0.36
辰 癸 0.24 0.22 0.2 0.2 0.208 0.2 0.2 0.2 0.24 0.24 0.212 0.228
辰 戊 0.5 0.55 0.53 0.5 0.55 0.6 0.6 0.58 0.5 0.5 0.57 0.5
巳 庚 0.3 0.342 0.3 0.3 0.33 0.3 0.3 0.33 0.342 0.36 0.348 0.3
巳 丙 0.7 0.7 0.84 0.84 0.742 0.84 0.84 0.798 0.7 0.7 0.728 0.742
午 丁 1.0 1.0 1.2 1.2 1.06 1.14 1.2 1.1 1.0 1.0 1.04 1.06
未 丁 0.3 0.3 0.36 0.36 0.318 0.342 0.36 0.33 0.3 0.3 0.312 0.318
未 乙 0.24 0.212 0.228 0.24 0.22 0.2 0.2 0.208 0.212 0.2 0.2 0.24
未 己 0.5 0.55 0.53 0.5 0.55 0.57 0.6 0.58 0.5 0.5 0.57 0.5
申 壬 0.36 0.33 0.3 0.3 0.312 0.318 0.3 0.3 0.36 0.36 0.318 0.342
申 庚 0.7 0.798 0.7 0.7 0.77 0.742 0.7 0.77 0.798 0.84 0.812 0.7
酉 辛 1.0 1.14 1.0 1.0 1.1 1.06 1.0 1.1 1.14 1.2 1.16 1.0
戌 辛 0.3 0.342 0.3 0.3 0.33 0.318 0.3 0.33 0.342 0.36 0.348 0.3
戌 丁 0.2 0.2 0.24 0.24 0.212 0.228 0.24 0.22 0.2 0.2 0.208 0.212
戌 戊 0.5 0.55 0.53 0.5 0.55 0.57 0.6 0.58 0.5 0.5 0.57 0.5
亥 甲 0.36 0.318 0.342 0.36 0.33 0.3 0.3 0.312 0.318 0.3 0.3 0.36
亥 壬 0.84 0.77 0.7 0.7 0.728 0.742 0.7 0.7 0.84 0.84 0.724 0.798
*/
struct ZISTRENGTH
{
public char diZhi;
public char zhiCang;
public double[] strength;
public ZISTRENGTH(char a, char b, double[] c)
{
diZhi = a; zhiCang = b; strength = c;
}
};
ZISTRENGTH[] DiZhi_Strength = new ZISTRENGTH[]
{
new ZISTRENGTH ('子', '癸', new double[] {1.2,1.1, 1.0, 1.0, 1.04, 1.06, 1.0,1.0, 1.2, 1.2, 1.06, 1.14}),
new ZISTRENGTH('醜', '癸', new double[] {0.36,0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36, 0.36, 0.318, 0.342}),
new ZISTRENGTH('醜', '辛', new double[] {0.2,0.228, 0.2, 0.2, 0.23, 0.212, 0.2, 0.22,0.228, 0.248, 0.232, 0.2}),
new ZISTRENGTH('醜', '己',new double[] {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),
new ZISTRENGTH('寅', '丙', new double[] {0.3,0.3, 0.36, 0.36, 0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.342, 0.318}),
new ZISTRENGTH('寅', '甲',new double[] {0.84,0.742, 0.798, 0.84, 0.77, 0.7, 0.7, 0.728, 0.742, 0.7, 0.7, 0.84}),
new ZISTRENGTH('卯', '乙', new double[] {1.2,1.06, 1.14, 1.2, 1.1, 1.0, 1.0, 1.04, 1.06, 1.0, 1.0, 1.2}),
new ZISTRENGTH('辰', '乙',new double[] {0.36,0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36}),
new ZISTRENGTH('辰', '癸', new double[] {0.24,0.22, 0.2, 0.2, 0.208, 0.2, 0.2, 0.2,0.24, 0.24, 0.212, 0.228}),
new ZISTRENGTH('辰', '戊',new double[] {0.5,0.55, 0.53, 0.5, 0.55, 0.6, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),
new ZISTRENGTH('巳', '庚', new double[] {0.3,0.342, 0.3, 0.3, 0.33, 0.3, 0.3, 0.33, 0.342, 0.36, 0.348, 0.3}),
new ZISTRENGTH('巳', '丙', new double[] {0.7,0.7, 0.84, 0.84, 0.742, 0.84, 0.84, 0.798, 0.7, 0.7, 0.728, 0.742}),
new ZISTRENGTH('午', '丁', new double[] {1.0,1.0, 1.2, 1.2, 1.06, 1.14, 1.2, 1.1, 1.0, 1.0, 1.04, 1.06}),
new ZISTRENGTH('未', '丁', new double[] {0.3,0.3, 0.36, 0.36, 0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318}),
new ZISTRENGTH('未', '乙',new double[] {0.24,0.212, 0.228, 0.24, 0.22, 0.2, 0.2, 0.208, 0.212, 0.2, 0.2, 0.24}),
new ZISTRENGTH('未', '己', new double[] {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),
new ZISTRENGTH('申', '壬', new double[] {0.36,0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36, 0.36, 0.318, 0.342}),
new ZISTRENGTH('申', '庚',new double[] {0.7,0.798, 0.7, 0.7, 0.77, 0.742, 0.7, 0.77, 0.798, 0.84, 0.812, 0.7}),
new ZISTRENGTH('酉', '辛',new double[] {1.0,1.14, 1.0, 1.0, 1.1, 1.06, 1.0, 1.1, 1.14, 1.2, 1.16, 1.0}),
new ZISTRENGTH('戌', '辛',new double[] {0.3,0.342, 0.3, 0.3, 0.33, 0.318, 0.3, 0.33, 0.342, 0.36, 0.348, 0.3}),
new ZISTRENGTH('戌', '丁', new double[] {0.2,0.2, 0.24, 0.24, 0.212, 0.228, 0.24, 0.22, 0.2, 0.2, 0.208, 0.212}),
new ZISTRENGTH('戌', '戊',new double[] {0.5,0.55, 0.53, 0.5, 0.55, 0.57, 0.6, 0.58, 0.5, 0.5, 0.57, 0.5}),
new ZISTRENGTH('亥', '甲',new double[] {0.36,0.318, 0.342, 0.36, 0.33, 0.3, 0.3, 0.312, 0.318, 0.3, 0.3, 0.36}),
new ZISTRENGTH('亥', '壬',new double[] {0.84,0.77, 0.7, 0.7, 0.728, 0.742, 0.7, 0.7, 0.84, 0.84, 0.724, 0.798})
};
/*
金 --- 0
木 --- 1
水 --- 2
火 --- 3
土 --- 4
*/
char[] WuXingTable = new char[] { '金', '木', '水', '火', '土' };
/*
天干地支的五行屬性表
天干: 甲-木、乙-木、丙-火、丁-火、戊-土、己-土、庚-金、辛-金、壬-水、癸-水
地支:子-水、醜-土、寅-木、卯-木、辰-土、巳-火、午-火、未-土、申-金、酉-金、戌-土、亥-水
*/
int[] TianGan_WuXingProp = new int[10] { 1, 1, 3, 3, 4, 4, 0, 0, 2, 2 };
int[] DiZhi_WuXingProp = new int[12] { 2, 4, 1, 1, 4, 3, 3, 4, 0, 0, 4, 2 };
int[] GenerationSourceTable = new int[5] { 4, 2, 0, 1, 3 };
int ComputeGanIndex(char gan)
{
int i;
for (i = 0; i < 10; i++)
if (TianGan[i] == gan) break;
if (i >= 10) return -1;
return i;
}
int ComputeZhiIndex(char zhi)
{
int i;
for (i = 0; i < 12; i++)
if (DiZhi[i] == zhi) break;
if (i >= 12) return -1;
return i;
}
static string sResultBuf; // 用作八字測算結果返回的字符緩衝區
// 根據八字計算五行平衡
// 輸入參數:bazi,年月日時的干支,即俗稱的八字
// 輸出結果:分析結果字符串,Unicode編碼
public string EvalBazi(string bazi)
{
double[] strengthResult = new double[5];
int monthIndex = ComputeZhiIndex(bazi[3]);
if (monthIndex == -1) return "";
sResultBuf = bazi;
sResultBuf += "\n\n五行強度:天干 + 支藏\n";
for (int wuXing = 0; wuXing < 5; wuXing++)
{
double value1 = 0.0, value2 = 0.0;
int i;
//掃描4個天干
for (i = 0; i < 8; i += 2)
{
char gan = bazi[i];
int index = ComputeGanIndex(gan);
if (index == -1) return "";
if (TianGan_WuXingProp[index] == wuXing)
value1 += TianGan_Strength[monthIndex][index];
}
//掃描支藏
for (i = 1; i < 8; i += 2)
{
char zhi = bazi[i];
for (int j = 0; j < DiZhi_Strength.Length; j++)
{
if (DiZhi_Strength[j].diZhi == zhi)
{
int zhiCangIndex = ComputeGanIndex(DiZhi_Strength[j].zhiCang);
if (zhiCangIndex == -1) return "";
if (TianGan_WuXingProp[zhiCangIndex] == wuXing)
{
value2 += DiZhi_Strength[j].strength[monthIndex];
break;
}
}
}
}
strengthResult[wuXing] = value1 + value2;
//輸出一行計算結果
{
string preStr;
string tmpBuf;
tmpBuf = value1.ToString("0.00") + " + " + value2.ToString("0.00") + " = " + (value1 + value2).ToString("0.00") + "\n";
preStr = WuXingTable[wuXing] + ":\t";
sResultBuf += preStr;
sResultBuf += tmpBuf;
}
}
//根據日干求命裏屬性
int fateProp, srcProp;
{
string tmpWBuf;
fateProp = TianGan_WuXingProp[ComputeGanIndex(bazi[4])];
if (fateProp == -1) return "";
tmpWBuf = "\n命屬" + WuXingTable[fateProp] + "\n\n";
sResultBuf += tmpWBuf;
}
//求同類和異類的強度值
srcProp = GenerationSourceTable[fateProp];
{
string preStr;
string tmpBuf;
double tongLei = strengthResult[fateProp] + strengthResult[srcProp];
double yiLei = 0.0;
for (int i = 0; i < 5; i++) yiLei += strengthResult[i];
yiLei -= tongLei;
tmpBuf = strengthResult[fateProp].ToString("0.00") + " + " + strengthResult[srcProp].ToString("0.00") + " = " + tongLei.ToString("0.00") + "\n";
preStr = "同類:" + WuXingTable[fateProp] + "+" + WuXingTable[srcProp] + ",";
sResultBuf += preStr;
sResultBuf += tmpBuf;
tmpBuf = yiLei.ToString("0.00") + "\n";
sResultBuf += "異類:總和爲 " + tmpBuf;
}
return sResultBuf;
}
}
注:原作c代碼裏面對於hour小時的範圍有個前後矛盾,這裏加了一句if (hour > 22) hour -= 24;來匹配範圍。
這個方法需要先去比如nongli.net查詢八字的前6字,也就是年月子對應的天干和地支,這個查萬年曆當然是很容易的,不過也可以用代碼的形式輸入年月日就自動得到這前6字,然後調用本篇的代碼算出五行。至於得到前6字的算法大家可以研究nongli.net的js代碼然後改寫成C#代碼,這個大家可以自己嘗試哈。能做到自動生成的話,其實本篇的CheckBazi()函數就不需要了。
值得一提的是,本篇的c語言轉成c#還是簡單的,其實js轉成c#也是簡單的,不過有些時間函數C#並沒有一一對應的,這裏講解兩個關鍵的。
在JS裏面的Date.UTC(1900,0,6,2,5)這個函數在C#是沒有對應的,所以需要自己寫,需要注意的是此函數的月份範圍是0~11而不是1-12,所以在用C#的datetime來表示的時候,月份需要+1,另外就是時區的問題,中國在東8區,所以正常情況下你的電腦設置的時區也是東8區的北京時間的話,在做轉換的時候需要考慮這個問題。UTC返回的可以用double變量來存,用int是不夠的切記。
還有new Date( Date.UTC(1900,0,6,2,5) )這個函數會把計算的UTC數值再轉化成日期並取出天的數值,需要寫另外一個C#函數來實現,下面是代碼。
public double ConvertDateTimeInt(System.DateTime time)
{
double intResult = 0;
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
time = time.AddHours(8);//轉化爲北京時間(北京時間=UTC時間+8小時 )
intResult = (time - startTime).TotalMilliseconds;
return intResult;
}
public DateTime ConvertIntDatetime(double utc)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
startTime = startTime.AddMilliseconds(utc);
startTime = startTime.AddHours(-8);//轉化爲北京時間(北京時間=UTC時間+8小時 )
return startTime;
}
這裏面的addHours的8和-8都是實際測試驗證的。有了上面2個函數,要計算八字就不難了。