sunhonghua's picture
Upload 54 files
e4efb8a verified
Raw
History Blame Contribute Delete
7.23 kB
from modules.qimen_interpreter import QiMenInterpreter
class QiMen:
"""
奇门遁甲核心算法类
实现定局、排盘(九星、八门、八神、天干)并集成占断解释
"""
TERM_JU = {
'冬至': (1, [1, 7, 4]), '小寒': (1, [2, 8, 5]), '大寒': (1, [3, 9, 6]),
'立春': (1, [8, 5, 2]), '雨水': (1, [9, 6, 3]), '惊蛰': (1, [1, 7, 4]),
'春分': (1, [3, 9, 6]), '清明': (1, [4, 1, 7]), '谷雨': (1, [5, 2, 8]),
'立夏': (1, [4, 1, 7]), '小满': (1, [5, 2, 8]), '芒种': (1, [6, 3, 9]),
'夏至': (-1, [9, 3, 6]), '小暑': (-1, [8, 2, 5]), '大暑': (-1, [7, 1, 4]),
'立秋': (-1, [2, 5, 8]), '处暑': (-1, [1, 4, 7]), '白露': (-1, [9, 3, 6]),
'秋分': (-1, [7, 1, 4]), '寒露': (-1, [6, 9, 3]), '霜降': (-1, [5, 8, 2]),
'立冬': (-1, [6, 9, 3]), '小雪': (-1, [5, 8, 2]), '大雪': (-1, [4, 7, 1])
}
STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
XUN_SHOU = {'甲子': '戊', '甲戌': '己', '甲申': '庚', '甲午': '辛', '甲辰': '壬', '甲寅': '癸'}
STAR_MAP = {1: '天蓬', 2: '天芮', 3: '天冲', 4: '天辅', 5: '天禽', 6: '天心', 7: '天柱', 8: '天任', 9: '天英'}
DOOR_MAP = {1: '休门', 2: '死门', 3: '伤门', 4: '杜门', 5: '中门', 6: '开门', 7: '惊门', 8: '生门', 9: '景门'}
PALACE_BRANCHES = {
1: '子', 2: '未申', 3: '卯', 4: '辰巳',
6: '戌亥', 7: '酉', 8: '丑寅', 9: '午', 5: '中'
}
def __init__(self, lunar_data):
self.data = lunar_data
self.bazi = lunar_data['bazi'].split()
self.day_stem_branch = self.bazi[2]
self.hour_stem_branch = self.bazi[3]
def _get_ju(self):
term = self.data['solar_term']
if term not in self.TERM_JU:
# 找到最近的节气
term = '冬至'
is_yang, ju_list = self.TERM_JU[term]
return is_yang, ju_list[0]
def _get_xun_shou(self):
stem_idx = self.STEMS.index(self.hour_stem_branch[0])
branch_idx = self.BRANCHES.index(self.hour_stem_branch[1])
xun_idx = (branch_idx - stem_idx) % 12
xun_map = {0: '甲子', 10: '甲戌', 8: '甲申', 6: '甲午', 4: '甲辰', 2: '甲寅'}
xun_head = xun_map.get(xun_idx, '甲子')
return xun_head, self.XUN_SHOU[xun_head]
def _get_earth_pan(self, is_yang, ju_num):
loop = ['戊', '己', '庚', '辛', '壬', '癸', '丁', '丙', '乙']
pan = [""] * 10
for i, stem in enumerate(loop):
pos = (ju_num + i - 1) % 9 + 1 if is_yang == 1 else (ju_num - i - 1) % 9 + 1
if pos <= 0: pos += 9
pan[pos] = stem
return pan[1:]
def _get_duty(self, earth_pan, helper_stem):
original_palace = earth_pan.index(helper_stem) + 1
return original_palace, self.STAR_MAP[original_palace], self.DOOR_MAP[original_palace]
def _rotate_stars(self, duty_star, target_palace):
stars_order = ['天蓬', '天任', '天冲', '天辅', '天英', '天芮', '天柱', '天心']
palaces = [1, 8, 3, 4, 9, 2, 7, 6]
try: duty_idx = stars_order.index(duty_star)
except: duty_idx = 5
target_idx = palaces.index(target_palace) if target_palace in palaces else 5
offset = (target_idx - duty_idx) % 8
result = [""] * 10
for i in range(8):
result[palaces[(i+offset)%8]] = stars_order[i]
if result[5] == "": result[5] = "天禽"
return result[1:]
def _rotate_doors(self, is_yang, duty_door, original_palace, hour_branch):
xun_heads = {'甲子': '子', '甲戌': '戌', '甲申': '申', '甲午': '午', '甲辰': '辰', '甲寅': '寅'}
xun_head, _ = self._get_xun_shou()
diff = (self.BRANCHES.index(hour_branch) - self.BRANCHES.index(xun_heads[xun_head])) % 12
doors_order = ['休门', '生门', '伤门', '杜门', '景门', '死门', '惊门', '开门']
palaces = [1, 8, 3, 4, 9, 2, 7, 6]
curr_palace = (original_palace + diff - 1) % 9 + 1 if is_yang == 1 else (original_palace - diff - 1) % 9 + 1
if curr_palace <= 0: curr_palace += 9
try: duty_idx = doors_order.index(duty_door)
except: duty_idx = 5
target_idx = palaces.index(curr_palace) if curr_palace in palaces else 5
offset = (target_idx - duty_idx) % 8
result = [""] * 10
for i in range(8):
result[palaces[(i+offset)%8]] = doors_order[i]
return result[1:]
def generate_chart(self):
is_yang, ju_num = self._get_ju()
earth_pan = self._get_earth_pan(is_yang, ju_num)
xun_head, helper_stem = self._get_xun_shou()
orig_palace, duty_star, duty_door = self._get_duty(earth_pan, helper_stem)
hour_stem = self.hour_stem_branch[0]
# 值符随旬首
target_palace = earth_pan.index(hour_stem) + 1 if hour_stem in earth_pan else 5
stars = self._rotate_stars(duty_star, target_palace)
doors = self._rotate_doors(is_yang, duty_door, orig_palace, self.hour_stem_branch[1])
gods_order = ['值符', '腾蛇', '太阴', '六合', '白虎', '玄武', '九地', '九天']
if is_yang == -1: gods_order = ['值符', '九天', '九地', '玄武', '白虎', '六合', '太阴', '腾蛇']
palaces = [1, 8, 3, 4, 9, 2, 7, 6]
target_idx = palaces.index(target_palace) if target_palace in palaces else 5
gods = [""] * 10
for i in range(8):
gods[palaces[(i+target_idx)%8]] = gods_order[i]
# 天盘干:随九星转动,星原宫的地盘干即为现在的天盘干
heaven_pan = [""] * 10
for i in range(1, 10):
star_now = stars[i-1]
if star_now:
star_name_to_orig = {v: k for k, v in self.STAR_MAP.items()}
orig_idx = star_name_to_orig.get(star_now, 5)
heaven_pan[i] = earth_pan[orig_idx-1]
pan = []
for i in range(1, 10):
palace_data = {
"id": i,
"star": stars[i-1],
"door": doors[i-1],
"god": gods[i-1],
"earth": earth_pan[i-1],
"heaven": heaven_pan[i],
"branches": self.PALACE_BRANCHES.get(i, "")
}
# 注入占断
palace_data["interpretation"] = QiMenInterpreter.interpret_palace(palace_data)
pan.append(palace_data)
return {
"type": "阳遁" if is_yang == 1 else "阴遁",
"ju_num": ju_num,
"term": self.data['solar_term'],
"xun_head": xun_head,
"pan": pan,
"global_patterns": QiMenInterpreter.detect_global_patterns({
"pan": pan,
"xun_head": xun_head,
"is_yang": is_yang
})
}