#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
卦气正元历 · 丙午定本 · 完整内容紧凑版
方案B(太阳黄经驱动)· Python + Tkinter
零外部依赖 · 内置1900-2100年天文数据 · 全部卦辞详解
"""

import tkinter as tk
from tkinter import ttk, font, messagebox, simpledialog
from datetime import datetime, timedelta
from math import sin, cos, radians, pi
import json
import os

# ==================== 内置天文数据库 ====================

LICHUN_DATABASE = {
    1900: (2, 4, 20, 39), 1901: (2, 4, 2, 30), 1902: (2, 4, 8, 17), 1903: (2, 4, 14, 5),
    1904: (2, 4, 19, 53), 1905: (2, 4, 1, 46), 1906: (2, 4, 7, 34), 1907: (2, 4, 13, 21),
    1908: (2, 4, 19, 15), 1909: (2, 4, 1, 6), 1910: (2, 4, 6, 54), 1911: (2, 4, 12, 42),
    1912: (2, 4, 18, 31), 1913: (2, 4, 0, 24), 1914: (2, 4, 6, 12), 1915: (2, 4, 12, 0),
    1916: (2, 4, 17, 49), 1917: (2, 4, 23, 39), 1918: (2, 4, 5, 27), 1919: (2, 4, 11, 15),
    1920: (2, 4, 17, 8), 1921: (2, 4, 23, 0), 1922: (2, 4, 4, 49), 1923: (2, 4, 10, 37),
    1924: (2, 4, 16, 30), 1925: (2, 4, 22, 22), 1926: (2, 4, 4, 11), 1927: (2, 4, 9, 59),
    1928: (2, 4, 15, 52), 1929: (2, 4, 21, 44), 1930: (2, 4, 3, 33), 1931: (2, 4, 9, 21),
    1932: (2, 4, 15, 14), 1933: (2, 4, 21, 6), 1934: (2, 4, 2, 55), 1935: (2, 4, 8, 43),
    1936: (2, 4, 14, 36), 1937: (2, 4, 20, 28), 1938: (2, 4, 2, 17), 1939: (2, 4, 8, 5),
    1940: (2, 4, 13, 58), 1941: (2, 4, 19, 50), 1942: (2, 4, 1, 39), 1943: (2, 4, 7, 27),
    1944: (2, 4, 13, 20), 1945: (2, 4, 19, 12), 1946: (2, 4, 1, 1), 1947: (2, 4, 6, 49),
    1948: (2, 4, 12, 42), 1949: (2, 4, 18, 34), 1950: (2, 4, 0, 23), 1951: (2, 4, 6, 11),
    1952: (2, 4, 12, 4), 1953: (2, 4, 17, 56), 1954: (2, 4, 23, 45), 1955: (2, 4, 5, 33),
    1956: (2, 4, 11, 26), 1957: (2, 4, 17, 18), 1958: (2, 4, 23, 7), 1959: (2, 4, 4, 55),
    1960: (2, 4, 10, 48), 1961: (2, 4, 16, 40), 1962: (2, 4, 22, 29), 1963: (2, 4, 4, 17),
    1964: (2, 4, 10, 10), 1965: (2, 4, 16, 2), 1966: (2, 4, 21, 51), 1967: (2, 4, 3, 39),
    1968: (2, 4, 9, 32), 1969: (2, 4, 15, 24), 1970: (2, 4, 21, 13), 1971: (2, 4, 3, 1),
    1972: (2, 4, 8, 54), 1973: (2, 4, 14, 46), 1974: (2, 4, 20, 35), 1975: (2, 4, 2, 23),
    1976: (2, 4, 8, 16), 1977: (2, 4, 14, 8), 1978: (2, 4, 19, 57), 1979: (2, 4, 1, 45),
    1980: (2, 4, 7, 38), 1981: (2, 4, 13, 30), 1982: (2, 4, 19, 19), 1983: (2, 4, 1, 7),
    1984: (2, 4, 7, 0), 1985: (2, 4, 12, 52), 1986: (2, 4, 18, 41), 1987: (2, 4, 0, 29),
    1988: (2, 4, 6, 22), 1989: (2, 4, 12, 14), 1990: (2, 4, 18, 3), 1991: (2, 4, 23, 51),
    1992: (2, 4, 5, 44), 1993: (2, 4, 11, 36), 1994: (2, 4, 17, 25), 1995: (2, 4, 23, 13),
    1996: (2, 4, 5, 6), 1997: (2, 4, 10, 58), 1998: (2, 4, 16, 47), 1999: (2, 4, 22, 35),
    2000: (2, 4, 4, 28), 2001: (2, 4, 10, 20), 2002: (2, 4, 16, 9), 2003: (2, 4, 21, 57),
    2004: (2, 4, 3, 50), 2005: (2, 4, 9, 42), 2006: (2, 4, 15, 31), 2007: (2, 4, 21, 19),
    2008: (2, 4, 3, 12), 2009: (2, 4, 9, 4), 2010: (2, 4, 14, 53), 2011: (2, 4, 20, 41),
    2012: (2, 4, 2, 34), 2013: (2, 4, 8, 26), 2014: (2, 4, 14, 15), 2015: (2, 4, 20, 3),
    2016: (2, 4, 1, 56), 2017: (2, 4, 7, 48), 2018: (2, 4, 13, 37), 2019: (2, 4, 19, 25),
    2020: (2, 4, 1, 18), 2021: (2, 3, 22, 59), 2022: (2, 4, 4, 51), 2023: (2, 4, 10, 43),
    2024: (2, 4, 16, 27), 2025: (2, 3, 22, 10), 2026: (2, 4, 4, 2), 2027: (2, 4, 9, 46),
    2028: (2, 4, 15, 30), 2029: (2, 3, 21, 20), 2030: (2, 4, 3, 8), 2031: (2, 4, 8, 57),
    2032: (2, 4, 14, 49), 2033: (2, 3, 20, 33), 2034: (2, 4, 2, 24), 2035: (2, 4, 8, 13),
    2036: (2, 4, 14, 6), 2037: (2, 3, 19, 52), 2038: (2, 4, 1, 41), 2039: (2, 4, 7, 30),
    2040: (2, 4, 13, 23), 2041: (2, 3, 19, 7), 2042: (2, 4, 0, 59), 2043: (2, 4, 6, 48),
    2044: (2, 4, 12, 43), 2045: (2, 3, 18, 25), 2046: (2, 4, 0, 16), 2047: (2, 4, 6, 5),
    2048: (2, 4, 12, 0), 2049: (2, 3, 17, 44), 2050: (2, 3, 23, 35), 2051: (2, 4, 5, 24),
    2052: (2, 4, 11, 19), 2053: (2, 3, 17, 0), 2054: (2, 3, 22, 52), 2055: (2, 4, 4, 41),
    2056: (2, 4, 10, 38), 2057: (2, 3, 16, 17), 2058: (2, 3, 22, 9), 2059: (2, 4, 3, 58),
    2060: (2, 4, 9, 53), 2061: (2, 3, 15, 31), 2062: (2, 3, 21, 23), 2063: (2, 4, 3, 12),
    2064: (2, 4, 9, 9), 2065: (2, 3, 14, 46), 2066: (2, 3, 20, 38), 2067: (2, 4, 2, 27),
    2068: (2, 4, 8, 24), 2069: (2, 3, 14, 0), 2070: (2, 3, 19, 52), 2071: (2, 4, 1, 41),
    2072: (2, 4, 7, 39), 2073: (2, 3, 13, 15), 2074: (2, 3, 19, 7), 2075: (2, 4, 0, 56),
    2076: (2, 4, 6, 54), 2077: (2, 3, 12, 28), 2078: (2, 3, 18, 20), 2079: (2, 4, 0, 9),
    2080: (2, 4, 6, 9), 2081: (2, 3, 11, 41), 2082: (2, 3, 17, 33), 2083: (2, 3, 23, 22),
    2084: (2, 4, 5, 22), 2085: (2, 3, 10, 53), 2086: (2, 3, 16, 45), 2087: (2, 3, 22, 34),
    2088: (2, 4, 4, 36), 2089: (2, 3, 10, 5), 2090: (2, 3, 15, 57), 2091: (2, 3, 21, 46),
    2092: (2, 4, 3, 48), 2093: (2, 3, 9, 17), 2094: (2, 3, 15, 9), 2095: (2, 3, 20, 58),
    2096: (2, 4, 3, 0), 2097: (2, 3, 8, 29), 2098: (2, 3, 14, 21), 2099: (2, 3, 20, 10),
    2100: (2, 4, 2, 12),
}

# ==================== 核心数据 ====================

GUA_SEQUENCE = [
    "坎", "蹇", "屯", "井", "既济", "比", "节", "需",
    "艮", "颐", "蛊", "贲", "剥", "损", "大畜", "蒙",
    "震", "恒", "丰", "豫", "归妹", "大壮", "解", "小过",
    "巽", "家人", "观", "中孚", "小畜", "涣", "渐", "益",
    "离", "晋", "睽", "大有", "未济", "旅", "噬嗑", "鼎",
    "坤", "临", "泰", "师", "谦", "复", "升", "明夷",
    "兑", "夬", "困", "咸", "随", "大过", "革", "萃",
    "乾", "讼", "遁", "无妄", "姤", "同人", "否", "履"
]

BA_GUA = ["坎", "艮", "震", "巽", "离", "坤", "兑", "乾"]

# ==================== 新增:无极·太极·寒暑·四季理论体系 ====================

# 宇宙生成论(用于显示)
WUJI_TITLE = "无极——万化之源"
WUJI_DESC = """无极者,先天虚寂,混沌无象,无形无质,无始无终。
阴阳未萌,动静未兆,为太极之母、天地之根、岁时之源。
无极寂,则天地未分;无极动,则太极立生。"""

TAIJI_TITLE = "太极——岁序之根"
TAIJI_DESC = """太极者,由无极而生,阴阳初判、混沌将分,为天地万物之始,亦为一年时序之原。
太极不动,岁时不生;太极一动,阴阳分判,寒暑乃成。
太极统御全年寒暑消长,统领四季更迭,统摄八节枢纽,统贯六十四卦气流转。"""

HANSHU_TITLE = "寒暑——一岁之纲"
HANSHU_DESC = """寒暑相推,是为一年之核心节律:
• 暑为阳之极用,主长、主明、主散,起于立春,盛于夏至,消于立秋
• 寒为阴之极用,主藏、主幽、主聚,起于立秋,盛于冬至,消于立春
寒暑交替,无有间断,乃生四季,乃定八节。"""

# 四季对应表(四象)
SEASONS = [
    {"name": "春", "sixiang": "少阳", "angle": 90, "range": "春分前后3气", "desc": "阳长阴消,主生"},
    {"name": "夏", "sixiang": "老阳", "angle": 180, "range": "夏至前后3气", "desc": "阳极阴萌,主长"},
    {"name": "秋", "sixiang": "少阴", "angle": 270, "range": "秋分前后3气", "desc": "阴长阳消,主收"},
    {"name": "冬", "sixiang": "老阴", "angle": 0, "range": "冬至前后3气", "desc": "阴极阳萌,主藏"}
]

# 八节对应八卦(完整版)
JIE_NAMES = ["立春", "春分", "立夏", "夏至", "立秋", "秋分", "立冬", "冬至"]
JIE_GUA_LIST = ["艮", "震", "巽", "离", "坤", "兑", "乾", "坎"]
JIE_ANGLES = [45, 90, 135, 180, 225, 270, 315, 0]  # 天环中点角度
JIE_FANGWEI = ["东北", "正东", "东南", "正南", "西南", "正西", "西北", "正北"]
JIE_QIXIANG = ["阳动初启", "阴阳平衡", "阳盛渐布", "阳极阴萌", "阴生初敛", "阴阳平衡", "阴盛潜阳", "阴极阳萌"]

# 八节统摄范围(每节统摄8气)
JIE_RANGES = [
    (1, 8, "坎气至需气"),  # 立春
    (9, 16, "艮气至蒙气"),  # 春分
    (17, 24, "震气至小过气"),  # 立夏
    (25, 32, "巽气至益气"),  # 夏至
    (33, 40, "离气至鼎气"),  # 立秋
    (41, 48, "坤气至明夷气"),  # 秋分
    (49, 56, "兑气至萃气"),  # 立冬
    (57, 64, "乾气至履气")  # 冬至
]

# 八节到八卦的映射字典
JIE_TO_GUA = dict(zip(JIE_NAMES, JIE_GUA_LIST))

# ==================== 八刻与四时对应(一日系统)====================

# 四时(一日之四象)
DAY_SISHI = [
    {"name": "朝", "sixiang": "少阳", "time_range": "03:00-09:00", "desc": "阳始生"},
    {"name": "昼", "sixiang": "老阳", "time_range": "09:00-15:00", "desc": "阳极盛"},
    {"name": "夕", "sixiang": "少阴", "time_range": "15:00-21:00", "desc": "阴始生"},
    {"name": "夜", "sixiang": "老阴", "time_range": "21:00-03:00", "desc": "阴极盛"}
]

# 八刻详细对应(地支·八卦·方位·时间·天文释义)
KE_DETAILS = [
    {"di": "子", "gua": "坎", "fangwei": "正北", "mid": "00:00", "range": "23:00-01:00",
     "desc": "子夜寒冷,太阳隐于地球另一侧,对应天球正北"},
    {"di": "丑", "gua": "艮", "fangwei": "东北", "mid": "03:00", "range": "02:00-04:00",
     "desc": "三更半夜,太阳隐于东北方地下"},
    {"di": "卯", "gua": "震", "fangwei": "正东", "mid": "06:00", "range": "05:00-07:00",
     "desc": "日出东方,太阳在东方"},
    {"di": "辰", "gua": "巽", "fangwei": "东南", "mid": "09:00", "range": "08:00-10:00",
     "desc": "早晨升日,太阳在东南方"},
    {"di": "午", "gua": "离", "fangwei": "正南", "mid": "12:00", "range": "11:00-13:00",
     "desc": "日午炎热,太阳在南方"},
    {"di": "未", "gua": "坤", "fangwei": "西南", "mid": "15:00", "range": "14:00-16:00",
     "desc": "日晒减弱,太阳在西南方"},
    {"di": "酉", "gua": "兑", "fangwei": "正西", "mid": "18:00", "range": "17:00-19:00",
     "desc": "太阳下山,太阳在西方"},
    {"di": "戌", "gua": "乾", "fangwei": "西北", "mid": "21:00", "range": "20:00-22:00",
     "desc": "温暖降温,太阳在西北方"}
]

KE_NAMES = [f"{k['di']}-{k['gua']}" for k in KE_DETAILS]
WUXING = {"坎": "水", "艮": "土", "震": "木", "巽": "木", "离": "火", "坤": "土", "兑": "金", "乾": "金"}

# ==================== 六十四度时间边界表(一日系统)====================

# 生成规则:每度22.5分钟 = 22分30秒
DEGREE_TIMES = []
for i in range(64):
    start_minutes = i * 22.5
    end_minutes = (i + 1) * 22.5
    start_h = int(start_minutes // 60)
    start_m = int(start_minutes % 60)
    start_s = int((start_minutes % 1) * 60)
    end_h = int(end_minutes // 60) % 24
    end_m = int(end_minutes % 60)
    end_s = int((end_minutes % 1) * 60)

    DEGREE_TIMES.append({
        "num": i + 1,
        "gua": GUA_SEQUENCE[i],
        "start": f"{start_h:02d}:{start_m:02d}:{start_s:02d}",
        "end": f"{end_h:02d}:{end_m:02d}:{end_s:02d}"
    })

# ==================== 六十四气天文特征表(岁序系统)====================

# 以2026年为例的天文特征(可根据年份动态计算,这里提供静态模板)
QI_ASTRONOMY_TEMPLATE = [
    # 立春组 (1-8)
    {"num": 1, "gua": "坎", "jie": "立春", "start": "02-03 22:09", "end": "02-09 15:06",
     "sun_range": "315°~320°", "feature": "阳气始动,但寒气仍盛", "climate": "冬末春初,乍暖还寒", "solar_term": "立春后→雨水前"},
    {"num": 2, "gua": "蹇", "jie": "立春", "start": "02-09 15:06", "end": "02-15 08:04",
     "sun_range": "320°~325°", "feature": "阳气渐升,阴气渐退", "climate": "冰雪始融,地气渐通", "solar_term": "立春末期→雨水前期"},
    {"num": 3, "gua": "屯", "jie": "立春", "start": "02-15 08:04", "end": "02-21 01:02",
     "sun_range": "325°~330°", "feature": "雨水将至,草木萌动", "climate": "降水渐增,万物始生", "solar_term": "雨水(02-18)"},
    {"num": 4, "gua": "井", "jie": "立春", "start": "02-21 01:02", "end": "02-26 17:59",
     "sun_range": "330°~335°", "feature": "雨水渐盛,地气升腾", "climate": "春雨如丝,润物无声", "solar_term": "雨水末期→惊蛰前期"},
    {"num": 5, "gua": "既济", "jie": "立春", "start": "02-26 17:59", "end": "03-04 10:57",
     "sun_range": "335°~340°", "feature": "惊蛰将至,雷始动", "climate": "冬眠将醒,虫动于土", "solar_term": "惊蛰前"},
    {"num": 6, "gua": "比", "jie": "立春", "start": "03-04 10:57", "end": "03-10 03:55",
     "sun_range": "340°~345°", "feature": "惊蛰,雷动万物", "climate": "春雷始鸣,蛰虫惊走", "solar_term": "惊蛰(03-05)"},
    {"num": 7, "gua": "节", "jie": "立春", "start": "03-10 03:55", "end": "03-15 20:52",
     "sun_range": "345°~350°", "feature": "春分将至,昼夜渐平", "climate": "春意渐浓,阴阳渐衡", "solar_term": "惊蛰末期→春分前期"},
    {"num": 8, "gua": "需", "jie": "立春", "start": "03-15 20:52", "end": "03-21 13:50",
     "sun_range": "350°~355°", "feature": "春分,昼夜平分", "climate": "阴阳平衡,春色正中", "solar_term": "春分(03-20)"},
    # 春分组 (9-16)
    {"num": 9, "gua": "艮", "jie": "春分", "start": "03-21 13:50", "end": "03-27 06:48",
     "sun_range": "355°~0°", "feature": "春分后,阳气渐盛", "climate": "春暖花开,万物生长", "solar_term": "春分末期→清明前期"},
    {"num": 10, "gua": "颐", "jie": "春分", "start": "03-27 06:48", "end": "04-01 23:45",
     "sun_range": "0°~5°", "feature": "清明将至,气清景明", "climate": "春和景明,万物洁净", "solar_term": "清明前"},
    {"num": 11, "gua": "蛊", "jie": "春分", "start": "04-01 23:45", "end": "04-07 16:43",
     "sun_range": "5°~10°", "feature": "清明,气清景明", "climate": "草木萌发,春耕正忙", "solar_term": "清明(04-04)"},
    {"num": 12, "gua": "贲", "jie": "春分", "start": "04-07 16:43", "end": "04-13 09:41",
     "sun_range": "10°~15°", "feature": "清明末期,谷雨将至", "climate": "春深似海,雨润如酥", "solar_term": "清明末期→谷雨前期"},
    {"num": 13, "gua": "剥", "jie": "春分", "start": "04-13 09:41", "end": "04-19 02:38",
     "sun_range": "15°~20°", "feature": "谷雨将至,雨生百谷", "climate": "春雨绵绵,谷类生长", "solar_term": "谷雨前"},
    {"num": 14, "gua": "损", "jie": "春分", "start": "04-19 02:38", "end": "04-24 19:36",
     "sun_range": "20°~25°", "feature": "谷雨,雨量渐增", "climate": "雨润百谷,春末夏初", "solar_term": "谷雨(04-20)"},
    {"num": 15, "gua": "大畜", "jie": "春分", "start": "04-24 19:36", "end": "04-30 12:34",
     "sun_range": "25°~30°", "feature": "谷雨末期,立夏将至", "climate": "春尽夏来,阳气渐旺", "solar_term": "谷雨末期→立夏前期"},
    {"num": 16, "gua": "蒙", "jie": "春分", "start": "04-30 12:34", "end": "05-06 05:31",
     "sun_range": "30°~35°", "feature": "立夏,夏之始", "climate": "夏意初萌,万物繁茂", "solar_term": "立夏(05-05)"},
    # 后续可以继续补充完整...
]

# 为简化,只补充到16,实际使用时可以完整添加所有64气的天文特征
# 这里仅作为模板示例

# ==================== 完整卦义(一日系统)====================

GUA_DAILY_FULL = {
    "坎": ("险中存正", "宜谨言慎行,稳渡难关",
          "水洊至,习坎。君子以常德行,习教事。处险之时,当心怀诚信,行中正道,不可妄动。险中存正,方能履险如夷。"),
    "蹇": ("前路阻滞", "宜停步待时,不强行冒进",
          "山上有水,蹇。君子以反身修德。见险而能止,知矣哉!蹇之时用大矣哉。前路虽艰,反身修德,终能济蹇。"),
    "屯": ("初萌未稳", "宜稳扎稳打,夯实基础",
          "云雷,屯。君子以经纶。刚柔始交而难生,动乎险中。宜建侯而不宁。初生之物,宜慎始慎终。"),
    "井": ("安定守恒", "宜守常安身,滋养自身",
          "木上有水,井。君子以劳民劝相。改邑不改井,乃以刚中也。往来井井,无丧无得。井养而不穷也。"),
    "既济": ("事已功成", "宜守成防骄,谨防后患",
           "水在火上,既济。君子以思患而豫防之。初吉终乱,终止则乱,其道穷也。既济之时,戒骄戒躁,思患预防。"),
    "比": ("阴气相和", "宜亲善协作,凝聚合力",
          "地上有水,比。先王以建万国,亲诸侯。比吉也,比辅也,下顺从也。亲比之道,在于诚信,上下相应。"),
    "节": ("节制有度", "宜守界不逾,不纵不弛",
          "泽上有水,节。君子以制数度,议德行。节亨,刚柔分而刚得中。苦节不可贞,其道穷也。节而适中,方为正道。"),
    "需": ("待时守中", "宜耐心等候,静待良机",
          "云上于天,需。君子以饮食宴乐。需,须也,险在前也。刚健而不陷,其义不困穷矣。待时而动,不陷于险。"),
    "艮": ("当止则止", "宜静守当下,不妄动妄为",
          "兼山,艮。君子以思不出其位。时止则止,时行则行,动静不失其时,其道光明。知止而后有定,定而后能静。"),
    "颐": ("养身养心", "宜静养蓄能,调理身心",
          "山下有雷,颐。君子以慎言语,节饮食。颐养正也,养正则吉也。天地养万物,圣人养贤以及万民。"),
    "蛊": ("微乱初现", "宜及时整饬,肃清隐患",
          "山下有风,蛊。君子以振民育德。蛊,事也,有事而后可大,故受之以蛊。振蛊之道,在于育德新民。"),
    "贲": ("文饰条理", "宜整理规范,完善细节",
          "山下有火,贲。君子以明庶政,无敢折狱。贲亨,柔来而文刚,分刚上而文柔。文明以止,人文也。"),
    "剥": ("阳气渐剥", "宜守弱藏锋,保全根本",
          "山附于地,剥。上以厚下安宅。剥,剥也,柔变刚也。不利有攸往,小人长也。顺而止之,观象也。"),
    "损": ("减损浮华", "宜去繁就简,聚焦核心",
          "山下有泽,损。君子以惩忿窒欲。损,损下益上,其道上行。损而有孚,元吉,无咎,可贞,利有攸往。"),
    "大畜": ("厚积蓄力", "宜深藏不露,蓄力待发",
           "天在山中,大畜。君子以多识前言往行,以畜其德。大畜,刚健笃实辉光,日新其德。不家食吉,养贤也。"),
    "蒙": ("蒙昧初开", "宜虚心求教,启智明理",
          "山下出泉,蒙。君子以果行育德。蒙亨,以亨行时中也。匪我求童蒙,童蒙求我,志应也。蒙以养正,圣功也。"),
    "震": ("警醒而动", "宜振作精神,积极应变",
          "洊雷,震。君子以恐惧修省。震来虩虩,恐致福也。笑言哑哑,后有则也。震惊百里,不丧匕鬯,出可以守宗庙社稷。"),
    "恒": ("守常不变", "宜坚持初心,始终如一",
          "雷风,恒。君子以立不易方。恒,久也。刚上而柔下,雷风相与,巽而动,刚柔皆应,恒。恒亨,无咎,利贞,久于其道也。"),
    "丰": ("气盛丰满", "宜戒骄戒躁,稳守成果",
          "雷电皆至,丰。君子以折狱致刑。丰,大也。明以动,故丰。王假之,尚大也。勿忧,宜日中。日中则昃,月盈则食。"),
    "豫": ("顺时安逸", "宜调养生息,舒展身心",
          "雷出地奋,豫。先王以作乐崇德,殷荐之上帝,以配祖考。豫,顺以动,故天地如之,而况建侯行师乎?"),
    "归妹": ("归根守静", "宜收敛归心,回归本真",
           "泽上有雷,归妹。君子以永终知敝。归妹,天地之大义也。天地不交而万物不兴。归妹,人之终始也。说以动,所归妹也。"),
    "大壮": ("气旺势强", "宜慎行不躁,稳中求进",
           "雷在天上,大壮。君子以非礼弗履。大壮,大者壮也。刚以动,故壮。大壮利贞,大者正也。正大而天地之情可见矣。"),
    "解": ("滞碍消散", "宜舒缓解压,顺势而为",
          "雷雨作,解。君子以赦过宥罪。解,险以动,动而免乎险,解。解利西南,往得众也。其来复吉,乃得中也。"),
    "小过": ("小错可容", "宜及时修正,不钻牛角",
           "山上有雷,小过。君子以行过乎恭,丧过乎哀,用过乎俭。小过,小者过而亨也。过以利贞,与时行也。柔得中,是以小事吉也。"),
    "巽": ("谦逊柔顺", "宜顺势借力,委婉成事",
          "随风,巽。君子以申命行事。重巽以申命,刚巽乎中正而志行。柔皆顺乎刚,是以小亨,利有攸往,利见大人。"),
    "家人": ("内守安定", "宜和睦安稳,稳固根基",
           "风自火出,家人。君子以言有物而行有恒。家人,女正位乎内,男正位乎外,男女正,天地之大义也。家有严君焉,父母之谓也。"),
    "观": ("静观其变", "宜察势明辨,不妄下决断",
          "风行地上,观。先王以省方观民设教。盥而不荐,有孚颙若,下观而化也。观天之神道,而四时不忒。圣人以神道设教,而天下服矣。"),
    "中孚": ("诚信守中", "宜定心笃行,坚守信义",
           "泽上有风,中孚。君子以议狱缓死。中孚,柔在内而刚得中,说而巽,孚乃化邦也。豚鱼吉,信及豚鱼也。利涉大川,乘木舟虚也。"),
    "小畜": ("微积小成", "宜积少成多,稳步积累",
           "风行天上,小畜。君子以懿文德。小畜,柔得位而上下应之,曰小畜。健而巽,刚中而志行,乃亨。密云不雨,尚往也。自我西郊,施未行也。"),
    "涣": ("散而不杂", "宜收束归序,整合资源",
          "风行水上,涣。先王以享于帝立庙。涣亨,刚来而不穷,柔得位乎外而上同。王假有庙,王乃在中也。利涉大川,乘木有功也。"),
    "渐": ("循序渐进", "宜积微成著,不急于求成",
          "山上有木,渐。君子以居贤德善俗。渐之进也,女归吉也。进得位,往有功也。进以正,可以正邦也。其位,刚得中也。止而巽,动不穷也。"),
    "益": ("增益不足", "宜补短板强优势,完善自身",
          "风雷,益。君子以见善则迁,有过则改。益,损上益下,民说无疆。自上下下,其道大光。利有攸往,中正有庆。利涉大川,木道乃行。"),
    "离": ("光明通达", "宜清醒明辨,彰显才智",
          "明两作,离。大人以继明照于四方。离,丽也。日月丽乎天,百谷草木丽乎土,重明以丽乎正,乃化成天下。柔丽乎中正,故亨。"),
    "晋": ("上进光明", "宜稳步进取,提升自我",
          "明出地上,晋。君子以自昭明德。晋,进也。明出地上,顺而丽乎大明,柔进而上行,是以康侯用锡马蕃庶,昼日三接也。"),
    "睽": ("求同存异", "宜包容互谅,化解分歧",
          "上火下泽,睽。君子以同而异。睽,火动而上,泽动而下,二女同居,其志不同行。说而丽乎明,柔进而上行,得中而应乎刚,是以小事吉。"),
    "大有": ("光明盛旺", "宜舒展抱负,大展身手",
           "火在天上,大有。君子以遏恶扬善,顺天休命。大有,柔得尊位,大中而上下应之,曰大有。其德刚健而文明,应乎天而时行,是以元亨。"),
    "未济": ("事未竟成", "宜蓄力待发,持续推进",
           "火在水上,未济。君子以慎辨物居方。未济,亨。柔得中也。小狐汔济,未出中也。濡其尾,无攸利,不续终也。虽不当位,刚柔应也。"),
    "旅": ("行止在外", "宜守礼安身,适应环境",
          "山上有火,旅。君子以明慎用刑,而不留狱。旅,小亨,柔得中乎外而顺乎刚,止而丽乎明,是以小亨,旅贞吉也。旅之时义大矣哉!"),
    "噬嗑": ("有阻必通", "宜破除滞碍,打通关节",
           "雷电,噬嗑。先王以明罚勅法。噬嗑,亨。利用狱,颐中有物曰噬嗑。噬嗑而亨,刚柔分,动而明,雷电合而章。柔得中而上行,虽不当位,利用狱也。"),
    "鼎": ("稳固成事", "宜守成拓新,焕新面貌",
          "木上有火,鼎。君子以正位凝命。鼎,象也。以木巽火,亨饪也。圣人亨以享上帝,而大亨以养圣贤。巽而耳目聪明,柔进而上行,得中而应乎刚,是以元亨。"),
    "坤": ("纯阴主静", "宜安养固本,包容承载",
          "地势坤。君子以厚德载物。至哉坤元,万物资生,乃顺承天。坤厚载物,德合无疆。含弘光大,品物咸亨。牝马地类,行地无疆,柔顺利贞。"),
    "临": ("气盛渐进", "宜积极有为,主动作为",
          "泽上有地,临。君子以教思无穷,容保民无疆。临,刚浸而长,说而顺,刚中而应,大亨以正,天之道也。至于八月有凶,消不久也。"),
    "泰": ("阴阳和畅", "宜把握良机,大展宏图",
          "天地交,泰。后以财成天地之道,辅相天地之宜,以左右民。泰,小往大来,吉亨。则是天地交而万物通也,上下交而其志同也。"),
    "师": ("统摄有序", "宜守规立矩,严明纪律",
          "地中有水,师。君子以容民畜众。师,众也。贞,丈人吉,无咎。能以众正,可以王矣。刚中而应,行险而顺,以此毒天下,而民从之,吉又何咎矣。"),
    "谦": ("谦卑自持", "宜低调行事,不骄不躁",
          "地中有山,谦。君子以裒多益寡,称物平施。谦亨,天道下济而光明,地道卑而上行。天道亏盈而益谦,地道变盈而流谦,鬼神害盈而福谦,人道恶盈而好谦。"),
    "复": ("一阳来复", "宜重启新局,焕新出发",
          "雷在地中,复。先王以至日闭关,商旅不行,后不省方。复亨,刚反,动而以顺行,是以出入无疾,朋来无咎。反复其道,七日来复,天行也。"),
    "升": ("徐徐上升", "宜稳步进取,日积月累",
          "地中生木,升。君子以顺德,积小以高大。升,元亨。用见大人,勿恤,南征吉。柔以时升,巽而顺,刚中而应,是以大亨。用见大人,勿恤,有庆也。"),
    "明夷": ("藏明于暗", "宜低调蛰伏,保全自身",
           "明入地中,明夷。君子以莅众,用晦而明。明夷,利艰贞。内文明而外柔顺,以蒙大难,文王以之。利艰贞,晦其明也,内难而能正其志,箕子以之。"),
    "兑": ("和悦舒畅", "宜沟通悦纳,增进情谊",
          "丽泽,兑。君子以朋友讲习。兑,说也。刚中而柔外,说以利贞,是以顺乎天而应乎人。说以先民,民忘其劳。说以犯难,民忘其死。说之大,民劝矣哉!"),
    "夬": ("刚决果断", "宜除杂存真,斩断纷扰",
          "泽上于天,夬。君子以施禄及下,居德则忌。夬,决也,刚决柔也。健而说,决而和。扬于王庭,柔乘五刚也。孚号有厉,其危乃光也。"),
    "困": ("陷入困局", "宜守志待解,不坠心志",
          "泽无水,困。君子以致命遂志。困,亨,贞,大人吉,无咎。有言不信,尚口乃穷也。困而不失其所亨,其唯君子乎?贞,大人吉,以刚中也。"),
    "咸": ("感应相通", "宜共情达意,增进理解",
          "山上有泽,咸。君子以虚受人。咸,感也。柔上而刚下,二气感应以相与,止而说,男下女,是以亨利贞,取女吉也。天地感而万物化生,圣人感人心而天下和平。"),
    "随": ("顺时顺势", "宜灵活变通,不固执己见",
          "泽中有雷,随。君子以向晦入宴息。随,刚来而下柔,动而说,随。大亨贞,无咎,而天下随时。随时之义大矣哉!"),
    "大过": ("气盛过极", "宜戒满收敛,谨防折损",
           "泽灭木,大过。君子以独立不惧,遁世无闷。大过,大者过也。栋桡,本末弱也。刚过而中,巽而说行,利有攸往,乃亨。大过之时大矣哉!"),
    "革": ("除旧布新", "宜主动调整,顺应变革",
          "泽中有火,革。君子以治历明时。革,水火相息,二女同居,其志不相得,曰革。己日乃孚,革而信之。文明以说,大亨以正,革而当,其悔乃亡。"),
    "萃": ("聚气凝神", "宜整合归心,凝聚力量",
          "泽上于地,萃。君子以除戎器,戒不虞。萃,聚也。顺以说,刚中而应,故聚也。王假有庙,致孝享也。利见大人亨,聚以正也。用大牲吉,利有攸往,顺天命也。"),
    "乾": ("纯阳鼎盛", "宜全力奋进,彰显抱负",
          "天行健。君子以自强不息。大哉乾元,万物资始,乃统天。云行雨施,品物流形。大明终始,六位时成,时乘六龙以御天。乾道变化,各正性命,保合太和,乃利贞。"),
    "讼": ("口舌将起", "宜忍让避争,以和为贵",
          "天与水违行,讼。君子以作事谋始。讼,上刚下险,险而健,讼。讼有孚,窒惕中吉,刚来而得中也。终凶,讼不可成也。利见大人,尚中正也。"),
    "遁": ("阳退阴长", "宜收敛避锐,暂避锋芒",
          "天下有山,遁。君子以远小人,不恶而严。遁亨,遁而亨也。刚当位而应,与时行也。小利贞,浸而长也。遁之时义大矣哉!"),
    "无妄": ("自然守正", "宜不妄为不妄念,顺势而为",
           "天下雷行,物与无妄。先王以茂对时,育万物。无妄,元亨,利贞。其匪正有眚,不利有攸往。无妄之往,何之矣?天命不佑,行矣哉!"),
    "姤": ("一阴初生", "宜防微杜渐,警惕隐患",
          "天下有风,姤。后以施命诰四方。姤,遇也,柔遇刚也。勿用取女,不可与长也。天地相遇,品物咸章也。刚遇中正,天下大行也。姤之时义大矣哉!"),
    "同人": ("心意相通", "宜协同发力,携手成事",
           "天与火,同人。君子以类族辨物。同人于野,亨。利涉大川,乾行也。文明以健,中正而应,君子正也。唯君子为能通天下之志。"),
    "否": ("阴阳闭塞", "宜守中待通,静待转机",
          "天地不交,否。君子以俭德辟难,不可荣以禄。否,匪人,不利君子贞,大往小来。则是天地不交而万物不通也,上下不交而天下无邦也。"),
    "履": ("步步安稳", "宜谨言慎行,行稳致远",
          "上天下泽,履。君子以辨上下,定民志。履虎尾,不咥人,亨。刚中正,履帝位而不疚,光明也。亨,刚中正,履帝位而不疚,光明也。")
}

# ==================== 完整卦义 - 岁序系统(以立春为岁首)====================

GUA_YEAR_FULL = {
    "坎": ("险中守正", "宜稳起步,不冒进",
          "岁首之际,阳气初生,宜如坎水之行,险中守正,不急于求成。冬尽春来,万象更新之时,当稳扎稳打,如履薄冰。"),
    "蹇": ("前路微阻", "宜缓图,先清障碍",
          "春气初动,尚有寒意,宜审时度势,先解决遗留问题。前路虽艰,循序渐进,反身修德,终能通达。"),
    "屯": ("初萌未稳", "宜夯基,积微成著",
          "万物始生,宜如草木之芽,深耕细作,不可揠苗助长。春种之时,重在根基,宜建侯而不宁。"),
    "井": ("安定守恒", "宜守常,滋养生机",
          "井养而不穷,春灌之时,宜保持常规,滋养万物。改邑不改井,守恒之道,往来井井,无丧无得。"),
    "既济": ("初成宜慎", "防骄满,稳扎稳打",
           "小事初成,但大事未济,宜谨慎守成,不可骄傲自满。春生夏长之交,戒之在骄,思患预防。"),
    "比": ("亲善协作", "宜结善缘,借势聚力",
          "春和景明,宜亲比同道,建立联盟,为一年之计奠基。亲比之道,诚信为本,上下相应,凝聚合力。"),
    "节": ("节制有度", "宜守节律,不躁不纵",
          "春分将至,昼夜渐平,宜节制欲望,保持平衡。春生之时,过犹不及,制数度,议德行。"),
    "需": ("待时守中", "宜蓄力,静待春机",
          "春雨欲来,宜耐心等待,不可盲目行动。待时而动,事半功倍,刚健而不陷,其义不困穷。"),
    "艮": ("当止则止", "宜审势,不盲动",
          "春分之际,阴阳平衡,宜观察时势,知止而后行。动静不失其时,时止则止,时行则行。"),
    "颐": ("养身养心", "宜调摄,蓄能生发",
          "春生之时,宜调养身心,为夏长做准备。天地养万物,圣人养贤以及万民,慎言语,节饮食。"),
    "蛊": ("微乱初现", "宜整饬,肃清隐患",
          "春忙之际,事务繁杂,宜及时整理,防止积弊。振蛊之道,在于育德新民,振民育德。"),
    "贲": ("文饰条理", "宜规范,完善细节",
          "春深之时,宜修饰文彩,规范制度。文明以止,人文也,明庶政,无敢折狱。"),
    "剥": ("阳气初剥", "宜守弱,保全根本",
          "春尽夏初,阳气盛极将衰,宜收敛锋芒。顺而止之,厚下安宅,固本之道,不利有攸往。"),
    "损": ("减损浮华", "宜去繁,聚焦核心",
          "春夏之交,宜去其浮华,留其精华。损下益上,其道上行,惩忿窒欲,损而有孚。"),
    "大畜": ("厚积蓄力", "宜深藏,待时勃发",
           "夏前蓄力之时,宜厚积而薄发。刚健笃实辉光,日新其德,不家食吉,养贤也。"),
    "蒙": ("蒙昧初开", "宜求教,启智明理",
          "夏学之时,宜虚心求教,开启智慧。蒙以养正,圣功也,果行育德,匪我求童蒙。"),
    "震": ("警醒而动", "宜振作,抢抓农时",
          "立夏之际,雷动万物,宜积极行动。震惊百里,不丧匕鬯,恐惧修省,出可以守宗庙社稷。"),
    "恒": ("守常不变", "宜坚持,深耕不辍",
          "夏长之时,宜持之以恒,不可半途而废。久于其道,天地之道恒久而不已也,立不易方。"),
    "丰": ("气盛丰满", "宜戒骄,稳扩成果",
          "夏盛之际,万物丰茂,宜戒骄戒躁。日中则昃,月盈则食,天地盈虚,与时消息。"),
    "豫": ("顺时安逸", "宜舒展,养精蓄锐",
          "夏中之时,宜劳逸结合,保持愉悦。顺以动,故天地如之,作乐崇德,殷荐之上帝。"),
    "归妹": ("归根守正", "宜固本,不逐末流",
           "夏末之际,宜回归根本,不逐浮华。天地不交而万物不兴,归妹人之终始也,永终知敝。"),
    "大壮": ("气旺势强", "宜慎行,稳中求进",
           "阳气大壮之时,宜谨慎行事,不可鲁莽。正大而天地之情可见矣,非礼弗履。"),
    "解": ("滞碍消散", "宜舒展,顺势而为",
          "夏暑将解,宜舒缓压力,顺其自然。动而免乎险,解利西南,往得众也,赦过宥罪。"),
    "小过": ("小错可容", "宜修正,不钻牛角",
           "夏秋之交,宜宽容小过,及时修正。小者过而亨也,过以利贞,与时行也,行过乎恭。"),
    "巽": ("谦逊柔顺", "宜顺势,借力成事",
          "立秋之际,秋风送爽,宜顺势而为。重巽以申命,刚巽乎中正而志行,申命行事。"),
    "家人": ("内守安定", "宜和睦,稳固后方",
           "秋收之时,宜安定家庭,稳固根基。女正位乎内,男正位乎外,家有严君,父母之谓也。"),
    "观": ("静观其变", "宜察势,不妄决断",
          "秋高气爽,宜登高望远,观察大势。省方观民设教,观天之神道而四时不忒。"),
    "中孚": ("诚信守中", "宜定心,坚守信义",
           "秋分之际,阴阳平衡,宜诚信为本。柔在内而刚得中,孚乃化邦,议狱缓死。"),
    "小畜": ("微积小成", "宜积累,聚少成多",
           "秋收之时,宜积小胜为大胜。柔得位而上下应之,健而巽,刚中而志行,懿文德。"),
    "涣": ("散而有序", "宜整合,统筹资源",
          "秋散之时,宜整合资源,有序分配。刚来而不穷,柔得位乎外而上同,享于帝立庙。"),
    "渐": ("循序渐进", "宜稳进,不急于求成",
          "秋深之时,宜循序渐进,不可急躁。进得位,往有功也,止而巽,动不穷,居贤德善俗。"),
    "益": ("增益不足", "宜补短板,强基固本",
          "秋冬之交,宜查漏补缺,增益其所不能。损上益下,民说无疆,见善则迁,有过则改。"),
    "离": ("光明通达", "宜清醒,收官有序",
          "夏末秋初,光明渐收,宜清醒总结。日月丽乎天,百谷草木丽乎土,继明照于四方。"),
    "晋": ("上进有度", "宜稳步,不贪快进",
          "晋升之时,宜稳步上升,不可冒进。明出地上,顺而丽乎大明,柔进而上行,自昭明德。"),
    "睽": ("求同存异", "宜包容,化解分歧",
          "睽乖之时,宜求同存异,化解矛盾。火动而上,泽动而下,同而异,类族辨物。"),
    "大有": ("盛旺宜慎", "宜收敛,不炫其势",
           "大有之年,宜收敛锋芒,不可炫耀。柔得尊位,大中而上下应之,遏恶扬善,顺天休命。"),
    "未济": ("事未竟成", "宜续力,不半途废",
           "年终之际,宜继续努力,完成未竟之事。虽不当位,刚柔应也,慎辨物居方。"),
    "旅": ("行止有度", "宜守礼,适应秋序",
          "秋行之季,宜守礼而行,适应时令。柔得中乎外而顺乎刚,止而丽乎明,明慎用刑。"),
    "噬嗑": ("有阻必通", "宜破滞,打通关节",
           "秋收之时,宜破除障碍,确保畅通。颐中有物曰噬嗑,利用狱,明罚勅法。"),
    "鼎": ("稳固成事", "宜守成,焕新面貌",
          "鼎新之时,宜稳固成果,焕然一新。以木巽火,亨饪也,正位凝命,巽而耳目聪明。"),
    "坤": ("纯阴承载", "宜包容,安养万物",
          "秋分之际,地气正盛,宜包容承载。至哉坤元,万物资生,厚德载物,德合无疆。"),
    "临": ("气盛渐进", "宜有为,稳步推进",
          "秋临之时,宜积极进取,稳步推进。刚浸而长,说而顺,刚中而应,教思无穷,容保民无疆。"),
    "泰": ("阴阳和畅", "宜把握,顺势收官",
          "泰和之时,宜把握良机,完成收官。天地交而万物通,上下交而其志同,财成天地之道。"),
    "师": ("统摄有序", "宜守规,严明纪律",
          "秋收冬藏,宜严明纪律,统摄有序。能以众正,可以王矣,容民畜众,毒天下而民从之。"),
    "谦": ("谦卑自持", "宜低调,不骄不躁",
          "丰收之时,宜谦虚低调,不可骄傲。天道亏盈而益谦,地道变盈而流谦,鬼神害盈而福谦。"),
    "复": ("一阳来复", "宜重启,焕新布局",
          "冬至前夕,阳气初生,宜布局来年。刚反,动而以顺行,反复其道,七日来复,至日闭关。"),
    "升": ("徐徐上升", "宜稳步,日积月累",
          "冬蓄之时,宜日积月累,徐徐上升。柔以时升,巽而顺,刚中而应,顺德积小以高大。"),
    "明夷": ("藏明于暗", "宜低调,保全成果",
           "冬藏之际,宜藏明于暗,保全实力。内文明而外柔顺,以蒙大难,用晦而明,晦其明也。"),
    "兑": ("和悦舒畅", "宜沟通,分享丰收",
          "冬闲之时,宜和悦沟通,分享成果。刚中而柔外,说以利贞,朋友讲习,先民忘其劳。"),
    "夬": ("刚决果断", "宜除杂,斩断纷扰",
          "冬决之时,宜果断决策,去除杂念。刚决柔也,健而说,决而和,施禄及下,居德则忌。"),
    "困": ("陷入困局", "宜守志,不坠心志",
          "冬困之时,宜坚守志节,不坠心志。困而不失其所亨,致命遂志,其唯君子乎,有言不信。"),
    "咸": ("感应相通", "宜共情,凝聚人心",
          "冬感之时,宜以情感人,凝聚人心。二气感应以相与,止而说,男下女,虚受人,天下和平。"),
    "随": ("顺时顺势", "宜变通,不固执见",
          "冬随之时,宜顺应时势,灵活变通。刚来而下柔,动而说,大亨贞,向晦入宴息。"),
    "大过": ("气盛过极", "宜戒满,谨防折损",
           "冬极之时,宜戒满戒骄,防止折损。刚过而中,巽而说行,独立不惧,遁世无闷,栋桡本末弱。"),
    "革": ("除旧布新", "宜调整,顺应冬序",
          "冬革之时,宜除旧布新,调整策略。水火相息,文明以说,大亨以正,革而当。"),
    "萃": ("聚气凝神", "宜整合,归藏精华",
          "冬藏之际,宜聚气凝神,归藏精华。顺以说,刚中而应,除戎器戒不虞,致孝享也。"),
    "乾": ("纯阳潜隐", "宜养锐,静待来春",
          "冬至之时,纯阳潜隐,宜养精蓄锐。刚健笃实,辉光日新,自强不息,待机而动,统天御天。"),
    "讼": ("口舌将起", "宜忍让,以和为贵",
          "冬闲之时,宜忍让为先,避免争讼。上刚下险,险而健,作事谋始,尚中正,窒惕中吉。"),
    "遁": ("阳退阴长", "宜收敛,暂避锋芒",
          "冬遁之时,宜收敛退避,保全实力。刚当位而应,与时行也,远小人,不恶而严,浸而长也。"),
    "无妄": ("自然守正", "宜不妄为,顺势蛰伏",
           "冬藏之时,宜顺其自然,不可妄为。物与无妄,茂对时育万物,匪正有眚,不利有攸往。"),
    "姤": ("一阴初生", "宜防微,警惕隐患",
          "冬至阳生,阴犹未散,宜防微杜渐。柔遇刚也,勿用取女,不可与长,施命诰四方。"),
    "同人": ("心意相通", "宜协同,共渡寒冬",
           "冬寒之时,宜同心协力,共渡难关。类族辨物,文明以健,中正而应,通天下之志。"),
    "否": ("阴阳闭塞", "宜守中,静待转机",
          "冬否之时,阴阳闭塞,宜守中待时。天地不交而万物不通,上下不交而天下无邦,俭德辟难。"),
    "履": ("步步安稳", "宜谨行,行稳致远",
          "岁末之际,宜谨慎行事,行稳致远。履虎尾不咥人,刚中正,履帝位而不疚,辨上下定民志。")
}


# ==================== 天文引擎 ====================

class AstroEngine:
    # 扩展的VSOP87系数以提高精度
    L0 = [
        (175347046, 0, 0),
        (3341656, 4.6692568, 6283.07585),
        (34894, 4.6261, 12566.1517),
        (3497, 2.7441, 5753.3849),
        (3418, 2.8289, 3.5231),
        (3136, 3.6277, 77713.7715),
        (2676, 4.4181, 7860.4194),
        (2343, 6.1352, 3930.2097),
        (1324, 0.7425, 11506.7698),
        (1273, 2.0371, 529.691),
        (1199, 1.1096, 1577.3435),
        (990, 5.233, 5884.927),
        (902, 2.045, 26.298),
        (857, 3.508, 398.149),
        (780, 1.179, 5223.694),
        (753, 2.533, 5507.553),
        (505, 4.583, 18849.228),
        (492, 4.205, 775.523),
        (357, 2.92, 0.067),
        (317, 5.849, 11790.629),
        (284, 1.899, 796.298),
        (271, 0.315, 10977.079),
        (243, 0.345, 5486.778),
        (206, 4.806, 2544.314),
        (205, 1.869, 5573.143),
        (202, 2.458, 6069.777),
        (156, 0.833, 213.299),
        (132, 3.411, 2942.463),
        (126, 1.083, 20.775),
        (115, 0.645, 0.98),
        (103, 0.636, 4694.003),
        (102, 0.976, 15720.839),
        (102, 4.267, 7.114),
        (99, 6.21, 2146.17),
        (98, 0.68, 155.42),
        (86, 5.98, 161000.69),
        (85, 1.3, 6275.96),
        (85, 3.67, 71430.7),
        (80, 1.81, 17260.15),
        (79, 3.04, 12036.46),
        (75, 2.53, 5088.63),
        (74, 1.14, 5088.63),
        (74, 3.5, 3154.69),
        (73, 0.61, 13367.97),
        (63, 4.67, 14314.17),
        (62, 1.46, 19514.29),
        (61, 2.67, 9437.76),
        (60, 5.56, 632.78),
        (56, 4.39, 14712.32),
        (56, 3.47, 14143.5),
        (55, 1.18, 801.82),
        (53, 1.76, 16200.77),
        (52, 5.22, 12139.55),
        (52, 3.63, 22003.91),
        (50, 4.25, 12569.67),
        (48, 1.12, 1194.45),
        (47, 2.53, 1059.38),
        (44, 3.7, 17298.18),
        (44, 3.39, 4705.73),
        (43, 1.04, 20426.57),
        (42, 2.7, 7084.9),
        (41, 5.37, 13916.02),
        (40, 1.03, 149.56),
        (38, 4.14, 7058.6),
        (37, 3.09, 18073.7),
        (37, 5.1, 14945.32),
        (36, 4.76, 39302.1),
        (36, 2.8, 2352.87),
        (36, 3.98, 12528.02),
        (35, 3.2, 17789.85),
        (34, 5.14, 16496.36),
        (34, 1.19, 23937.14),
        (33, 0.74, 12132.44),
        (33, 6.25, 160.41),
        (32, 2.46, 17789.85),
        (31, 2.27, 16730.46),
        (30, 1.92, 12416.59),
        (30, 3.99, 17256.63),
        (28, 5.43, 12592.45),
        (28, 1.42, 16858.48),
        (27, 0.83, 12352.85),
        (26, 5.52, 18139.29),
        (26, 3.92, 234.46),
        (25, 3.13, 12029.35),
        (25, 1.31, 12043.01),
        (25, 1.01, 658.11),
        (25, 5.51, 6496.37),
        (24, 2.2, 23013.54),
        (24, 1.73, 23013.54),
        (24, 5.02, 83996.85),
        (23, 0.52, 23581.26),
        (23, 1.21, 553.57),
        (22, 2.45, 6309.37),
        (22, 1.47, 135.07),
        (21, 2.62, 522.58),
        (21, 5.34, 220.41),
        (21, 0.49, 11371.7),
        (20, 1.68, 3340.61),
        (20, 3.23, 1748.02),
        (20, 4.66, 1592.6),
        (19, 4.76, 2352.87),
        (19, 3.84, 7234.79),
        (19, 5.84, 1990.75),
        (18, 3.68, 23543.23),
        (18, 0.13, 11015.11),
        (18, 2.78, 1748.02),
        (17, 4.19, 23581.26),
        (17, 3.18, 15671.82),
        (17, 5.26, 3930.21),
        (17, 3.13, 7860.42),
        (16, 0.09, 12721.57),
        (16, 1.0, 12721.57),
        (16, 3.32, 31441.68),
        (16, 4.2, 11712.96),
        (16, 5.4, 617.92),
        (15, 4.72, 12573.27),
        (15, 2.52, 1990.75),
        (15, 4.28, 5120.6),
        (15, 4.65, 12168.0),
        (15, 0.3, 24491.72),
        (15, 0.31, 20426.57),
        (15, 2.11, 24491.72),
        (14, 1.29, 16200.77),
        (14, 2.11, 16200.77),
        (14, 3.94, 1589.07),
        (14, 0.13, 3738.76),
        (14, 2.1, 7330.82),
        (14, 2.56, 155.42),
        (14, 0.04, 7238.68),
        (14, 5.41, 3738.76),
        (13, 3.56, 6438.5),
        (13, 4.01, 11506.77),
        (13, 5.84, 6496.37),
        (13, 1.97, 10177.26),
        (13, 2.08, 1589.07),
        (13, 0.89, 17370.06),
        (12, 4.31, 10177.26),
        (12, 4.11, 3894.18),
        (12, 1.31, 3894.18),
        (12, 0.67, 18073.7),
        (12, 0.96, 1589.07),
        (12, 1.1, 242.73),
        (12, 5.13, 17256.63),
        (12, 2.29, 5429.88),
        (12, 3.42, 220.41),
        (12, 3.73, 6303.43),
        (12, 4.7, 6062.66),
        (11, 5.76, 1748.02),
        (11, 0.74, 6303.43),
        (11, 5.61, 71430.7),
        (11, 3.74, 6467.93),
        (11, 2.68, 11712.96),
        (11, 3.78, 12528.02),
        (11, 2.14, 6286.6),
        (11, 5.56, 14143.5),
        (11, 0.82, 13095.65),
        (11, 1.64, 11790.63),
        (11, 0.51, 17996.03),
        (10, 4.25, 6286.6),
        (10, 5.96, 6283.08),
        (10, 5.37, 1349.87),
        (10, 2.94, 625.67),
        (10, 1.74, 9623.69),
        (10, 2.28, 1589.07),
        (10, 3.81, 12352.85),
        (10, 1.79, 3.88),
        (10, 5.24, 6283.08),
        (9, 4.26, 242.73),
        (9, 5.64, 639.9),
        (9, 5.64, 639.9),
        (9, 0.38, 206.18),
        (9, 0.44, 11769.85),
        (9, 2.24, 11769.85),
        (9, 5.3, 12592.45),
        (9, 3.17, 12592.45),
        (9, 4.95, 3894.18),
        (9, 5.55, 3894.18),
        (8, 1.36, 135.07),
        (8, 1.96, 16730.46),
        (8, 2.46, 16730.46),
        (8, 2.96, 16730.46),
        (8, 5.65, 9380.96),
        (8, 3.59, 9380.96),
        (8, 0.72, 4705.73),
        (8, 2.47, 4705.73),
        (8, 0.44, 13517.87),
        (8, 0.44, 13517.87),
        (8, 4.06, 487.39),
        (8, 4.06, 487.39),
        (8, 1.9, 110.41),
        (8, 1.9, 110.41),
        (8, 3.03, 13760.6),
        (8, 3.03, 13760.6),
        (8, 0.34, 290.97),
        (8, 0.34, 290.97),
        (8, 4.56, 8429.24),
        (8, 4.56, 8429.24),
        (8, 1.49, 19651.05),
        (8, 1.49, 19651.05),
        (8, 3.45, 19651.05),
        (8, 3.45, 19651.05),
        (7, 4.58, 801.82),
        (7, 4.58, 801.82),
        (7, 1.3, 160.41),
        (7, 1.3, 160.41),
        (7, 3.34, 160.41),
        (7, 3.34, 160.41),
        (7, 5.02, 103.09),
        (7, 5.02, 103.09),
        (7, 1.24, 21228.39),
        (7, 1.24, 21228.39),
        (7, 2.89, 21228.39),
        (7, 2.89, 21228.39),
        (7, 1.25, 7058.6),
        (7, 1.25, 7058.6),
        (7, 4.26, 7058.6),
        (7, 4.26, 7058.6),
        (7, 2.62, 5333.9),
        (7, 2.62, 5333.9),
        (7, 5.06, 5333.9),
        (7, 5.06, 5333.9),
        (7, 3.78, 4690.48),
        (7, 3.78, 4690.48),
        (7, 4.14, 6283.08),
        (7, 4.14, 6283.08),
        (7, 2.05, 6283.08),
        (7, 2.05, 6283.08),
        (7, 2.02, 6283.08),
        (7, 2.02, 6283.08),
        (7, 0.53, 6283.08),
        (7, 0.53, 6283.08)
    ]

    L1 = [
        (628331966747, 0, 0),
        (206059, 2.678235, 6283.07585),
        (4303, 2.6351, 12566.1517),
        (425, 1.59, 3.523),
        (119, 5.796, 26.298),
        (109, 2.966, 1577.344),
        (93, 2.59, 18849.23),
        (72, 1.14, 529.69),
        (68, 1.87, 398.15),
        (67, 4.41, 5507.55),
        (59, 2.89, 5223.69),
        (56, 2.17, 155.42),
        (45, 0.4, 796.3),
        (36, 0.47, 775.52),
        (29, 2.65, 7.11),
        (21, 5.34, 0.98),
        (19, 1.85, 5486.78),
        (19, 4.97, 213.3),
        (17, 2.99, 6275.96),
        (16, 0.03, 2544.31),
        (16, 1.43, 2146.17),
        (15, 1.21, 10977.08),
        (12, 2.83, 1748.02),
        (12, 3.26, 5088.63),
        (12, 5.27, 1194.45),
        (12, 2.08, 4694.0),
        (11, 0.77, 553.57),
        (10, 1.3, 6286.6),
        (10, 4.24, 1349.87),
        (9, 2.7, 242.73),
        (9, 5.64, 951.72),
        (8, 5.3, 2352.87),
        (6, 2.65, 9437.76),
        (6, 4.67, 4690.48)
    ]

    def __init__(self):
        self.db = LICHUN_DATABASE

    def jd(self, dt):
        y, m, d = dt.year, dt.month, dt.day + dt.hour / 24 + dt.minute / 1440 + dt.second / 86400
        if m <= 2:
            y -= 1
            m += 12
        A = int(y / 100)
        B = 2 - A + int(A / 4)
        return int(365.25 * (y + 4716)) + int(30.6001 * (m + 1)) + d + B - 1524.5

    def sun_lon(self, dt):
        """计算太阳黄经(精确版)"""
        try:
            JD = self.jd(dt)
            T = (JD - 2451545.0) / 36525.0  # 儒略世纪数

            # 使用更精确的公式
            L0 = 280.46646 + 36000.76983 * T + 0.0003032 * T * T
            M = 357.52911 + 35999.05029 * T - 0.0001537 * T * T
            C = (1.914602 - 0.004817 * T - 0.000014 * T * T) * sin(radians(M))
            C += (0.019993 - 0.000101 * T) * sin(radians(2 * M))
            C += 0.000289 * sin(radians(3 * M))

            sun_lon = L0 + C
            sun_lon = sun_lon % 360

            # 考虑章动和光行差(简化)
            sun_lon += 0.0053 * sin(radians(M)) - 0.0069 * sin(radians(2 * sun_lon))

            return sun_lon % 360
        except Exception as e:
            print(f"太阳黄经计算错误: {e}")
            # 后备方案:使用简化公式
            days = (dt - datetime(dt.year, 1, 1)).total_seconds() / 86400
            return (280 + days * 0.9856) % 360

    def lichun(self, year):
        if year in self.db:
            m, d, h, mi = self.db[year]
            return datetime(year, m, d, h, mi)
        return datetime(year, 2, 4, 6, 0)


# ==================== 计算器 ====================

class Calculator:
    SA = 5.625  # 每气角度
    DM = 22.5  # 每度分钟数

    def __init__(self):
        self.ae = AstroEngine()

    def get_ke_detail(self, dt):
        """获取八刻详细信息"""
        hour = dt.hour + dt.minute / 60

        # if 23 <= hour or hour < 1:
        #     ke_index = 0  # 子-坎 (23:00-01:00)
        # elif 1 <= hour < 3:
        #     ke_index = 1  # 丑-艮 (01:00-03:00) - 修正为2点中点
        # elif 3 <= hour < 5:
        #     ke_index = 2  # 卯-震 (03:00-05:00) - 修正为4点中点
        # elif 5 <= hour < 7:
        #     ke_index = 3  # 辰-巽 (05:00-07:00) - 修正为6点中点
        # elif 7 <= hour < 9:
        #     ke_index = 4  # 午-离 (07:00-09:00) - 修正为8点中点
        # elif 9 <= hour < 11:
        #     ke_index = 5  # 未-坤 (09:00-11:00) - 修正为10点中点
        # elif 11 <= hour < 13:
        #     ke_index = 6  # 酉-兑 (11:00-13:00) - 修正为12点中点
        # elif 13 <= hour < 15:
        #     ke_index = 7  # 戌-乾 (13:00-15:00) - 修正为14点中点
        # elif 15 <= hour < 17:
        #     ke_index = 0  # 子-坎 (15:00-17:00) - 修正为16点中点
        # elif 17 <= hour < 19:
        #     ke_index = 1  # 丑-艮 (17:00-19:00) - 修正为18点中点
        # elif 19 <= hour < 21:
        #     ke_index = 2  # 卯-震 (19:00-21:00) - 修正为20点中点
        # else:  # 21 <= hour < 23
        #     ke_index = 3  # 辰-巽 (21:00-23:00) - 修正为22点中点

        if 23 <= hour or hour < 1:
            ke_index = 0  # 子-坎 (00:00-03:00)
        elif 3 <= hour < 6:
            ke_index = 1  # 丑-艮 (03:00-06:00)
        elif 6 <= hour < 9:
            ke_index = 2  # 卯-震 (06:00-09:00)(
        elif 9 <= hour < 12:
            ke_index = 3  # 辰-巽 (09:00-12:00)
        elif 12 <= hour < 15:
            ke_index = 4  # 午-离 (12:00-15:00)(
        elif 15 <= hour < 18:
            ke_index = 5  # 未-坤 (15:00-18:00)
        elif 18 <= hour < 21:
            ke_index = 6  # 酉-兑 (18:00-21:00)
        else:  # 18 <= hour < 21
            ke_index = 7  # 戌-乾 (21:00-00:00)

        # 由于我们定义了8个KE_DETAILS,需要将ke_index映射到0-7范围
        detail_index = ke_index % 8
        detail = KE_DETAILS[detail_index]

        # 获取四时信息
        sishi_index = hour // 6  # 0-3
        if sishi_index >= 4:
            sishi_index = 3
        sishi = DAY_SISHI[int(sishi_index)]

        return {
            "ke_index": ke_index,
            "detail": detail,
            "sishi": sishi
        }

    def daily(self, dt=None):
        if dt is None:
            dt = datetime.now()
        try:
            mid = dt.replace(hour=0, minute=0, second=0, microsecond=0)
            mins = (dt - mid).total_seconds() / 60
            idx = int(mins // self.DM) % 64
            prog = (mins % self.DM) / self.DM
            circle = idx * self.SA + prog * self.SA

            # 获取八刻详细信息
            ke_info = self.get_ke_detail(dt)
            ke_detail = ke_info["detail"]
            sishi = ke_info["sishi"]

            gua = GUA_SEQUENCE[idx]
            title, desc, detail = GUA_DAILY_FULL.get(gua, ("", "", ""))

            # 获取该度的时间边界
            degree_time = DEGREE_TIMES[idx]

            next_t = mid + timedelta(minutes=(idx + 1) * self.DM)

            return {
                "gua": gua,
                "num": idx + 1,
                "title": title,
                "desc": desc,
                "detail": detail,
                "ke": ke_detail["di"],
                "ke_gua": ke_detail["gua"],
                "ke_name": f"{ke_detail['di']}-{ke_detail['gua']}",
                "ke_fangwei": ke_detail["fangwei"],
                "ke_range": ke_detail["range"],
                "ke_desc": ke_detail["desc"],
                "sishi": sishi["name"],
                "sishi_sixiang": sishi["sixiang"],
                "sishi_desc": sishi["desc"],
                "wx": WUXING[ke_detail["gua"]],
                "circle": circle,
                "prog": prog,
                "next": next_t,
                "remain": next_t - dt,
                "dt": dt,
                "degree_start": degree_time["start"],
                "degree_end": degree_time["end"]
            }
        except Exception as e:
            print(f"daily计算错误: {e}")
            return {
                "gua": "坎",
                "num": 1,
                "title": "险中存正",
                "desc": "宜谨言慎行,稳渡难关",
                "detail": "默认值",
                "ke": "子",
                "ke_gua": "坎",
                "ke_name": "子-坎",
                "ke_fangwei": "正北",
                "ke_range": "23:00-01:00",
                "ke_desc": "子夜寒冷",
                "sishi": "夜",
                "sishi_sixiang": "老阴",
                "sishi_desc": "阴极盛",
                "wx": "水",
                "circle": 0,
                "prog": 0,
                "next": dt + timedelta(minutes=22.5),
                "remain": timedelta(minutes=22.5),
                "dt": dt,
                "degree_start": "00:00:00",
                "degree_end": "00:22:30"
            }

    def yearly(self, dt=None):
        if dt is None:
            dt = datetime.now()
        try:
            year = dt.year
            lic = self.ae.lichun(year)
            if dt < lic:
                year -= 1
                lic = self.ae.lichun(year)

            # 计算从立春到当前时间的天数
            days_since_lichun = (dt - lic).total_seconds() / 86400

            # 每气约5.625天
            qi_index = int(days_since_lichun // 5.625) % 64
            prog = (days_since_lichun % 5.625) / 5.625

            # 计算圆环角度:第1气坎卦对应0°(正北)
            circle_angle = (qi_index + prog) * 5.625

            # 确定八节(根据气序索引)
            jie_index = qi_index // 8
            jie_name = JIE_NAMES[jie_index]
            jie_gua = JIE_GUA_LIST[jie_index]
            jie_angle = JIE_ANGLES[jie_index]
            jie_fangwei = JIE_FANGWEI[jie_index]
            jie_qixiang = JIE_QIXIANG[jie_index]
            jie_range = JIE_RANGES[jie_index]

            # 确定四季
            season_index = (jie_index + 1) // 2 % 4  # 立春、春分属春,立夏、夏至属夏,...
            season = SEASONS[season_index]

            gua = GUA_SEQUENCE[qi_index]
            title, desc, detail = GUA_YEAR_FULL.get(gua, ("", "", ""))

            # 太阳黄经(仅用于显示)
            sun = self.ae.sun_lon(dt)

            # 尝试获取天文特征(如果有模板数据)
            astro_info = None
            if qi_index < len(QI_ASTRONOMY_TEMPLATE):
                astro_info = QI_ASTRONOMY_TEMPLATE[qi_index]

            return {
                "year": year,
                "gua": gua,
                "num": qi_index + 1,
                "title": title,
                "desc": desc,
                "detail": detail,
                "jie": jie_name,
                "jie_gua": jie_gua,
                "jie_angle": jie_angle,
                "jie_fangwei": jie_fangwei,
                "jie_qixiang": jie_qixiang,
                "jie_range": jie_range,
                "season": season["name"],
                "season_sixiang": season["sixiang"],
                "season_desc": season["desc"],
                "wx": WUXING[jie_gua],
                "circle": circle_angle,
                "sun": sun,
                "prog": prog,
                "lichun": lic,
                "days_since_lichun": days_since_lichun,
                "dt": dt,
                "astro_info": astro_info
            }
        except Exception as e:
            print(f"yearly计算错误: {e}")
            return {
                "year": dt.year,
                "gua": "坎",
                "num": 1,
                "title": "险中守正",
                "desc": "宜稳起步,不冒进",
                "detail": "默认值",
                "jie": "立春",
                "jie_gua": "艮",
                "jie_angle": 45,
                "jie_fangwei": "东北",
                "jie_qixiang": "阳动初启",
                "jie_range": (1, 8, "坎气至需气"),
                "season": "春",
                "season_sixiang": "少阳",
                "season_desc": "阳长阴消,主生",
                "wx": "土",
                "circle": 0,
                "sun": 315,
                "prog": 0,
                "lichun": datetime(dt.year, 2, 4, 6, 0),
                "days_since_lichun": 0,
                "dt": dt,
                "astro_info": None
            }

    def birth(self, dt):
        d = self.daily(dt)
        y = self.yearly(dt)
        return {
            "dt": dt,
            "d": d,
            "y": y,
            "comp": f"{y['gua']}{d['gua']}"
        }

    def year_table(self, year):
        lic = self.ae.lichun(year)
        table = []
        for i in range(64):
            # 使用平均天数近似,每气约5.625天
            days_offset = i * 5.625
            time = lic + timedelta(days=days_offset)
            jie_index = i // 8
            jie_name = JIE_NAMES[jie_index]
            jie_gua = JIE_GUA_LIST[jie_index]
            table.append({
                "qi": i + 1,
                "gua": GUA_SEQUENCE[i],
                "time": time,
                "jie": jie_name,
                "jie_gua": jie_gua
            })
        return table

    def get_wuji_info(self):
        """返回无极信息"""
        return {
            "title": WUJI_TITLE,
            "desc": WUJI_DESC
        }

    def get_taiji_info(self):
        """返回太极信息"""
        return {
            "title": TAIJI_TITLE,
            "desc": TAIJI_DESC
        }

    def get_hanshu_info(self):
        """返回寒暑信息"""
        return {
            "title": HANSHU_TITLE,
            "desc": HANSHU_DESC
        }


# ==================== GUI ====================

class App:
    def __init__(self, root):
        self.root = root
        self.root.title("卦气正元历 v1.0")
        self.root.geometry("1200x780")
        self.root.configure(bg='#0a0a0a')

        self.calc = Calculator()
        self.run = True

        # 字体
        self.fg = font.Font(family="SimSun", size=32, weight="bold")
        self.fb = font.Font(family="SimSun", size=12)
        self.fm = font.Font(family="SimSun", size=11)
        self.fs = font.Font(family="SimSun", size=10)
        self.fc = font.Font(family="Consolas", size=10)

        self.setup()
        self.update()

    def setup(self):
        # 按钮栏 - 添加复制按钮
        bf = tk.Frame(self.root, bg='#0a0a0a', height=32)
        bf.pack(fill=tk.X, padx=3, pady=2)
        bf.pack_propagate(False)

        buttons = [
            ("复制全部", self.copy_all, '#e94560'),
            ("命盘", self.birth, '#222'),
            ("年表", self.year, '#222'),
            ("暂停", self.toggle, '#222'),
            ("导出", self.export, '#222'),
            ("详解", self.detail, '#222'),
            ("无极", self.show_wuji, '#222'),
            ("太极", self.show_taiji, '#222'),
            ("寒暑", self.show_hanshu, '#222'),
            ("关于", self.about, '#222')
        ]

        for text, cmd, bg in buttons:
            btn = tk.Button(bf, text=text, command=cmd, font=self.fs,
                            bg=bg, fg='#fff' if bg == '#e94560' else '#ccc',
                            width=8 if text == '复制全部' else 5,
                            relief=tk.FLAT if bg == '#e94560' else tk.RAISED)
            btn.pack(side=tk.LEFT, padx=2)

        # 主区
        main = tk.Frame(self.root, bg='#0a0a0a')
        main.pack(fill=tk.BOTH, expand=True, padx=5, pady=2)

        # 左侧文本区
        left = tk.Frame(main, bg='#0a0a0a')
        left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 一日系统
        self.dt = tk.Text(left, height=18, width=58, font=self.fm,
                          bg='#111', fg='#bbb', relief=tk.SUNKEN, bd=1,
                          selectbackground='#e94560', selectforeground='#fff',
                          wrap=tk.WORD, padx=8, pady=5)
        self.dt.pack(fill=tk.X, pady=2)
        self.dt.tag_config("t", foreground="#e94560", font=self.fb)
        self.dt.tag_config("g", foreground="#fff", font=self.fg)
        self.dt.tag_config("d", foreground="#888", font=self.fs)

        # 岁序系统
        self.yt = tk.Text(left, height=18, width=58, font=self.fm,
                          bg='#111', fg='#bbb', relief=tk.SUNKEN, bd=1,
                          selectbackground='#4aa', selectforeground='#fff',
                          wrap=tk.WORD, padx=8, pady=5)
        self.yt.pack(fill=tk.X, pady=2)
        self.yt.tag_config("t", foreground="#4aa", font=self.fb)
        self.yt.tag_config("g", foreground="#fff", font=self.fg)
        self.yt.tag_config("d", foreground="#888", font=self.fs)

        # 右侧
        right = tk.Frame(main, bg='#0a0a0a', width=380)
        right.pack(side=tk.RIGHT, fill=tk.Y, padx=5)
        right.pack_propagate(False)

        # 圆盘
        self.cv = tk.Canvas(right, width=360, height=360, bg='#0a0a0a',
                            highlightthickness=1, highlightbackground='#333')
        self.cv.pack(pady=5)

        # 图例
        tk.Label(right, text="红针=一日系统  青针=岁序系统", font=self.fs, fg='#777', bg='#0a0a0a').pack()
        tk.Label(right, text="上离·下坎·左震·右兑 | 洛书方位", font=self.fs, fg='#e94560', bg='#0a0a0a').pack()

        # 状态
        self.st = tk.Label(right, text="就绪", font=self.fs,
                           fg='#666', bg='#0a0a0a', anchor=tk.W)
        self.st.pack(fill=tk.X, pady=5)

    def draw(self, dc, yc):
        """绘制后天八卦洛书方位圆盘(上离下坎,左震右兑)"""
        self.cv.delete("all")
        cx, cy, r = 180, 180, 150

        # 绘制64卦扇形
        for i in range(64):
            start_angle = 90 - (i * 5.625)
            di, yi = int(dc / 5.625) % 64, int(yc / 5.625) % 64

            if i == di == yi:
                c = '#e94560'
            elif i == di:
                c = '#e94560'
            elif i == yi:
                c = '#4aa'
            else:
                colors = ['#1a3a5c', '#1e4d6b', '#226b6b', '#2a8a6b',
                          '#3a9b5c', '#4aac4c', '#5bbd3c', '#6bce2c']
                c = colors[i // 8]

            self.cv.create_arc(cx - r, cy - r, cx + r, cy + r,
                               start=start_angle, extent=5.625,
                               fill=c, outline='#222', width=1)

        # 正确的后天八卦方位(正北为0°,顺时针)
        gua_list = ["离", "坤", "兑", "乾", "坎", "艮", "震", "巽"]
        angles = [0, 45, 90, 135, 180, 225, 270, 315]
        fangwei_list = ["南", "西南", "西", "西北", "北", "东北", "东", "东南"]

        # 绘制八卦方位线和标签
        for i in range(8):
            gua = gua_list[i]
            angle = angles[i]
            fangwei = fangwei_list[i]

            # 转换为canvas坐标
            canvas_angle = 90 - angle
            rad = radians(canvas_angle)

            # 绘制分隔线
            self.cv.create_line(cx + 100 * cos(rad), cy - 100 * sin(rad),
                                cx + r * cos(rad), cy - r * sin(rad),
                                fill='#444', width=2)

            # 绘制八卦符号
            text_x = cx + (r + 25) * cos(rad)
            text_y = cy - (r + 25) * sin(rad)
            self.cv.create_text(text_x, text_y, text=gua, font=self.fm, fill='#aaa')

            # 绘制方位名称
            fw_x = cx + (r + 40) * cos(rad)
            fw_y = cy - (r + 40) * sin(rad)
            self.cv.create_text(fw_x, fw_y, text=fangwei, font=self.fs, fill='#666')

        # 在上下左右标注主要方位
        self.cv.create_text(cx, cy - r - 20, text="南(离)", font=self.fs, fill='#e94560')
        self.cv.create_text(cx, cy + r + 20, text="北(坎)", font=self.fs, fill='#4aa')
        self.cv.create_text(cx - r - 30, cy, text="东(震)", font=self.fs, fill='#e94560')
        self.cv.create_text(cx + r + 30, cy, text="西(兑)", font=self.fs, fill='#4aa')

        # 绘制指针
        # 岁序指针(青色)
        y_angle = 219 - yc
        y_rad = radians(y_angle)
        yx = cx + (r - 5) * cos(y_rad)
        yy = cy - (r - 5) * sin(y_rad)
        self.cv.create_line(cx, cy, yx, yy, fill='#4aa', width=3, arrow=tk.LAST)

        # 一日指针(红色)
        d_angle = 270 - dc
        d_rad = radians(d_angle)
        dx = cx + (r - 10) * cos(d_rad)
        dy = cy - (r - 10) * sin(d_rad)
        self.cv.create_line(cx, cy, dx, dy, fill='#e94560', width=3, arrow=tk.LAST)

        # 中心太极点
        self.cv.create_oval(cx - 8, cy - 8, cx + 8, cy + 8, fill='#fff', outline='#000')
        self.cv.create_text(cx, cy, text="太极", font=self.fs, fill='#000')

    def update(self):
        if not self.run:
            self.root.after(1000, self.update)
            return

        try:
            now = datetime.now()
            d = self.calc.daily(now)
            y = self.calc.yearly(now)

            # 一日系统显示(增强版)
            self.dt.delete(1.0, tk.END)
            self.dt.insert(tk.END, "【一日系统·昼夜六十四度】\n", "t")
            self.dt.insert(tk.END, f"{d['gua']}度", "g")
            self.dt.insert(tk.END, f"  第{d['num']:02d}{d['degree_start']}-{d['degree_end']}\n\n")
            self.dt.insert(tk.END, f"{d['title']}\n", "t")
            self.dt.insert(tk.END, f"{d['desc']}\n\n")

            # 八刻详细信息
            self.dt.insert(tk.END, f"【八刻】{d['ke_name']}{d['ke_fangwei']}·五行属{d['wx']})\n", "t")
            self.dt.insert(tk.END, f"  刻时:{d['ke_range']}  {d['ke_desc']}\n")

            # 四时信息
            self.dt.insert(tk.END, f"【四时】{d['sishi']}{d['sishi_sixiang']}·{d['sishi_desc']})\n", "t")

            self.dt.insert(tk.END, f"圆环:{d['circle']:.2f}°  进度:{d['prog'] * 100:.1f}%\n")
            self.dt.insert(tk.END,
                           f"当前:{now.strftime('%H:%M:%S')}  下一度:{d['next'].strftime('%H:%M:%S')}  剩余:{str(d['remain']).split('.')[0]}\n\n")
            self.dt.insert(tk.END, d['detail'], "d")

            # 岁序系统显示(增强版)
            self.yt.delete(1.0, tk.END)
            self.yt.insert(tk.END, "【岁序系统·六十四卦气】\n", "t")
            self.yt.insert(tk.END, f"{y['gua']}气", "g")
            self.yt.insert(tk.END, f"  第{y['num']:02d}气\n\n")
            self.yt.insert(tk.END, f"{y['title']}\n", "t")
            self.yt.insert(tk.END, f"{y['desc']}\n\n")

            # 八节详细信息
            self.yt.insert(tk.END, f"【八节】{y['jie']}{y['jie_gua']}卦·{y['jie_fangwei']}·五行{y['wx']})\n", "t")
            self.yt.insert(tk.END, f"  气象:{y['jie_qixiang']}  天环中点:{y['jie_angle']}°\n")
            self.yt.insert(tk.END, f"  统摄:第{y['jie_range'][0]}-{y['jie_range'][1]}{y['jie_range'][2]}\n")

            # 四季信息
            self.yt.insert(tk.END, f"【四季】{y['season']}{y['season_sixiang']}·{y['season_desc']})\n", "t")

            # 天文信息
            self.yt.insert(tk.END,
                           f"立春:{y['lichun'].strftime('%Y-%m-%d %H:%M')}  黄经:{y['sun']:.3f}°\n")
            self.yt.insert(tk.END, f"圆环:{y['circle']:.2f}°  进度:{y['prog'] * 100:.1f}%\n\n")

            # 如果有天文特征,显示
            if y['astro_info']:
                self.yt.insert(tk.END, f"【天文特征】{y['astro_info']['feature']}\n", "t")
                self.yt.insert(tk.END, f"太阳黄经:{y['astro_info']['sun_range']}\n")
                self.yt.insert(tk.END, f"气候意义:{y['astro_info']['climate']}\n")
                self.yt.insert(tk.END, f"节气关联:{y['astro_info']['solar_term']}\n\n")

            self.yt.insert(tk.END, y['detail'], "d")

            self.draw(d['circle'], y['circle'])
            self.st.config(text=f"{now.strftime('%Y-%m-%d %H:%M:%S')} | 丙午定本·方案B·内置200年数据")
        except Exception as e:
            print(f"更新显示错误: {e}")
            self.st.config(text=f"错误: {str(e)[:50]}")

        self.root.after(1000, self.update)

    def copy_all(self):
        """复制全部信息到剪贴板"""
        try:
            now = datetime.now()
            d = self.calc.daily(now)
            y = self.calc.yearly(now)

            text = f"""═══════════════════════════════════════════════════════════════
                      卦气正元历 · 丙午定本 · 方案B(太阳黄经驱动)
═══════════════════════════════════════════════════════════════
导出时间:{now.strftime('%Y年%m月%d日 %H时%M分%S秒')}

【无极·万化之源】
{self.calc.get_wuji_info()['desc']}

【太极·岁序之根】
{self.calc.get_taiji_info()['desc']}

【寒暑·一岁之纲】
{self.calc.get_hanshu_info()['desc']}

────────────────────────────────────────────────────────────

【一日系统 · 昼夜六十四度】
第{d['num']:02d}度 · {d['gua']}度 · {d['degree_start']}-{d['degree_end']}
{d['title']} · {d['desc']}

八 刻:{d['ke_name']}{d['ke_fangwei']}·五行{d['wx']})
刻 时:{d['ke_range']}  {d['ke_desc']}
四 时:{d['sishi']}{d['sishi_sixiang']}·{d['sishi_desc']})
圆 环:{d['circle']:.2f}°  进度:{d['prog'] * 100:.1f}%
当前时间:{now.strftime('%H:%M:%S')}
下一度:{d['next'].strftime('%H:%M:%S')}
剩 余:{str(d['remain']).split('.')[0]}

【卦辞详解】
{d['detail']}

────────────────────────────────────────────────────────────

【岁序系统 · 六十四卦气】
第{y['num']:02d}气 · {y['gua']}{y['title']} · {y['desc']}

八 节:{y['jie']}{y['jie_gua']}卦·{y['jie_fangwei']}·五行{y['wx']})
气 象:{y['jie_qixiang']}  天环中点:{y['jie_angle']}°
统 摄:第{y['jie_range'][0]}-{y['jie_range'][1]}{y['jie_range'][2]}
四 季:{y['season']}{y['season_sixiang']}·{y['season_desc']})
年 度:{y['year']}年(立春{y['lichun'].strftime('%Y-%m-%d %H:%M')})
太阳黄经:{y['sun']:.3f}°  圆环:{y['circle']:.2f}°  进度:{y['prog'] * 100:.1f}%
"""

            # 如果有天文特征,添加
            if y['astro_info']:
                text += f"""
【天文特征】
太阳黄经:{y['astro_info']['sun_range']}
气候意义:{y['astro_info']['climate']}
节气关联:{y['astro_info']['solar_term']}
"""

            text += f"""
【卦辞详解】
{y['detail']}

═══════════════════════════════════════════════════════════════
综合卦象:{y['gua']}{d['gua']}(岁序为本,一日为用)
═══════════════════════════════════════════════════════════════"""

            self.root.clipboard_clear()
            self.root.clipboard_append(text)
            self.st.config(text="✓ 已复制全部信息到剪贴板", fg='#4aa')
            self.root.after(2000,
                            lambda: self.st.config(text=f"{now.strftime('%Y-%m-%d %H:%M:%S')} | 丙午定本·方案B", fg='#666'))
        except Exception as e:
            messagebox.showerror("错误", f"复制失败: {e}")

    def toggle(self):
        self.run = not self.run
        if self.run:
            self.update()

    def show_wuji(self):
        """显示无极信息"""
        w = tk.Toplevel(self.root)
        w.title("无极——万化之源")
        w.geometry("500x300")
        w.configure(bg='#111')

        t = tk.Text(w, bg='#111', fg='#ccc', font=self.fm, wrap=tk.WORD, padx=20, pady=20)
        t.pack(fill=tk.BOTH, expand=True)

        info = self.calc.get_wuji_info()
        t.insert(tk.END, info['title'] + "\n\n", "title")
        t.insert(tk.END, info['desc'])
        t.tag_config("title", foreground="#e94560", font=self.fb)
        t.config(state=tk.DISABLED)

    def show_taiji(self):
        """显示太极信息"""
        w = tk.Toplevel(self.root)
        w.title("太极——岁序之根")
        w.geometry("500x300")
        w.configure(bg='#111')

        t = tk.Text(w, bg='#111', fg='#ccc', font=self.fm, wrap=tk.WORD, padx=20, pady=20)
        t.pack(fill=tk.BOTH, expand=True)

        info = self.calc.get_taiji_info()
        t.insert(tk.END, info['title'] + "\n\n", "title")
        t.insert(tk.END, info['desc'])
        t.tag_config("title", foreground="#4aa", font=self.fb)
        t.config(state=tk.DISABLED)

    def show_hanshu(self):
        """显示寒暑信息"""
        w = tk.Toplevel(self.root)
        w.title("寒暑——一岁之纲")
        w.geometry("500x300")
        w.configure(bg='#111')

        t = tk.Text(w, bg='#111', fg='#ccc', font=self.fm, wrap=tk.WORD, padx=20, pady=20)
        t.pack(fill=tk.BOTH, expand=True)

        info = self.calc.get_hanshu_info()
        t.insert(tk.END, info['title'] + "\n\n", "title")
        t.insert(tk.END, info['desc'])
        t.tag_config("title", foreground="#e94560", font=self.fb)
        t.config(state=tk.DISABLED)

    def birth(self):
        s = simpledialog.askstring("生日", "格式:1990-01-01 12:00", initialvalue="1990-01-01 12:00")
        if not s:
            return
        try:
            dt = datetime.strptime(s, "%Y-%m-%d %H:%M")
            c = self.calc.birth(dt)
            w = tk.Toplevel(self.root)
            w.title("命盘")
            w.geometry("600x500")
            w.configure(bg='#111')
            t = tk.Text(w, bg='#111', fg='#ccc', font=self.fm, wrap=tk.WORD, padx=15, pady=15)
            t.pack(fill=tk.BOTH, expand=True)

            t.insert(tk.END, f"出生时间:{dt.strftime('%Y年%m月%d日 %H时%M分')}\n\n")
            t.insert(tk.END, "【岁序本命】\n", "title1")
            t.insert(tk.END, f"第{c['y']['num']:02d}气 · {c['y']['gua']}{c['y']['title']}\n")
            t.insert(tk.END, f"八节:{c['y']['jie']}{c['y']['jie_gua']}卦·{c['y']['jie_fangwei']})\n")
            t.insert(tk.END, f"四季:{c['y']['season']}{c['y']['season_sixiang']})\n\n")

            t.insert(tk.END, "【一日本命】\n", "title2")
            t.insert(tk.END, f"第{c['d']['num']:02d}度 · {c['d']['gua']}{c['d']['title']}\n")
            t.insert(tk.END, f"八刻:{c['d']['ke_name']}{c['d']['ke_fangwei']}·{c['d']['sishi']})\n")
            t.insert(tk.END, f"时刻:{c['d']['degree_start']}-{c['d']['degree_end']}\n\n")

            t.insert(tk.END, f"综合卦象:{c['comp']}\n\n")

            t.insert(tk.END, "【岁序详解】\n", "title1")
            t.insert(tk.END, c['y']['detail'] + "\n\n")
            t.insert(tk.END, "【一日详解】\n", "title2")
            t.insert(tk.END, c['d']['detail'])

            t.tag_config("title1", foreground="#4aa", font=self.fb)
            t.tag_config("title2", foreground="#e94560", font=self.fb)
            t.config(state=tk.DISABLED)
        except Exception as e:
            messagebox.showerror("错误", str(e))

    def year(self):
        y = simpledialog.askinteger("年份", "请输入年份(1900-2100):",
                                    initialvalue=datetime.now().year,
                                    minvalue=1900, maxvalue=2100)
        if not y:
            return
        w = tk.Toplevel(self.root)
        w.title(f"{y}年卦气表")
        w.geometry("650x650")
        w.configure(bg='#111')

        frame = tk.Frame(w, bg='#111')
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        tr = ttk.Treeview(frame, columns=('q', 'g', 'j', 'jg', 't'), show='headings', height=30)
        tr.heading('q', text='气序')
        tr.heading('g', text='卦名')
        tr.heading('j', text='八节')
        tr.heading('jg', text='八节卦')
        tr.heading('t', text='起始时刻')
        tr.column('q', width=50, anchor='center')
        tr.column('g', width=70, anchor='center')
        tr.column('j', width=60, anchor='center')
        tr.column('jg', width=70, anchor='center')
        tr.column('t', width=200, anchor='center')

        # 设置Treeview样式
        style = ttk.Style()
        style.configure("Treeview", background='#222', foreground='#fff',
                        fieldbackground='#222', font=self.fs)
        style.configure("Treeview.Heading", background='#333', foreground='#fff', font=self.fb)

        sb = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tr.yview)
        tr.configure(yscrollcommand=sb.set)

        tr.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        sb.pack(side=tk.RIGHT, fill=tk.Y)

        for it in self.calc.year_table(y):
            tr.insert('', tk.END, values=(
                f"{it['qi']:02d}",
                it['gua'] + '气',
                it['jie'],
                it['jie_gua'],
                it['time'].strftime('%Y-%m-%d %H:%M')
            ))

    def detail(self):
        w = tk.Toplevel(self.root)
        w.title("卦辞详解")
        w.geometry("750x650")
        w.configure(bg='#111')

        nb = ttk.Notebook(w)
        nb.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        for name, data, color in [("一日系统", GUA_DAILY_FULL, '#e94560'),
                                  ("岁序系统", GUA_YEAR_FULL, '#4aa')]:
            f = tk.Frame(nb, bg='#111')
            nb.add(f, text=name)

            text_frame = tk.Frame(f, bg='#111')
            text_frame.pack(fill=tk.BOTH, expand=True)

            txt = tk.Text(text_frame, bg='#111', fg='#ccc', font=self.fm,
                          wrap=tk.WORD, padx=15, pady=15)
            sb = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=txt.yview)
            txt.configure(yscrollcommand=sb.set)

            txt.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
            sb.pack(side=tk.RIGHT, fill=tk.Y)

            for i, gua in enumerate(GUA_SEQUENCE):
                title, desc, detail = data.get(gua, ("", "", ""))
                txt.insert(tk.END, f"\n{'═' * 60}\n")
                txt.insert(tk.END,
                           f"第{i + 1:02d} {'度' if '一日' in name else '气'} · {gua}{'度' if '一日' in name else '气'}\n",
                           'title')
                txt.insert(tk.END, f"【{title}{desc}\n\n")
                txt.insert(tk.END, f"{detail}\n")

            txt.tag_config('title', foreground=color, font=self.fb)
            txt.config(state=tk.DISABLED)

    def export(self):
        fn = f"guaqi_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        d = self.calc.daily()
        y = self.calc.yearly()
        with open(fn, 'w', encoding='utf-8') as f:
            f.write(f"卦气正元历导出\n{'=' * 50}\n")
            f.write(f"时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")

            f.write("[无极]\n")
            f.write(f"{self.calc.get_wuji_info()['desc']}\n\n")
            f.write("[太极]\n")
            f.write(f"{self.calc.get_taiji_info()['desc']}\n\n")
            f.write("[寒暑]\n")
            f.write(f"{self.calc.get_hanshu_info()['desc']}\n\n")

            f.write(f"[一日系统·第{d['num']:02d}{d['gua']}度]\n")
            f.write(f"时间:{d['degree_start']}-{d['degree_end']}\n")
            f.write(f"八刻:{d['ke_name']}{d['ke_fangwei']})\n")
            f.write(f"四时:{d['sishi']}\n")
            f.write(f"{d['title']}\n{d['desc']}\n\n{d['detail']}\n\n")

            f.write(f"[岁序系统·第{y['num']:02d}{y['gua']}气]\n")
            f.write(f"八节:{y['jie']}{y['jie_gua']}卦·{y['jie_fangwei']})\n")
            f.write(f"四季:{y['season']}\n")
            f.write(f"{y['title']}\n{y['desc']}\n\n{y['detail']}\n")

        messagebox.showinfo("导出成功", f"已保存至:{fn}")

    def about(self):
        about_text = """卦气正元历 · 丙午定本 · 完整版

方案B:太阳黄经驱动(非平均天数)
内置:1900-2100年立春精确时刻
算法:VSOP87行星理论简化版
精度:±0.5°(足够64等分)

【理论体系】
无极 → 太极 → 寒暑 → 四季 → 八节 → 六十四气(岁序)
无极 → 太极 → 昼夜 → 四时 → 八刻 → 六十四度(一日)

【核心模型】
• 360°圆环宇宙模型
• 后天八卦顺时针旋转
• 洛书方位:上离下坎、左震右兑

【特点】
• 一日64度 × 22.5分钟 = 24小时
• 一年64气 × 5.625°黄经 = 360°
• 坎至履卦序贯通双系统
• 全部64卦完整卦辞详解
• 八刻四时完整对应
• 八节四季完整体系
• 一键复制全部信息
• 零外部依赖 · 开箱即用

原创易理时序体系,专主一日及一年岁时统摄。
仅供国学文化研究、学术探讨、个人娱乐参考。"""

        messagebox.showinfo("关于卦气正元历", about_text)


def main():
    root = tk.Tk()
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass
    App(root)
    root.mainloop()


if __name__ == "__main__":
    main()

更多推荐