Spaces:
Running
Running
| 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 | |
| }) | |
| } | |