V43.Full_Sync
Booting...
↻
拆补法 (Chai Bu)
置润法 (Zhi Run)
正在初始化...
定位状态:
初始化...
--
--
--
|
--
符头:
--
--
积日:
--
(超神>9天且逢二至前需置润)
局数:
--
月将:
--
值符:
--
值使:
--
真黄经:
--
斗柄:
--
时差(EOT):
--
Meeus Algorithm
--
正在读取本地算法库...
Step 1: 启动...
packages = []
import js import micropip import asyncio import datetime import math import json def log(msg): try: js.document.getElementById('log-msg').innerText = msg except: pass async def init_engine(): try: file_url = "./lunar_python-1.4.8-py3-none-any.whl" log(f"Step 2: 加载文件 {file_url}...") await micropip.install(file_url) log("Step 3: 导入模块...") global Lunar, Solar, JieQi from lunar_python import Lunar, Solar, JieQi log("Step 4: 就绪!") js.window.init_complete() except Exception as e: log("❌ 加载失败") js.window.show_error(f"本地文件加载失败: {str(e)}") asyncio.ensure_future(init_engine()) GAN = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"] ZHI = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"] STARS = ['', '天蓬', '天芮', '天冲', '天辅', '天禽', '天心', '天柱', '天任', '天英'] DOORS = ['', '休门', '死门', '伤门', '杜门', '', '开门', '惊门', '生门', '景门'] GODS = ['值符', '螣蛇', '太阴', '六合', '白虎', '玄武', '九地', '九天'] JU_MAP = {'冬至':[1,7,4], '小寒':[2,8,5], '大寒':[3,9,6], '立春':[8,5,2], '雨水':[9,6,3], '惊蛰':[1,7,4], '春分':[3,9,6], '清明':[4,1,7], '谷雨':[5,2,8], '立夏':[4,1,7], '小满':[5,2,8], '芒种':[6,3,9], '夏至':[9,3,6], '小暑':[8,2,5], '大暑':[7,1,4], '立秋':[2,5,8], '处暑':[1,4,7], '白露':[9,3,6], '秋分':[7,1,4], '寒露':[6,9,3], '霜降':[5,8,2], '立冬':[6,9,3], '小雪':[5,8,2], '大雪':[4,7,1]} class PreciseAstronomy: @staticmethod def get_lon(dt): y, m, d = dt.year, dt.month, dt.day h = dt.hour + dt.minute/60.0 + dt.second/3600.0 if m <= 2: y -= 1; m += 12 A = int(y / 100) B = 2 - A + int(A / 4) JD = int(365.25 * (y + 4716)) + int(30.6001 * (m + 1)) + d + h / 24.0 + B - 1524.5 T = (JD - 2451545.0) / 36525.0 L0 = 280.46646 + 36000.76983 * T + 0.0003032 * T**2 L0 = L0 % 360 M = 357.52911 + 35999.05029 * T - 0.0001537 * T**2 M_rad = math.radians(M) C = (1.914602 - 0.004817 * T - 0.000014 * T**2) * math.sin(M_rad) + \ (0.019993 - 0.000101 * T) * math.sin(2 * M_rad) + \ 0.000289 * math.sin(3 * M_rad) true_lon = L0 + C return true_lon % 360.0 class QimenEngine: def _get_yuan_by_zhi(self, zhi_str): if zhi_str in ['子', '午', '卯', '酉']: return 0 elif zhi_str in ['寅', '申', '巳', '亥']: return 1 return 2 def _calculate_futou(self, lunar): gz = lunar.getEightChar() day_gan = gz.getDayGan() day_zhi = gz.getDayZhi() day_gan_idx = GAN.index(day_gan) day_zhi_idx = ZHI.index(day_zhi) offset = day_gan_idx % 5 futou_zhi_idx = (day_zhi_idx - offset) % 12 futou_zhi = ZHI[futou_zhi_idx] futou_gan = '甲' if day_gan_idx < 5 else '己' return futou_gan + futou_zhi, futou_zhi def _get_strict_jieqi(self, lunar, current_dt): prev = lunar.getPrevJieQi(True) p_solar = prev.getSolar() p_dt = datetime.datetime(p_solar.getYear(), p_solar.getMonth(), p_solar.getDay(), p_solar.getHour(), p_solar.getMinute(), p_solar.getSecond()) if current_dt < p_dt: return lunar.getPrevJieQi(False) return prev def _get_synced_eight_char(self, current_dt, strict_term_obj): try: ts = strict_term_obj.getSolar() safe_solar = Solar.fromYmdHms(ts.getYear(), ts.getMonth(), ts.getDay(), ts.getHour(), ts.getMinute(), ts.getSecond()) safe_lunar = safe_solar.getLunar() safe_gz = safe_lunar.getEightChar() user_solar = Solar.fromYmdHms(current_dt.year, current_dt.month, current_dt.day, current_dt.hour, current_dt.minute, current_dt.second) user_lunar = user_solar.getLunar() user_gz = user_lunar.getEightChar() return { "year": safe_gz.getYear(), "month": safe_gz.getMonth(), "day": user_gz.getDay(), "time": user_gz.getTime(), "time_gan": user_gz.getTimeGan(), "time_zhi": user_gz.getTimeZhi() } except: user_solar = Solar.fromYmdHms(current_dt.year, current_dt.month, current_dt.day, current_dt.hour, current_dt.minute, current_dt.second) ugz = user_solar.getLunar().getEightChar() return { "year": ugz.getYear(), "month": ugz.getMonth(), "day": ugz.getDay(), "time": ugz.getTime(), "time_gan": ugz.getTimeGan(), "time_zhi": ugz.getTimeZhi() } def run(self, year, month, day, hour, minute, lat, lon, method): try: dt_obj = datetime.datetime(year, month, day, hour, minute) doy = dt_obj.timetuple().tm_yday b = (2 * math.pi / 365.24) * (doy - 81) eot = 9.87 * math.sin(2*b) - 7.53 * math.cos(b) - 1.5 * math.sin(b) tst = dt_obj + datetime.timedelta(minutes=eot + (lon-120)*4) solar = Solar.fromYmdHms(tst.year, tst.month, tst.day, tst.hour, tst.minute, 0) lunar = solar.getLunar() strict_term_obj = self._get_strict_jieqi(lunar, dt_obj) if method == 'zhirun': params = self._get_zhirun_params(lunar, dt_obj, strict_term_obj) else: params = self._get_chaibu_params(lunar, strict_term_obj) final_term = params['term_name'] ju = params['ju_num'] yuan = params['yuan'] extra = params['extra_info'] sync_gz = self._get_synced_eight_char(dt_obj, strict_term_obj) final_ganzhi_str = f"{sync_gz['year']}年 {sync_gz['month']}月 {sync_gz['day']}日 {sync_gz['time']}时" real_yang = final_term in ['冬至','小寒','大寒','立春','雨水','惊蛰','春分','清明','谷雨','立夏','小满','芒种'] stems_order = ['戊', '己', '庚', '辛', '壬', '癸', '丁', '丙', '乙'] # 1. 地盘 dp = {} for i, s in enumerate(stems_order): pos = ((ju - 1 + i) % 9) + 1 if real_yang else ((ju - 1 - i) % 9) + 1 if pos <= 0: pos += 9 dp[pos] = s # 2. 旬首 h_gan, h_zhi = sync_gz['time_gan'], sync_gz['time_zhi'] h_zhi_idx = ZHI.index(h_zhi) head_offset = (h_zhi_idx - GAN.index(h_gan)) % 12 xun_map = {0:'戊', 10:'己', 8:'庚', 6:'辛', 4:'壬', 2:'癸'} xun_gan = xun_map.get(head_offset, '戊') pos_xun = 1 for p, s in dp.items(): if s == xun_gan: pos_xun = p; break zhifu_star = STARS[pos_xun] zhishi_door = DOORS[pos_xun] if pos_xun != 5 else "死门" # 3. 天盘与八神 (转盘路径) path = [1, 8, 3, 4, 9, 2, 7, 6] full_grid = {i: {"stem_d": dp.get(i, ""), "stem_t": "", "star": "", "door": "", "god": ""} for i in range(1, 10)} target_stem = h_gan if h_gan != '甲' else xun_gan pos_sky_dest = 1 for p, s in dp.items(): if s == target_stem: pos_sky_dest = p; break if pos_sky_dest == 5: pos_sky_dest = 2 try: start_idx = path.index(pos_sky_dest) except: start_idx = 0 # 八神 for i in range(8): p_idx = (start_idx + i) % 8 if real_yang else (start_idx - i) % 8 full_grid[path[p_idx]]["god"] = GODS[i] # 九星转动 target_star_name = "天芮" if zhifu_star == "天禽" else zhifu_star base_stars = ["天蓬","天任","天冲","天辅","天英","天芮","天柱","天心"] star_to_ori = {"天蓬":1, "天任":8, "天冲":3, "天辅":4, "天英":9, "天芮":2, "天柱":7, "天心":6} try: s_idx = base_stars.index(target_star_name) except: s_idx = 0 for i in range(8): curr_star = base_stars[(s_idx + i) % 8] curr_palace = path[(start_idx + i) % 8] full_grid[curr_palace]["star"] = curr_star + "(禽)" if curr_star == "天芮" else curr_star orig_p = star_to_ori.get(curr_star) sky_gan = dp.get(orig_p, "") if orig_p == 2: sky_gan += dp.get(5, "") # 携带中五干 full_grid[curr_palace]["stem_t"] = sky_gan # 4. 门盘修正 (值使行走算法) step_count = (h_zhi_idx - head_offset) % 12 curr_door_pos = pos_xun for _ in range(step_count): if real_yang: curr_door_pos = (curr_door_pos % 9) + 1 else: curr_door_pos = 9 if curr_door_pos == 1 else curr_door_pos - 1 if curr_door_pos == 5: curr_door_pos = 2 base_doors_order = ["休门","生门","伤门","杜门","景门","死门","惊门","开门"] try: ori_door_idx = base_doors_order.index(zhishi_door) except: ori_door_idx = base_doors_order.index("死门") try: d_idx = path.index(curr_door_pos) except: d_idx = 5 for i in range(8): full_grid[path[(d_idx + i) % 8]]["door"] = base_doors_order[(ori_door_idx + i) % 8] slon = PreciseAstronomy.get_lon(tst) dubhe = (slon + 90.0) % 360.0 jiang_idx = (10 - int(slon / 30)) % 12 return json.dumps({ "lunar": f"农历 {lunar.getMonthInChinese()}月{lunar.getDayInChinese()}", "ganzhi": final_ganzhi_str, "jieqi": f"{final_term}", "exact_jieqi": f"基准节气: {strict_term_obj.getSolar().toYmdHms()}", "kongwang": f"日空:{lunar.getDayXunKong()} 时空:{lunar.getTimeXunKong()}", "info": { "lon": f"{slon:.2f}°", "dubhe": f"{dubhe:.2f}°", "eot": f"{eot:.1f}m", "coords": f"{lat:.2f}, {lon:.2f}" }, "ju": { "name": f"{'阳' if real_yang else '阴'}遁{ju}局 {['上','中','下'][yuan]}元", "zhifu": zhifu_star, "zhishi": zhishi_door, "jiang": ZHI[jiang_idx] + "将" }, "grid": full_grid, "zhirun_info": extra }) except Exception as e: import traceback return json.dumps({"error": f"{str(e)}\n{traceback.format_exc()}"}) def _get_chaibu_params(self, lunar, strict_term_obj): stn = strict_term_obj.getName() ft_gz, ft_zhi = self._calculate_futou(lunar) yuan = self._get_yuan_by_zhi(ft_zhi) if stn not in JU_MAP: stn = '冬至' return {"term_name": stn, "ju_num": JU_MAP[stn][yuan], "yuan": yuan, "extra_info": None} def _get_zhirun_params(self, lunar, current_dt, strict_term_obj): ft_gz, ft_zhi = self._calculate_futou(lunar) gz = lunar.getEightChar() offset = GAN.index(gz.getDayGan()) % 5 ft_dt = (current_dt - datetime.timedelta(days=offset)).replace(hour=0, minute=0, second=0, microsecond=0) jsl = strict_term_obj.getSolar() jdt = datetime.datetime(jsl.getYear(), jsl.getMonth(), jsl.getDay(), jsl.getHour(), jsl.getMinute(), jsl.getSecond()) dd = (jdt - ft_dt).total_seconds() / 86400.0 is_cs = dd > 0 ad = abs(dd) utn = strict_term_obj.getName() isl = False if is_cs and ad > 9: if utn == '夏至': utn = '芒种'; isl = True elif utn == '冬至': utn = '大雪'; isl = True yuan = self._get_yuan_by_zhi(ft_zhi) if utn not in JU_MAP: utn = '冬至' return {"term_name": utn, "ju_num": JU_MAP[utn][yuan], "yuan": yuan, "extra_info": {"futou": ft_gz, "chaoshen": is_cs, "days": f"{ad:.1f}", "leaping": isl, "raw_term": strict_term_obj.getName()}} engine = QimenEngine() def python_entry(y, m, d, h, minute, lat, lon, method): res_str = engine.run(int(y), int(m), int(d), int(h), int(minute), float(lat), float(lon), str(method)) js.render_result(res_str) js.window.python_entry = python_entry