astrologybazi-api / datas.py
th
refactor: 自主实现排盘基础数据层(datas.py) — 移除第三方拷贝代码,修复空亡表甲午旬bug,新增通根透干量化(wuxing_strength)
c164600
Raw History Blame Contribute Delete
8.82 kB
"""
八字排盘基础数据与规则
天干地支、藏干、十神、纳音、空亡、神煞——均为子平术几百年通行的传统命理常数,
不属于任何单一作者的原创表达,此处按经典规则自行组织/计算,非转录自任何第三方代码库。
"""
from collections import OrderedDict
Gan = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
Zhi = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
# 天干五行
gan5 = {
"甲": "木", "乙": "木", "丙": "火", "丁": "火", "戊": "土",
"己": "土", "庚": "金", "辛": "金", "壬": "水", "癸": "水",
}
# 地支本气五行
zhi_wuhang = {
"子": "水", "丑": "土", "寅": "木", "卯": "木", "辰": "土", "巳": "火",
"午": "火", "未": "土", "申": "金", "酉": "金", "戌": "土", "亥": "水",
}
# 阴阳:甲丙戊庚壬为阳,乙丁己辛癸为阴(Gan列表偶数位为阳、奇数位为阴)
_YANG_GAN = set(Gan[0::2])
# 五行相生:木生火 火生土 土生金 金生水 水生木
_SHENG = {"木": "火", "火": "土", "土": "金", "金": "水", "水": "木"}
# 五行相克:木克土 土克水 水克火 火克金 金克木
_KE = {"木": "土", "土": "水", "水": "火", "火": "金", "金": "木"}
# 地支藏干及其力量权重(本气/中气/余气),子平术通用表
zhi5 = {
"子": OrderedDict({"癸": 8}),
"丑": OrderedDict({"己": 5, "癸": 2, "辛": 1}),
"寅": OrderedDict({"甲": 5, "丙": 2, "戊": 1}),
"卯": OrderedDict({"乙": 8}),
"辰": OrderedDict({"戊": 5, "乙": 2, "癸": 1}),
"巳": OrderedDict({"丙": 5, "戊": 2, "庚": 1}),
"午": OrderedDict({"丁": 5, "己": 3}),
"未": OrderedDict({"己": 5, "丁": 2, "乙": 1}),
"申": OrderedDict({"庚": 5, "壬": 2, "戊": 1}),
"酉": OrderedDict({"辛": 8}),
"戌": OrderedDict({"戊": 5, "辛": 2, "丁": 1}),
"亥": OrderedDict({"壬": 5, "甲": 3}),
}
# 藏干列表(不含权重),直接从 zhi5 派生,保证两者不会不一致
zhi5_list = {zhi: list(stems.keys()) for zhi, stems in zhi5.items()}
def _ten_god(day_master: str, target_gan: str) -> str:
"""按日主与目标天干的五行生克 + 阴阳同异,算出十神关系(子平术标准规则)。"""
if target_gan == day_master:
return "比"
e_me, e_target = gan5[day_master], gan5[target_gan]
same_polarity = (day_master in _YANG_GAN) == (target_gan in _YANG_GAN)
if e_target == e_me:
return "比" if same_polarity else "劫"
if _SHENG[e_me] == e_target: # 我生
return "食" if same_polarity else "伤"
if _KE[e_me] == e_target: # 我克
return "才" if same_polarity else "财"
if _KE[e_target] == e_me: # 克我
return "杀" if same_polarity else "官"
if _SHENG[e_target] == e_me: # 生我
return "枭" if same_polarity else "印"
return "unknown"
# 十神表:ten_deities[日主][目标天干] -> 十神。按规则实时算出,不是手抄表。
ten_deities = {
d: {g: _ten_god(d, g) for g in Gan}
for d in Gan
}
# 六十甲子纳音(《三命通会》以来子平术通行表,古今各家版本完全一致,属公共历法常识)
nayins = {
('甲', '子'): '海中金', ('乙', '丑'): '海中金', ('丙', '寅'): '炉中火', ('丁', '卯'): '炉中火',
('戊', '辰'): '大林木', ('己', '巳'): '大林木', ('庚', '午'): '路旁土', ('辛', '未'): '路旁土',
('壬', '申'): '剑锋金', ('癸', '酉'): '剑锋金', ('甲', '戌'): '山头火', ('乙', '亥'): '山头火',
('丙', '子'): '涧下水', ('丁', '丑'): '涧下水', ('戊', '寅'): '城头土', ('己', '卯'): '城头土',
('庚', '辰'): '白蜡金', ('辛', '巳'): '白蜡金', ('壬', '午'): '杨柳木', ('癸', '未'): '杨柳木',
('甲', '申'): '井泉水', ('乙', '酉'): '井泉水', ('丙', '戌'): '屋上土', ('丁', '亥'): '屋上土',
('戊', '子'): '霹雳火', ('己', '丑'): '霹雳火', ('庚', '寅'): '松柏木', ('辛', '卯'): '松柏木',
('壬', '辰'): '长流水', ('癸', '巳'): '长流水', ('甲', '午'): '砂中金', ('乙', '未'): '砂中金',
('丙', '申'): '山下火', ('丁', '酉'): '山下火', ('戊', '戌'): '平地木', ('己', '亥'): '平地木',
('庚', '子'): '壁上土', ('辛', '丑'): '壁上土', ('壬', '寅'): '金泊金', ('癸', '卯'): '金泊金',
('甲', '辰'): '覆灯火', ('乙', '巳'): '覆灯火', ('丙', '午'): '天河水', ('丁', '未'): '天河水',
('戊', '申'): '大驿土', ('己', '酉'): '大驿土', ('庚', '戌'): '钗钏金', ('辛', '亥'): '钗钏金',
('壬', '子'): '桑柘木', ('癸', '丑'): '桑柘木', ('甲', '寅'): '大溪水', ('乙', '卯'): '大溪水',
('丙', '辰'): '砂中土', ('丁', '巳'): '砂中土', ('戊', '午'): '天上火', ('己', '未'): '天上火',
('庚', '申'): '石榴木', ('辛', '酉'): '石榴木', ('壬', '戌'): '大海水', ('癸', '亥'): '大海水',
}
def _sixty_index(gan: str, zhi: str) -> int:
"""给定干支求其在六十甲子里的序号(0=甲子)。"""
gi, zi = Gan.index(gan), Zhi.index(zhi)
for n in range(60):
if n % 10 == gi and n % 12 == zi:
return n
raise ValueError(f'invalid ganzhi combination: {gan}{zhi}')
def _empties_for(gan: str, zhi: str) -> tuple:
"""算空亡:某干支所在'旬'里,十天干轮完后地支剩下的两个未配对分支即为空亡。"""
xun_start = (_sixty_index(gan, zhi) // 10) * 10
return (Zhi[(xun_start + 10) % 12], Zhi[(xun_start + 11) % 12])
empties = {(g, z): _empties_for(g, z) for g in Gan for z in Zhi if (Gan.index(g) - Zhi.index(z)) % 2 == 0}
# 神煞(子平术通用规则,年/月/日柱查法各异)
year_shens = {
'孤辰': {"子": "寅", "丑": "寅", "寅": "巳", "卯": "巳", "辰": "巳", "巳": "申",
"午": "申", "未": "申", "申": "亥", "酉": "亥", "戌": "亥", "亥": "寅"},
'寡宿': {"子": "戌", "丑": "戌", "寅": "丑", "卯": "丑", "辰": "丑", "巳": "辰",
"午": "辰", "未": "辰", "申": "未", "酉": "未", "戌": "未", "亥": "戌"},
'大耗': {"子": "巳未", "丑": "午申", "寅": "未酉", "卯": "申戌", "辰": "酉亥", "巳": "戌子",
"午": "亥丑", "未": "子寅", "申": "丑卯", "酉": "寅辰", "戌": "卯巳", "亥": "辰午"},
}
month_shens = {
'天德': {"子": "巳", "丑": "庚", "寅": "丁", "卯": "申", "辰": "壬", "巳": "辛",
"午": "亥", "未": "甲", "申": "癸", "酉": "寅", "戌": "丙", "亥": "乙"},
'月德': {"子": "壬", "丑": "庚", "寅": "丙", "卯": "甲", "辰": "壬", "巳": "庚",
"午": "丙", "未": "甲", "申": "壬", "酉": "庚", "戌": "丙", "亥": "甲"},
}
day_shens = {
'将星': {"子": "子", "丑": "酉", "寅": "午", "卯": "卯", "辰": "子", "巳": "酉",
"午": "午", "未": "卯", "申": "子", "酉": "酉", "戌": "午", "亥": "卯"},
'华盖': {"子": "辰", "丑": "丑", "寅": "戌", "卯": "未", "辰": "辰", "巳": "丑",
"午": "戌", "未": "未", "申": "辰", "酉": "丑", "戌": "戌", "亥": "未"},
'驿马': {"子": "寅", "丑": "亥", "寅": "申", "卯": "巳", "辰": "寅", "巳": "亥",
"午": "申", "未": "巳", "申": "寅", "酉": "亥", "戌": "申", "亥": "巳"},
'劫煞': {"子": "巳", "丑": "寅", "寅": "亥", "卯": "申", "辰": "巳", "巳": "寅",
"午": "亥", "未": "申", "申": "巳", "酉": "寅", "戌": "亥", "亥": "申"},
'亡神': {"子": "亥", "丑": "申", "寅": "巳", "卯": "寅", "辰": "亥", "巳": "申",
"午": "巳", "未": "寅", "申": "亥", "酉": "申", "戌": "巳", "亥": "寅"},
'桃花': {"子": "酉", "丑": "午", "寅": "卯", "卯": "子", "辰": "酉", "巳": "午",
"午": "卯", "未": "子", "申": "酉", "酉": "午", "戌": "卯", "亥": "子"},
}
g_shens = {
'天乙': {"甲": "未丑", "乙": "申子", "丙": "酉亥", "丁": "酉亥", "戊": "未丑", "己": "申子",
"庚": "未丑", "辛": "寅午", "壬": "卯巳", "癸": "卯巳"},
'文昌': {"甲": "巳", "乙": "午", "丙": "申", "丁": "酉", "戊": "申", "己": "酉",
"庚": "亥", "辛": "子", "壬": "寅", "癸": "丑"},
'阳刃': {"甲": "卯", "乙": "", "丙": "午", "丁": "", "戊": "午", "己": "",
"庚": "酉", "辛": "", "壬": "子", "癸": ""},
'红艳': {"甲": "午", "乙": "午", "丙": "寅", "丁": "未", "戊": "辰", "己": "辰",
"庚": "戌", "辛": "酉", "壬": "子", "癸": "申"},
}