diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b510ef..0ff1ebc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,45 @@ # 印度占星 Skill 更新日志 +## v6.0.16-marriage-counting-d30-muntha-prashna(2026-06-04)—— 新增 Marriage Counting + D30 + Muntha(占位) + Prashna(占位) + +> **触发原因**:用户要求继续补充印度占星 skill 缺少的技法。审计报告显示:Marriage Counting(精确)、D30 Trimshamsa(基础)、Muntha(缺失)、Prashna(未接入full-reading)为 P0/P1 缺失项。 + +### 新增功能 + +- `scripts/marriage_counting.py`(新文件):Bhrigu 婚姻计数法 + - `marriage_counting_method(d1_7lord, d1_lons, d9_lons, ...)`:精确婚姻计数算法(D1 7宫主星座距离法) + - `marriage_counting_full_analysis(...)`:完整分析(含 D9 质量评估) + - `_check_parivartana()`:Parivartana(行星交换)检测与警告 +- `scripts/trimshamsa_d30.py`(新文件):D30 Trimshamsa 分盘 + - `calc_d30_chart(planet_lons)`:D30 分盘行星位置计算 + - `d30_full_report(birth_planet_lons)`:D30 完整报告 + - `analyze_d30_marriage_crisis(d30_planets)`:D30 婚姻危机分析(简化版) +- `scripts/muntha.py`(新文件):Muntha(Tajika 年运盘核心指标) + - `calc_muntha_from_sun_sign(sun_sign_vp, age)`:Muntha 计算(从 Varshaphala 太阳星座) + - `muntha_full_analysis(vp_sun_sign, vp_age, vp_planet_lons, vp_houses)`:Muntha 完整分析 + - `calc_yoga_from_muntha(muntha_sign, planet_lons_vp, house_data_vp)`:Muntha Tajika Yoga 分析 +- `scripts/jyotish_engine.py` 的 `cmd_full_reading` 新增 Step 4.11: + - 调用 `marriage_counting_full_analysis` → `modules.marriage_counting` + - 调用 `d30_full_report` → `modules.trimshamsa_d30` + - Muntha:占位符(需 Varshaphala 数据,v6.0.17 实现) + - Prashna:占位符(独立命令可用,full-reading 接入 v6.0.17) +- `references/technique_registry.json` 新增 4 个技法注册 + +### 技法状态变更 + +| 技法 | 原状态 | 新状态 | 说明 | +|------|--------|--------|------| +| marriage_counting | missing | partial | 精确算法已实现,Dasha 集成待完善 | +| trimshamsa_d30 | missing | partial | 基础 D30 计算已实现,宫位数据待补充 | +| muntha | missing | missing | 仅占位符,Varshaphala 数据依赖未解决 | +| prashna_integration | missing | partial | 独立命令可用,full-reading 接入待完成 | + +### 已知限制 + +- Muntha 完整计算需要 Varshaphala(太阳返照)排盘数据 → v6.0.17 +- Prashna full-reading 接入需要 Prashna 盘数据 → v6.0.17 +- D30 宫位计算需要 D30 上升度 → 依赖专业天文软件 + ## v6.0.15-tithi-pakshi-rt-navamsa(2026-06-04)—— 新增 Tithi Lord + Pancha Pakshi + Rashi Tulya Navamsa > **触发原因**:用户要求继续补充印度占星 skill 缺少的技法。P1 级剩余技法:Tithi Lord、Pancha Pakshi、Rashi Tulya Navamsa、Bhrigu Pada Dasha、KP Sub-Lord、Prashna、Gochara complete。本轮实现前 3 项。 diff --git a/SKILL.md b/SKILL.md index 0c62b6bd..755761f1 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: jyotish-vedic-astrology -version: 6.0.15 +version: 6.0.16 description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、PDF星盘、读取PDF、分析PDF星盘、现代解读、误判纠错、Varga分盘、综合分析、过境分析、合盘、婚姻匹配、年运盘、Prashna、Argala、Jaimini、Shadbala、Ashtakavarga、HTML报告、深度解盘。 --- diff --git a/references/technique_registry.json b/references/technique_registry.json index 7e691303..5674c50e 100644 --- a/references/technique_registry.json +++ b/references/technique_registry.json @@ -1,5 +1,5 @@ { - "version": "v6.0.15-tithi-pakshi-rt-navamsa", + "version": "v6.0.16-marriage-counting-d30-muntha-prashna", "source_inspiration": [ { "name": "jyotishyamitra", @@ -692,6 +692,88 @@ ], "audit_label": "Rashi Tulya Navamsa", "missing_impact": "D1-D9 同宫对比分析不完整,婚姻/内在潜力判断受限。" + }, + "marriage_counting": { + "name": "Marriage Counting Method / 婚姻计数法", + "domains": [ + "marriage", + "bhrigu", + "counting", + "d1_d9" + ], + "status": "partial", + "knowledge_refs": [ + "bhrigu-pada-dasha-marriage-counting.md" + ], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.marriage_counting" + ], + "audit_label": "Marriage Counting", + "missing_impact": "婚姻数量判断不完整,关系模式分析受限。" + }, + "trimshamsa_d30": { + "name": "Trimshamsa D30 / 三十分盘", + "domains": [ + "varga", + "d30", + "crisis", + "disaster" + ], + "status": "partial", + "knowledge_refs": [ + "varga-system-quick-reference.md" + ], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.trimshamsa_d30" + ], + "audit_label": "D30 Trimshamsa", + "missing_impact": "D30 灾难分析不完整,危机事件判断受限。" + }, + "muntha": { + "name": "Muntha / 年运之主 (Tajika)", + "domains": [ + "tajika", + "varsha_phal", + "muntha", + "annual" + ], + "status": "missing", + "knowledge_refs": [ + "tajika-yoga-complete-guide.md" + ], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.muntha" + ], + "audit_label": "Muntha", + "missing_impact": "Varshaphala 年运盘核心指标缺失,年度主题判断受限。" + }, + "prashna_integration": { + "name": "Prashna Integration / 问事占星接入", + "domains": [ + "prashna", + "standalone", + "full_reading_integration" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading", + "prashna" + ], + "output_paths": [ + "modules.prashna" + ], + "audit_label": "Prashna Integration", + "missing_impact": "Prashna 未接入 full-reading,问事分析不完整。" } }, "routes": { @@ -735,7 +817,11 @@ "upapada_lagna", "tithi_lord", "pancha_pakshi", - "rashi_tulya_navamsa" + "rashi_tulya_navamsa", + "marriage_counting", + "trimshamsa_d30", + "muntha", + "prashna_integration" ], "optional_techniques": [ "bhava_chalit", @@ -775,7 +861,11 @@ "upapada_lagna", "tithi_lord", "pancha_pakshi", - "rashi_tulya_navamsa" + "rashi_tulya_navamsa", + "marriage_counting", + "trimshamsa_d30", + "muntha", + "prashna_integration" ], "optional_techniques": [ "d9_navamsa", @@ -821,7 +911,11 @@ "upapada_lagna", "tithi_lord", "pancha_pakshi", - "rashi_tulya_navamsa" + "rashi_tulya_navamsa", + "marriage_counting", + "trimshamsa_d30", + "muntha", + "prashna_integration" ], "optional_techniques": [ "bhava_chalit", diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index c8d6bf6b..7ae3fe24 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -3550,6 +3550,45 @@ def cmd_full_reading(args): except Exception as e: report['errors'].append(f"rashi-tulya-navamsa: {e}") + # ── Step 4.11: Marriage Counting + Muntha + D30 + Prashna (v6.0.16) ── + try: + # Marriage Counting Method (Bhrigu) + from marriage_counting import marriage_counting_full_analysis + d1_house7_lord = houses.get('7', {}).get('lord', '') if isinstance(houses.get('7'), dict) else '' + if d1_house7_lord and 'varga_full' in report['modules']: + d9_data = report['modules']['varga_full'].get('D9_Navamsa', {}) + if d9_data.get('planets'): + mc_result = marriage_counting_full_analysis( + d1_house7_lord, planet_lons, d9_data['planets'], + houses, d9_data.get('houses') + ) + report['modules']['marriage_counting'] = mc_result + except Exception as e: + report['errors'].append(f"marriage-counting: {e}") + + try: + # Muntha (Tajika Varshaphala) - needs Varshaphala chart data + # For now, only calculate if Varshaphala data is available + # Placeholder: will be filled when Varshaphala casting is implemented + report['modules']['muntha'] = {'note': 'Muntha calculation requires Varshaphala chart data (solar return). Placeholder for v6.0.17.'} + except Exception as e: + report['errors'].append(f"muntha: {e}") + + try: + # D30 Trimshamsa analysis + from trimshamsa_d30 import d30_full_report + d30_result = d30_full_report(planet_lons) + report['modules']['trimshamsa_d30'] = d30_result + except Exception as e: + report['errors'].append(f"trimshamsa-d30: {e}") + + try: + # Prashna integration (limited - only if prashna data is available) + # Prashna is mainly a standalone command; full integration in v6.0.17 + report['modules']['prashna'] = {'note': 'Prashna is available via cmd_prashna standalone command. Full integration pending v6.0.17.'} + except Exception as e: + report['errors'].append(f"prashna: {e}") + # ── Step 5: 精确相位 ── try: from aspects import calc_all_aspects diff --git a/scripts/marriage_counting.py b/scripts/marriage_counting.py new file mode 100644 index 00000000..5704d252 --- /dev/null +++ b/scripts/marriage_counting.py @@ -0,0 +1,304 @@ +""" +Marriage Counting Method (婚姻计数法) —— Bhrigu 体系 +Jyotish Vedic Astrology Skill + +来源:bhrigu-pada-dasha-marriage-counting.md +算法:D1 第7宫主在 D1 的星座(A) → D9 的星座(B) → 从A数到B = 婚姻次数 +""" +from typing import Dict, Optional, List + + +# 星座名称 +SIGN_CN = ['白羊座','金牛座','双子座','巨蟹座','狮子座','处女座', + '天秤座','天蝎座','射手座','摩羯座','水瓶座','双鱼座'] + + +def sign_of(lon: float) -> int: + """从黄道经度计算星座序号 (0-11)""" + return int((lon % 360) / 30) + + +def marriage_counting_method( + d1_house7_lord: str, + d1_planet_lons: Dict[str, float], + d9_planet_lons: Dict[str, float], + d1_houses: Optional[Dict] = None, + d9_houses: Optional[Dict] = None, + parivartana_check: bool = True +) -> Dict: + """ + 婚姻计数法 (Marriage Counting Method) + + 参数: + d1_house7_lord: D1 第7宫主星名称 (如 'Venus') + d1_planet_lons: D1 行星经度字典 + d9_planet_lons: D9 行星经度字典 + d1_houses: D1 宫位数据 (可选,用于 Parivartana 检查) + d9_houses: D9 宫位数据 (可选) + parivartana_check: 是否检查 Parivartana (默认 True) + + 返回: + dict: { + 'method': 'Marriage Counting Method', + 'd1_7th_lord': str, + 'point_A': {'sign': int, 'sign_cn': str}, # D1 中7宫主星座 + 'point_B': {'sign': int, 'sign_cn': str}, # D9 中7宫主星座 + 'distance': int, # 从A数到B (包含A和B) + 'marriage_count': int, # 婚姻/认真关系数量 + 'interpretation': str, # 解读 + 'parivartana': dict or None, # Parivartana 检查结果 + 'warnings': list, + } + """ + warnings = [] + + # Step 1: 找到 D1 第7宫主 + if not d1_house7_lord: + return {'error': '未提供 D1 第7宫主', 'method': 'Marriage Counting Method'} + + # Step 2: 找到 7宫主在 D1 中的星座 (A) + if d1_house7_lord not in d1_planet_lons: + warnings.append(f"D1 中未找到 {d1_house7_lord} 的位置") + return {'error': f"D1 中未找到 {d1_house7_lord}", 'method': 'Marriage Counting Method'} + + d1_lon = d1_planet_lons[d1_house7_lord] + point_A = sign_of(d1_lon) + + # Step 3: 找到 7宫主在 D9 中的星座 (B) + if d1_house7_lord not in d9_planet_lons: + warnings.append(f"D9 中未找到 {d1_house7_lord} 的位置") + return {'error': f"D9 中未找到 {d1_house7_lord}", 'method': 'Marriage Counting Method'} + + d9_lon = d9_planet_lons[d1_house7_lord] + point_B = sign_of(d9_lon) + + # Parivartana 检查 + parivartana = None + if parivartana_check and d1_houses: + parivartana = _check_parivartana( + d1_house7_lord, point_A, d1_houses, d1_planet_lons + ) + if parivartana and parivartana.get('has_parivartana'): + warnings.append( + f"⚠️ 发现 Parivartana(行星交换)!" + f" {parivartana['planet1']} 与 {parivartana['planet2']} 交换宫位。" + f" 需使用交换后的星座重新计算。" + ) + # TODO: 实现 Parivartana 后的重新计算 + # 当前版本仅警告,不自动重算 + + # Step 4: 计数 (从 A 到 B,包含 A 和 B) + if point_B >= point_A: + distance = point_B - point_A + 1 + else: + # 跨越白羊座0°: 从 A 到双鱼座(11) + 从白羊座(0) 到 B + distance = (11 - point_A + 1) + (point_B + 1) + + marriage_count = distance + + # 解读 + interpretation = _interpret_marriage_count(marriage_count, point_A, point_B) + + return { + 'method': 'Marriage Counting Method (Bhrigu)', + 'd1_7th_lord': d1_house7_lord, + 'point_A': { + 'sign': point_A, + 'sign_cn': SIGN_CN[point_A], + 'degree': d1_lon, + }, + 'point_B': { + 'sign': point_B, + 'sign_cn': SIGN_CN[point_B], + 'degree': d9_lon, + }, + 'distance': distance, + 'marriage_count': marriage_count, + 'interpretation': interpretation, + 'parivartana': parivartana, + 'warnings': warnings, + } + + +def _check_parivartana( + lord: str, + lord_sign: int, + d1_houses: Dict, + d1_planet_lons: Dict[str, float] +) -> Dict: + """ + 检查 7宫主是否与其落入星座的主星有 Parivartana(行星交换) + + 返回: {'has_parivartana': bool, 'planet1': str, 'planet2': str, ...} + """ + # 找到 lord 落入星座的主星 + SIGN_LORDS = ['Mars','Venus','Mercury','Moon','Sun','Mercury', + 'Venus','Mars','Jupiter','Saturn','Saturn','Jupiter'] + host = SIGN_LORDS[lord_sign] # lord 落入星座的主星 + + if host not in d1_planet_lons: + return {'has_parivartana': False, 'reason': f'{host} 位置未知'} + + host_sign = sign_of(d1_planet_lons[host]) + lord_own_sign = sign_of(d1_planet_lons.get(lord, 0)) + + # Parivartana: lord 在 host 的星座里,host 在 lord 的星座里 + if host_sign == lord_own_sign and lord_sign == sign_of(d1_planet_lons.get(host, 0)): + return { + 'has_parivartana': True, + 'planet1': lord, + 'planet1_sign': lord_sign, + 'planet2': host, + 'planet2_sign': host_sign, + 'note': f'{lord}(在{ SIGN_CN[lord_sign]}) 与 {host}(在{ SIGN_CN[host_sign]}) 交换宫位', + } + + return {'has_parivartana': False} + + +def _interpret_marriage_count(count: int, A: int, B: int) -> str: + """解读婚姻计数结果""" + lines = [] + lines.append(f"婚姻/认真关系数量:{count}") + + if count == 1: + lines.append("解读:一次终身关系,忠诚度较高。") + if A == B: + lines.append(" D1与D9同星座 → 关系稳定,不易动摇。") + elif count == 2: + lines.append("解读:两段重要关系,可能再婚或长期关系更替。") + elif count == 3: + lines.append("解读:多段关系,关系模式较为复杂。") + elif count >= 4: + lines.append(f"解读:{count}段关系,关系频繁变化,需检视关系模式中的重复问题。") + + # 特殊位置解读 + if A == B: + lines.append("⭐ A=B(D1与D9同星座):内在一致,关系忠诚度高。") + if (B - A) % 12 == 6: # 对冲 + lines.append("⚠️ A与B对冲:内在矛盾,关系中的拉锯与不稳定性。") + + return "\n".join(lines) + + +def marriage_counting_full_analysis( + d1_house7_lord: str, + d1_planet_lons: Dict[str, float], + d9_planet_lons: Dict[str, float], + d1_houses: Optional[Dict] = None, + d9_houses: Optional[Dict] = None, + d1_moon_nak_idx: Optional[int] = None, + d9_upapada_lord: Optional[str] = None, +) -> Dict: + """ + 完整婚姻计数分析(配合 Dasha + D9 验证) + + 返回包含婚姻计数 + D9 质量评估 + 综合建议 + """ + # 基础计数 + base = marriage_counting_method( + d1_house7_lord, d1_planet_lons, d9_planet_lons, + d1_houses, d9_houses + ) + + if 'error' in base: + return base + + # D9 质量评估(简化版) + d9_quality = _assess_d9_marriage_quality(d9_planet_lons, d9_houses) + + # 综合建议 + recommendations = _marriage_recommendations(base, d9_quality) + + return { + **base, + 'd9_marriage_quality': d9_quality, + 'recommendations': recommendations, + 'note': '此法的"婚姻"指持续1年以上的认真关系,不一定是法律婚姻。', + } + + +def _assess_d9_marriage_quality( + d9_planet_lons: Dict[str, float], + d9_houses: Optional[Dict] +) -> Dict: + """简化版 D9 婚姻质量评估""" + quality_points = 0 + factors = [] + + # 检查 D9 中 Venus 状态 + venus_d9 = d9_planet_lons.get('Venus') + if venus_d9 is not None: + venus_sign = sign_of(venus_d9) + # 入庙/本宫加分 + if venus_sign in [1, 6]: # Taurus or Libra + quality_points += 2 + factors.append("D9 金星入庙 → 婚姻关系质量高") + elif venus_sign in [2, 3, 9]: # Gemini, Cancer, Sagittarius (friends) + quality_points += 1 + factors.append("D9 金星在友宫 → 婚姻关系尚可") + elif venus_sign in [7, 10]: # Scorpio, Capricorn (debilated/ruled by enemies) + quality_points -= 1 + factors.append("⚠️ D9 金星受克 → 婚姻关系有挑战") + + # 检查 D9 中 7宫/7宫主 + if d9_houses and '7' in d9_houses: + h7_d9 = d9_houses['7'] + if isinstance(h7_d9, dict) and 'lord' in h7_d9: + h7_lord_d9 = h7_d9['lord'] + factors.append(f"D9 第7宫主:{h7_lord_d9}") + + # 综合评级 + if quality_points >= 2: + rating = "高(关系质量好,伴侣支持强)" + elif quality_points >= 0: + rating = "中(关系质量一般,需经营)" + else: + rating = "低(关系质量有挑战,需注意沟通)" + + return { + 'quality_rating': rating, + 'quality_points': quality_points, + 'factors': factors, + } + + +def _marriage_recommendations(base: Dict, d9_quality: Dict) -> List[str]: + """生成综合建议""" + recs = [] + count = base['marriage_count'] + + if count == 1: + recs.append("重点经营唯一关系,避免第三者介入。") + elif count == 2: + recs.append("第一次关系需认真经营;若结束,第二次关系质量需提前评估。") + else: + recs.append("需检视关系模式中的重复问题(依恋类型、沟通方式等)。") + + # D9 质量建议 + q_rating = d9_quality['quality_rating'] + if '低' in q_rating: + recs.append("D9显示婚姻关系有挑战 → 建议在Dasha吉期内主动经营关系。") + elif '高' in q_rating: + recs.append("D9显示婚姻关系质量高 → 珍惜并维护现有关系。") + + recs.append("建议配合 Vimshottari/Chara Dasha 确认具体结婚/分手时间。") + recs.append("注意:此法给出数量框架,具体事件需通过 Dasha + Transit 精确定位。") + + return recs + + +# 导出函数 +def calc_marriage_count(d1_7lord, d1_lons, d9_lons, d1_h=None, d9_h=None): + """便捷函数:计算婚姻计数""" + return marriage_counting_method(d1_7lord, d1_lons, d9_lons, d1_h, d9_h) + + +if __name__ == '__main__': + # 测试:假设 D1 7宫主 = Venus,D1 Venus 在 Gemini(2),D9 Venus 在 Virgo(5) + test = marriage_counting_method( + 'Venus', + {'Venus': 2*30 + 15}, # Gemini 15° + {'Venus': 5*30 + 10}, # Virgo 10° + ) + print(test) diff --git a/scripts/muntha.py b/scripts/muntha.py new file mode 100644 index 00000000..1c3b5636 --- /dev/null +++ b/scripts/muntha.py @@ -0,0 +1,260 @@ +""" +Muntha (Varshaphala 年运盘核心指标) 计算模块 +Jyotish Vedic Astrology Skill + +Muntha 是 Tajika 年运盘(Varshaphala)中的核心指标, +代表该年度的"年度之主",用于判断年度主旋律。 + +计算原理: +1. 计算太阳返照时间(Solar Return)——太阳回到出生太阳精确位置的时刻 +2. 以太阳返照时刻排盘,得到 Varshaphala 年运盘 +3. Muntha = 从年运盘太阳星座开始,向前数(当前年龄-1)mod 12 + 1 个星座 + Muntha 所在星座 = (Solar Return Sun sign + (age - 1) mod 12) + 如果结果 >= 12,则减 12 + +注意:不同流派对 Muntha 计算公式有微小差异。 +本实现采用最广泛接受的方法。 +""" +from typing import Dict, Optional +from datetime import datetime, timedelta + + +# 星座名称 +SIGN_CN = ['白羊座','金牛座','双子座','巨蟹座','狮子座','处女座', + '天秤座','天蝎座','射手座','摩羯座','水瓶座','双鱼座'] + +# 星座守护星(用于判断 Muntha 守护星) +SIGN_LORDS = ['Mars','Venus','Mercury','Moon','Sun','Mercury', + 'Venus','Mars','Jupiter','Saturn','Saturn','Jupiter'] + + +def calc_muntha(solar_return_dt: datetime, birth_year: int, + age: Optional[int] = None) -> Dict: + """ + 计算 Muntha(年度之主) + + 参数: + solar_return_dt: 太阳返照时间(datetime) + birth_year: 出生年份 + age: 当前年龄(可选,不提供则自动计算) + + 返回: + dict: { + 'muntha_sign': int, # 0-11 + 'muntha_sign_cn': str, + 'muntha_lord': str, # 守护星 + 'muntha_lord_cn': str, + 'solar_return_dt': str, # 太阳返照时间 + 'age_at_return': int, # 返照时的年龄 + 'calculation_note': str, + } + """ + if age is None: + age = solar_return_dt.year - birth_year + + # 太阳返照盘中的太阳星座 + # 简化:假设 solar_return_dt 时刻的太阳黄道经度已计算好 + # 实际使用中,需要从 Varshaphala 盘数据获取太阳经度 + # 这里提供一个接口,接受太阳经度作为参数更合理 + + return { + 'note': 'calc_muntha 需要 Varshaphala 盘的太阳经度,请使用 calc_muntha_from_sun_sign', + 'solar_return_dt': solar_return_dt.isoformat() if solar_return_dt else None, + } + + +def calc_muntha_from_sun_sign(sun_sign_vp: int, age: int) -> Dict: + """ + 从 Varshaphala 盘太阳星座计算 Muntha + + 参数: + sun_sign_vp: Varshaphala 盘中太阳所在星座 (0-11) + age: 该年度的年龄(年运盘对应的年龄) + + 返回: + dict: Muntha 信息 + """ + # Muntha 公式:(sun_sign_vp + (age - 1)) mod 12 + muntha_sign = (sun_sign_vp + (age - 1)) % 12 + muntha_lord = SIGN_LORDS[muntha_sign] + muntha_lord_cn = {'Sun':'太阳','Moon':'月亮','Mars':'火星','Mercury':'水星', + 'Jupiter':'木星','Venus':'金星','Saturn':'土星'}.get(muntha_lord, muntha_lord) + + return { + 'muntha_sign': muntha_sign, + 'muntha_sign_cn': SIGN_CN[muntha_sign], + 'muntha_lord': muntha_lord, + 'muntha_lord_cn': muntha_lord_cn, + 'age': age, + 'formula': f'(太阳星座{sun_sign_vp} + 年龄{age}-1) mod 12 = {muntha_sign}', + 'interpretation': _interpret_muntha(muntha_sign, muntha_lord), + } + + +def _interpret_muntha(sign: int, lord: str) -> str: + """Muntha 基础解读""" + interpretations = { + 0: "Muntha 在白羊座:该年度精力充沛,主动开启新项目,可能有新的开始。", + 1: "Muntha 在金牛座:该年度注重财务和物质稳定,适合投资和积累。", + 2: "Muntha 在双子座:该年度沟通、学习、短途旅行活跃,信息处理量大。", + 3: "Muntha 在巨蟹座:该年度注重家庭、情感和安全感,家庭事务重要。", + 4: "Muntha 在狮子座:该年度创造力强,关注自我表达和子女,可能有创作项目。", + 5: "Muntha 在处女座:该年度注重健康、服务和日常工作,细节管理重要。", + 6: "Muntha 在天秤座:该年度注重关系、合作和伴侣,婚姻/合伙事务活跃。", + 7: "Muntha 在天蝎座:该年度深入转型,可能涉及财务共享、心理探索或危机处理。", + 8: "Muntha 在射手座:该年度注重高等学习、长途旅行、哲学/宗教事务。", + 9: "Muntha 在摩羯座:该年度注重事业、社会地位和长期规划,职业上有重要进展。", + 10: "Muntha 在水瓶座:该年度注重社交网络、团体活动和创新思维。", + 11: "Muntha 在双鱼座:该年度注重灵性、慈悲服务和潜意识探索。", + } + return interpretations.get(sign, f"Muntha 在 {SIGN_CN[sign]}") + + +def calc_yoga_from_muntha(muntha_sign: int, planet_lons_vp: Dict[str, float], + house_data_vp: Dict) -> Dict: + """ + 基于 Muntha 的 Tajika Yoga 分析(Varshaphala 年运盘) + + 分析 Muntha 与其他行星的 Tajika Yoga 关系(Ithasala/Easarapha 等) + """ + from .tajika import calc_tajika_yogas # 复用已有 Tajika Yoga 计算 + + # 将 Muntha 视为一颗"虚拟行星"参与 Tajika Yoga 计算 + muntha_lon = muntha_sign * 30 + 15 # 取星座中点 + all_lons = dict(planet_lons_vp) + all_lons['Muntha'] = muntha_lon + + yogas = calc_tajika_yogas(all_lons) + + # 筛选涉及 Muntha 的 Yoga + muntha_yogas = [] + for y in yogas.get('yogas', []): + if 'Muntha' in y.get('involved', []): + muntha_yogas.append(y) + + return { + 'muntha_sign': muntha_sign, + 'muntha_lon': muntha_lon, + 'muntha_yogas': muntha_yogas, + 'all_yogas': yogas, + 'interpretation': _interpret_muntha_yogas(muntha_yogas), + } + + +def _interpret_muntha_yogas(yogas: List[Dict]) -> str: + """解读涉及 Muntha 的 Tajika Yoga""" + if not yogas: + return "Muntha 未形成显著的 Tajika Yoga,该年度主旋律较平稳。" + + lines = ["涉及 Muntha 的 Tajika Yoga:"] + for y in yogas: + y_type = y.get('type', 'unknown') + involved = y.get('involved', []) + lines.append(f" - {y_type}: {involved} → {y.get('interpretation', '')[:60]}") + + return "\n".join(lines) + + +# Varshaphala(太阳返照盘)辅助函数 + +def estimate_solar_return_ut(birth_sun_lon: float, target_year: int, + tz_offset: float = 0) -> Dict: + """ + 估算太阳返照 UTC 时间(简化版) + + 参数: + birth_sun_lon: 出生太阳黄道经度 + target_year: 目标年份(计算该年的太阳返照) + tz_offset: 时区偏移(小时),用于转换到本地时间 + + 返回: + dict: {'utc_dt': datetime, 'local_dt': datetime, 'note': str} + + 注意:这是估算值,精确计算需要天文算法(pyswisseph)。 + """ + # 简化:假设太阳每天移动 ~1°,找到太阳经度 = birth_sun_lon 的日期 + # 实际应使用 pyswisseph 的 swe_calc_ut 进行精确计算 + return { + 'note': '精确太阳返照时间计算需要 pyswisseph 支持,当前为估算值', + 'suggest': '使用 pyswisseph.swe_calc_ut 计算太阳精确位置,然后二分搜索', + } + + +def muntha_full_analysis(vp_sun_sign: int, vp_age: int, + vp_planet_lons: Dict[str, float], + vp_houses: Dict) -> Dict: + """ + Muntha 完整分析(Varshaphala 年运盘) + + 参数: + vp_sun_sign: Varshaphala 盘太阳星座 (0-11) + vp_age: 年运盘对应年龄 + vp_planet_lons: Varshaphala 盘行星经度 + vp_houses: Varshaphala 盘宫位数据 + """ + # 1. 计算 Muntha + muntha = calc_muntha_from_sun_sign(vp_sun_sign, vp_age) + + # 2. Muntha 在 Varshaphala 盘中的位置 + muntha_sign = muntha['muntha_sign'] + vp_house_of_muntha = None + for h_num, h_data in vp_houses.items(): + if isinstance(h_data, dict) and h_data.get('sign') == muntha_sign: + vp_house_of_muntha = int(h_num) + break + elif isinstance(h_data, int) and h_data == muntha_sign: + vp_house_of_muntha = int(h_num) + break + + # 3. Muntha Tajika Yoga 分析 + yoga_analysis = calc_yoga_from_muntha(muntha_sign, vp_planet_lons, vp_houses) + + # 4. 综合解读 + synthesis = _synthesize_muntha_analysis( + muntha, vp_house_of_muntha, yoga_analysis + ) + + return { + 'muntha': muntha, + 'vp_house_of_muntha': vp_house_of_muntha, + 'yoga_analysis': yoga_analysis, + 'synthesis': synthesis, + 'method': 'Muntha (Tajika Varshaphala)', + 'note': 'Varshaphala 精确排盘需太阳返照时刻,建议配合 pyswisseph 使用', + } + + +def _synthesize_muntha_analysis(muntha: Dict, vp_house: Optional[int], + yoga: Dict) -> str: + """综合解读 Muntha 分析""" + lines = [] + m_sign_cn = muntha['muntha_sign_cn'] + m_lord_cn = muntha['muntha_lord_cn'] + + lines.append(f"【Muntha 分析】") + lines.append(f" Muntha在 {m_sign_cn},守护星 {m_lord_cn}") + lines.append(f" {muntha['interpretation']}") + + if vp_house: + lines.append(f" Varshaphala 盘中 Muntha 在第 {vp_house} 宫") + if vp_house in [1,4,7,10]: + lines.append(f" → Muntha在角宫:该年度事件主导性强,主动权在握") + elif vp_house in [2,5,8,11]: + lines.append(f" → Muntha在固定宫:该年度稳步积累,成果可持续") + else: + lines.append(f" → Muntha在双体宫:该年度变化多,需灵活应对") + + lines.append(f"\n【Muntha Tajika Yoga】") + lines.append(yoga['interpretation']) + + return "\n".join(lines) + + +if __name__ == '__main__': + # 测试 + m = calc_muntha_from_sun_sign(0, 33) # 太阳在白羊座,年龄33岁 + print("Muntha 测试:") + print(m) + print() + a = muntha_full_analysis(0, 33, {'Sun': 15, 'Moon': 45, 'Jupiter': 90}, {1:0, 2:1, 3:2, 4:3, 5:4, 6:5, 7:6, 8:7, 9:8, 10:9, 11:10, 12:11}) + print(a['synthesis']) diff --git a/scripts/trimshamsa_d30.py b/scripts/trimshamsa_d30.py new file mode 100644 index 00000000..b476fc45 --- /dev/null +++ b/scripts/trimshamsa_d30.py @@ -0,0 +1,145 @@ +""" +Trimshamsa D30 分盘计算模块 +Jyotish Vedic Astrology Skill + +D30 (Trimsamsa,三十分盘): +- 每个星座(30°)分为30等份(每份1°) +- 第1份(0-1°)→起始星座,第2份(1-2°)→下一星座,... 循环 +- 用于分析灾难、苦难、重大危机事件 + +来源:Parashara Hora Shastra + 现代应用指南 +""" +from typing import Dict, List, Optional + + +SIGN_CN = ['白羊座','金牛座','双子座','巨蟹座','狮子座','处女座', + '天秤座','天蝎座','射手座','摩羯座','水瓶座','双鱼座'] + +# D30 每个星座的起始映射(Parashara 规则) +# 白羊座30°÷30=1°/份,依次分配给12星座循环 +# 份0(0-1°)→白羊,份1(1-2°)→金牛,...份11(11-12°)→双鱼,份12(12-13°)→白羊... +D30_SIGN_MAP = [] +for sign_start in range(12): + row = [] + for part in range(30): + target_sign = (sign_start + part) % 12 + row.append(target_sign) + D30_SIGN_MAP.append(row) + + +def calc_d30_sign(longitude: float) -> int: + """ + 计算 D30 分盘中的星座 + + 参数: + longitude: 行星黄道经度 (0-360) + 返回: + D30 中的星座序号 (0-11) + """ + sign = int(longitude // 30) # 本命星座 0-11 + deg_in_sign = longitude % 30 # 在星座内的度数 0-29.999 + part = int(deg_in_sign) # 第几份 0-29 + + d30_sign = D30_SIGN_MAP[sign][part] + return d30_sign + + +def calc_d30_chart(planet_lons: Dict[str, float]) -> Dict: + """ + 计算完整 D30 分盘 + + 参数: + planet_lons: 本命行星经度字典 {'Sun': lon, 'Moon': lon, ...} + 返回: + dict: {'planets': {planet: {'d30_sign': int, 'd30_sign_cn': str}}, + 'houses': {...}} # 简化版暂不计算宫位 + """ + d30_planets = {} + for pname, lon in planet_lons.items(): + d30_s = calc_d30_sign(lon) + d30_planets[pname] = { + 'd30_longitude': d30_s * 30 + (lon % 30), # 简化经度 + 'd30_sign': d30_s, + 'd30_sign_cn': SIGN_CN[d30_s], + } + + # 简化:不计算 D30 宫位(需要 D30 上升度) + return { + 'chart': 'D30_Trimshamsa', + 'meaning': '灾难、苦难、重大危机、深层业力', + 'planets': d30_planets, + 'note': 'D30 宫位计算需要 D30 上升度(基于出生时间和地点),当前仅提供行星 D30 星座', + } + + +def analyze_d30_marriage_crisis(d30_planets: Dict) -> Dict: + """ + D30 婚姻危机分析(简化版) + + D30 中第7宫(伴侣)/第8宫(危机)/第12宫(损失)的行星状态 + 用于判断婚姻中的深层危机模式 + """ + # 简化:检查金星、7宫主、12宫主在 D30 中的状态 + crisis_factors = [] + + venus_d30 = d30_planets.get('Venus', {}).get('d30_sign') + if venus_d30 is not None: + crisis_factors.append(f"D30 金星在 {SIGN_CN[venus_d30]}") + + return { + 'd30_marriage_crisis': crisis_factors, + 'note': 'D30 完整分析需要 D30 宫位数据,建议使用专业软件(如 Jagannatha Hora)', + } + + +def d30_full_report(birth_planet_lons: Dict[str, float]) -> Dict: + """ + D30 完整报告(简化版) + """ + d30 = calc_d30_chart(birth_planet_lons) + crisis = analyze_d30_marriage_crisis(d30['planets']) + + return { + 'd30_chart': d30, + 'marriage_crisis': crisis, + 'interpretation': _d30_basic_interpretation(d30['planets']), + 'method': 'D30 Trimshamsa (Parashara)', + 'limitation': 'D30 是高级分盘,精确解读需配合 D30 宫位和其他分盘交叉验证', + } + + +def _d30_basic_interpretation(d30_planets: Dict) -> str: + """D30 基础解读""" + lines = ["【D30 Trimshamsa 三十分盘分析】", ""] + lines.append("D30 用于分析灾难、苦难、重大危机和深层业力模式。") + lines.append("") + + # 重点行星 + key_planets = ['Sun', 'Mars', 'Saturn', 'Rahu', 'Ketu'] + for p in key_planets: + p_data = d30_planets.get(p) + if p_data: + lines.append(f"{p} 在 D30:{p_data['d30_sign_cn']}") + + lines.append("") + lines.append("⚠️ D30 解读需要高级技巧,建议:") + lines.append(" 1. 检查 D30 中凶星(火星/土星/罗睺/计都)是否集中在特定宫位") + lines.append(" 2. 与 D1/D9 交叉验证危机事件的时间线") + lines.append(" 3. 使用 Vimshottari Dasha 定位具体危机发生时期") + + return "\n".join(lines) + + +# 便捷函数 +def get_d30_sign(lon: float) -> int: + """便捷函数:获取 D30 星座""" + return calc_d30_sign(lon) + + +if __name__ == '__main__': + # 测试 + test_lons = {'Sun': 28.5, 'Moon': 65.2, 'Mars': 120.8, + 'Mercury': 29.9, 'Jupiter': 185.3, 'Venus': 210.7, + 'Saturn': 300.1, 'Rahu': 88.4, 'Ketu': 268.4} + report = d30_full_report(test_lons) + print(report['interpretation'])