Enhance Jyotish validation and Jaimini modules
- add external validation reports and open-source comparison references - integrate Jaimini arudha/graha pada, enhanced argala, and additional synastry kutas - update skill docs and capability matrices - add smoke tests for open-source integrations
This commit is contained in:
+176
-126
@@ -1,17 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Argala(门闩)行星干预模块 v1.0
|
||||
Parashara体系的行星影响力锁定机制
|
||||
Argala(门闩)行星干预模块 v1.1
|
||||
|
||||
Argala = "门闩/木栓",指一颗行星通过特定宫位对另一颗行星产生
|
||||
不可阻挡的干预影响。这是判断行星力量和结果表达的关键技法。
|
||||
从旧版“逐行星Argala”升级为“逐参考点/逐宫完整Argala”:
|
||||
- 主Argala: 2/4/11宫
|
||||
- Virodhargala: 12/10/3宫分别阻挡2/4/11宫
|
||||
- 特殊Argala: 第3宫有2颗以上凶星
|
||||
- 次级Argala: 5/9宫
|
||||
- Argala Rajayoga分类: Poornargala / Tripadargala / Ardhargala / Padargala
|
||||
|
||||
规则:
|
||||
- 主Argala: 2/4/11宫位产生正面干预
|
||||
- 副Argala: 5/8宫位(从第2宫起算)产生正面干预
|
||||
- Virodha Argala: 12/10/3宫位产生反向阻止
|
||||
- 更强Argala: 多颗行星在同一Argala位置则力量增强
|
||||
MIT复用来源:
|
||||
- jaimini-tropical/jaimini/core/argala.py (tunanfang-pixel, MIT)
|
||||
适配:使用本项目 chart 输出的英文行星名与恒星黄道星座索引。
|
||||
"""
|
||||
from typing import Dict, List
|
||||
|
||||
@@ -21,129 +22,178 @@ SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon'
|
||||
'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars',
|
||||
'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'}
|
||||
|
||||
BENEFICS = ['Jupiter', 'Venus', 'Moon']
|
||||
MALEFICS = ['Saturn', 'Mars', 'Sun', 'Rahu', 'Ketu']
|
||||
NATURAL_MALEFICS = {'Sun', 'Mars', 'Saturn'}
|
||||
NATURAL_BENEFICS = {'Moon', 'Mercury', 'Jupiter', 'Venus'}
|
||||
NODES = {'Rahu', 'Ketu'}
|
||||
|
||||
PRIMARY_ARGALA = {2, 4, 11}
|
||||
VIRODHARGALA_MAP = {2: 12, 4: 10, 11: 3}
|
||||
SECONDARY_ARGALA = {5, 9}
|
||||
|
||||
|
||||
def calc_argala(planet_sign_indices: Dict[str, int], asc_sign_idx: int) -> Dict:
|
||||
def _house_from(ref_sign_idx: int, offset: int) -> int:
|
||||
"""从参考星座起算第offset宫对应的星座索引。"""
|
||||
return (ref_sign_idx + offset - 1) % 12
|
||||
|
||||
|
||||
def _planets_in_sign(sign_idx: int, planet_sign_indices: Dict[str, int], include_nodes: bool = False) -> List[str]:
|
||||
planets = []
|
||||
for pname, psi in planet_sign_indices.items():
|
||||
if not include_nodes and pname in NODES:
|
||||
continue
|
||||
if psi % 12 == sign_idx % 12:
|
||||
planets.append(pname)
|
||||
return planets
|
||||
|
||||
|
||||
def classify_argala_rajayoga(argala_result: Dict) -> Dict:
|
||||
"""按主Argala占据数量分类Rajayoga强度。"""
|
||||
primary = argala_result.get('primary', {})
|
||||
occupied = sum(1 for h in ['H2', 'H4', 'H11'] if primary.get(h, {}).get('planets'))
|
||||
blocked = sum(1 for h in ['H2', 'H4', 'H11'] if primary.get(h, {}).get('blockers'))
|
||||
if occupied == 3:
|
||||
return {'type': 'Poornargala', 'level': 4, 'cn': '完整Argala,最强支持'}
|
||||
if occupied == 2:
|
||||
return {'type': 'Tripadargala', 'level': 3, 'cn': '三足Argala,强支持'}
|
||||
if occupied == 1:
|
||||
return {'type': 'Ardhargala', 'level': 2, 'cn': '半Argala,中等支持'}
|
||||
if blocked:
|
||||
return {'type': 'Padargala', 'level': 1, 'cn': '弱Argala且受阻'}
|
||||
return {'type': 'None', 'level': 0, 'cn': '无明显Argala'}
|
||||
|
||||
|
||||
def calc_argala_for_reference(ref_sign_idx: int, planet_sign_indices: Dict[str, int], include_nodes: bool = False) -> Dict:
|
||||
"""计算单一参考点的完整Argala。"""
|
||||
result = {
|
||||
'ref_sign': SIGNS[ref_sign_idx],
|
||||
'ref_sign_idx': ref_sign_idx,
|
||||
'primary': {},
|
||||
'specific': None,
|
||||
'secondary': {},
|
||||
'argala_count': 0,
|
||||
'virodhargala_count': 0,
|
||||
'net_result': 'neutral',
|
||||
}
|
||||
|
||||
for h in sorted(PRIMARY_ARGALA):
|
||||
argala_sign = _house_from(ref_sign_idx, h)
|
||||
planets = _planets_in_sign(argala_sign, planet_sign_indices, include_nodes)
|
||||
block_h = VIRODHARGALA_MAP[h]
|
||||
block_sign = _house_from(ref_sign_idx, block_h)
|
||||
blockers = _planets_in_sign(block_sign, planet_sign_indices, include_nodes)
|
||||
effective = len(planets) > len(blockers)
|
||||
result['primary'][f'H{h}'] = {
|
||||
'house_from_reference': h,
|
||||
'sign': SIGNS[argala_sign],
|
||||
'sign_idx': argala_sign,
|
||||
'planets': planets,
|
||||
'blocked_by_house': block_h,
|
||||
'blocked_by_sign': SIGNS[block_sign],
|
||||
'blockers': blockers,
|
||||
'effective': effective,
|
||||
'effect': _argala_effect(h, planets, blockers),
|
||||
}
|
||||
if planets:
|
||||
result['argala_count'] += 1
|
||||
if blockers:
|
||||
result['virodhargala_count'] += 1
|
||||
|
||||
h3_sign = _house_from(ref_sign_idx, 3)
|
||||
h3_planets = _planets_in_sign(h3_sign, planet_sign_indices, include_nodes)
|
||||
h3_malefics = [p for p in h3_planets if p in NATURAL_MALEFICS]
|
||||
result['specific'] = {
|
||||
'house': 3,
|
||||
'sign': SIGNS[h3_sign],
|
||||
'sign_idx': h3_sign,
|
||||
'planets': h3_planets,
|
||||
'malefics': h3_malefics,
|
||||
'effective': len(h3_malefics) >= 2,
|
||||
'rule': '第3宫有2颗以上天然凶星形成特殊Argala',
|
||||
}
|
||||
if result['specific']['effective']:
|
||||
result['argala_count'] += 1
|
||||
|
||||
for h in sorted(SECONDARY_ARGALA):
|
||||
sign_idx = _house_from(ref_sign_idx, h)
|
||||
planets = _planets_in_sign(sign_idx, planet_sign_indices, include_nodes)
|
||||
result['secondary'][f'H{h}'] = {
|
||||
'house_from_reference': h,
|
||||
'sign': SIGNS[sign_idx],
|
||||
'sign_idx': sign_idx,
|
||||
'planets': planets,
|
||||
}
|
||||
|
||||
if result['argala_count'] > result['virodhargala_count']:
|
||||
result['net_result'] = 'supported'
|
||||
elif result['argala_count'] < result['virodhargala_count']:
|
||||
result['net_result'] = 'obstructed'
|
||||
result['rajayoga_classification'] = classify_argala_rajayoga(result)
|
||||
return result
|
||||
|
||||
|
||||
def calc_argala(planet_sign_indices: Dict[str, int], asc_sign_idx: int, include_nodes: bool = False) -> Dict:
|
||||
"""
|
||||
计算所有行星的Argala和Virodha Argala
|
||||
|
||||
参数:
|
||||
planet_sign_indices: {'Sun': 0, 'Moon': 3, ...} 行星所在星座索引
|
||||
计算全盘Argala。
|
||||
|
||||
Args:
|
||||
planet_sign_indices: {'Sun': 0, 'Moon': 3, ...}
|
||||
asc_sign_idx: 上升星座索引
|
||||
|
||||
返回: {
|
||||
planet_name: {
|
||||
'house': 宫位,
|
||||
'argala_from': [对哪些宫位有Argala],
|
||||
'argala_to': [被哪些行星Argala],
|
||||
'virodha_from': [被哪些行星阻止],
|
||||
'net_argala': 净Argala力量评估,
|
||||
}
|
||||
}
|
||||
include_nodes: 是否把Rahu/Ketu纳入占位阻挡统计(默认False,遵循Jaimini七行星口径)
|
||||
"""
|
||||
# 计算各行星宫位
|
||||
houses = {}
|
||||
for pname, si in planet_sign_indices.items():
|
||||
h = ((si - asc_sign_idx) % 12) + 1
|
||||
houses[pname] = h
|
||||
|
||||
# 主Argala位置(从目标行星宫位起算)
|
||||
# 2宫=财富Argala, 4宫=幸福Argala, 11宫=收益Argala
|
||||
MAIN_ARGALA = [2, 4, 11]
|
||||
# 副Argala位置(特殊条件:需要无其他行星在相应Virodha位置)
|
||||
SUB_ARGALA = [5, 8] # 第5宫=权力Argala(当2宫无Virodha), 第8宫(当4宫无Virodha)
|
||||
# Virodha Argala位置(反向阻止)
|
||||
VIRODHA = {2: 12, 4: 10, 11: 3, 5: 9, 8: 2}
|
||||
|
||||
results = {}
|
||||
|
||||
for target_p, target_h in houses.items():
|
||||
argala_on_target = [] # 作用于此行星的Argala
|
||||
virodha_on_target = [] # 作用于此行星的Virodha
|
||||
argala_by_target = [] # 此行星作用于其他位置的Argala
|
||||
|
||||
# 检查哪些行星对此行星有Argala
|
||||
for source_p, source_h in houses.items():
|
||||
if source_p == target_p:
|
||||
continue
|
||||
rel = ((source_h - target_h) % 12) + 1
|
||||
|
||||
# 主Argala检查
|
||||
if rel in MAIN_ARGALA:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
strength = 'strong' if _is_strong_argala(source_p, rel) else 'normal'
|
||||
argala_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'type': 'main', 'nature': nature, 'strength': strength,
|
||||
'effect': _argala_effect(rel, nature),
|
||||
})
|
||||
|
||||
# 副Argala检查
|
||||
elif rel in SUB_ARGALA:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
argala_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'type': 'sub', 'nature': nature, 'strength': 'conditional',
|
||||
'effect': _argala_effect(rel, nature),
|
||||
})
|
||||
|
||||
# Virodha检查
|
||||
for a_house, v_house in VIRODHA.items():
|
||||
if rel == v_house:
|
||||
nature = 'benefic' if source_p in BENEFICS else 'malefic'
|
||||
virodha_on_target.append({
|
||||
'source': source_p, 'house_from': rel,
|
||||
'blocks_argala_from': a_house,
|
||||
'nature': nature,
|
||||
})
|
||||
|
||||
# 此行星对其他位置产生的Argala
|
||||
for rel_house in MAIN_ARGALA:
|
||||
target_house = ((target_h - 1 + rel_house - 1) % 12) + 1
|
||||
planets_there = [p for p, h in houses.items() if h == target_house]
|
||||
if planets_there:
|
||||
argala_by_target.append({
|
||||
'argala_type': f'{rel_house}宫Argala',
|
||||
'target_house': target_house,
|
||||
'affects': planets_there,
|
||||
'effect': _argala_effect(rel_house, 'benefic' if target_p in BENEFICS else 'malefic'),
|
||||
})
|
||||
|
||||
# 净Argala评估
|
||||
benefic_argala = sum(1 for a in argala_on_target if a['nature'] == 'benefic')
|
||||
malefic_argala = sum(1 for a in argala_on_target if a['nature'] == 'malefic')
|
||||
benefic_virodha = sum(1 for v in virodha_on_target if v['nature'] == 'benefic')
|
||||
malefic_virodha = sum(1 for v in virodha_on_target if v['nature'] == 'malefic')
|
||||
|
||||
net = (benefic_argala - malefic_virodha) - (malefic_argala - benefic_virodha)
|
||||
|
||||
results[target_p] = {
|
||||
'house': target_h,
|
||||
'argala_on_this': argala_on_target,
|
||||
'virodha_on_this': virodha_on_target,
|
||||
'argala_by_this': argala_by_target,
|
||||
'net_score': net,
|
||||
'net_assessment': 'strongly_supported' if net >= 2 else 'supported' if net >= 1
|
||||
else 'blocked' if net <= -2 else 'neutral',
|
||||
}
|
||||
|
||||
return results
|
||||
for house_num in range(1, 13):
|
||||
ref_sign_idx = (asc_sign_idx + house_num - 1) % 12
|
||||
houses[f'house_{house_num}'] = calc_argala_for_reference(ref_sign_idx, planet_sign_indices, include_nodes)
|
||||
|
||||
planet_refs = {}
|
||||
for pname, sign_idx in planet_sign_indices.items():
|
||||
if pname in NODES and not include_nodes:
|
||||
continue
|
||||
planet_refs[pname] = calc_argala_for_reference(sign_idx, planet_sign_indices, include_nodes)
|
||||
|
||||
def _is_strong_argala(planet, house):
|
||||
"""判断Argala是否特别强(有2+行星在同一位置)"""
|
||||
return False # 需要宫位行星数信息,简化返回
|
||||
|
||||
|
||||
def _argala_effect(house, nature):
|
||||
"""Argala效果描述"""
|
||||
effects = {
|
||||
2: {'benefic': '财富和资源流入', 'malefic': '财务压力和资源消耗'},
|
||||
4: {'benefic': '幸福感、住所和内心平静增强', 'malefic': '家庭不和、住所问题'},
|
||||
11: {'benefic': '收益、愿望实现和社会认可', 'malefic': '损失、社会障碍'},
|
||||
5: {'benefic': '智慧、权力和创造力增强', 'malefic': '智力困扰、决策失误'},
|
||||
8: {'benefic': '隐藏资源和转化力量', 'malefic': '隐藏障碍和突发危机'},
|
||||
summary = _summarize_argala(houses)
|
||||
return {
|
||||
'method': 'Jaimini Argala + Virodhargala (jaimini-tropical MIT adapted)',
|
||||
'version': '1.1',
|
||||
'include_nodes': include_nodes,
|
||||
'ascendant': SIGNS[asc_sign_idx],
|
||||
'houses': houses,
|
||||
'planets': planet_refs,
|
||||
'summary': summary,
|
||||
}
|
||||
return effects.get(house, {}).get(nature, '一般性影响')
|
||||
|
||||
|
||||
def _summarize_argala(houses: Dict) -> Dict:
|
||||
supported = []
|
||||
obstructed = []
|
||||
strongest = []
|
||||
for house_key, data in houses.items():
|
||||
if data['net_result'] == 'supported':
|
||||
supported.append(house_key)
|
||||
elif data['net_result'] == 'obstructed':
|
||||
obstructed.append(house_key)
|
||||
level = data.get('rajayoga_classification', {}).get('level', 0)
|
||||
strongest.append((house_key, level, data.get('rajayoga_classification', {}).get('type')))
|
||||
strongest.sort(key=lambda x: x[1], reverse=True)
|
||||
return {
|
||||
'supported_houses': supported,
|
||||
'obstructed_houses': obstructed,
|
||||
'top_argala_houses': [{'house': h, 'level': lvl, 'type': typ} for h, lvl, typ in strongest[:5] if lvl > 0],
|
||||
'supported_count': len(supported),
|
||||
'obstructed_count': len(obstructed),
|
||||
}
|
||||
|
||||
|
||||
def _argala_effect(house: int, planets: List[str], blockers: List[str]) -> str:
|
||||
if not planets:
|
||||
return '无行星形成此类Argala'
|
||||
base = {
|
||||
2: '资源、语言、家族与财务支持',
|
||||
4: '内在稳定、住所、母亲、教育与幸福感支持',
|
||||
11: '收益、人脉、愿望实现与社会网络支持',
|
||||
}.get(house, '一般支持')
|
||||
if blockers and len(blockers) >= len(planets):
|
||||
return f'{base},但被{len(blockers)}个Virodhargala阻挡'
|
||||
if blockers:
|
||||
return f'{base},有轻度阻挡但仍可能有效'
|
||||
return f'{base},未见对应阻挡'
|
||||
|
||||
+148
-105
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Jaimini占星体系模块 v1.1
|
||||
Jaimini占星体系模块 v1.2
|
||||
Parashara传承中的Jaimini子系统
|
||||
|
||||
支持:
|
||||
- Chara Karaka: 7/8个功能指示星(按度数排序)
|
||||
- Arudha Pada: A1-A12 + Upapada(UL),复用 dashaflow/jaimini-tropical 的 MIT 算法
|
||||
- Karakamsha: AK在Navamsa中的上升(灵魂方向)
|
||||
- Chara Dasha: 当前为简化 timing 实现,v6.0.9 后标注为 partial,不得单独作为高置信度应期依据
|
||||
- Jaimini Sutras关键规则
|
||||
- Special Lagnas: HL/GL/VL 简化计算(出生时间敏感,作为辅助)
|
||||
|
||||
MIT复用来源:
|
||||
- dashaflow (adarshj322): Arudha/Upapada公式与例外规则
|
||||
- jaimini-tropical (tunanfang-pixel): Pada命名、Graha Pada与Jaimini特殊点结构
|
||||
"""
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
import math
|
||||
@@ -54,6 +59,26 @@ KARAKA_DOMAINS = {
|
||||
'Pitrukaraka': '父亲、祖先业力、传统传承',
|
||||
}
|
||||
|
||||
ARUDHA_NAMES = {
|
||||
1: 'Arudha Lagna (AL)', 2: 'Dhana Pada (A2)', 3: 'Vikrama Pada (A3)',
|
||||
4: 'Sukha Pada (A4)', 5: 'Mantra Pada (A5)', 6: 'Roga Pada (A6)',
|
||||
7: 'Dara Pada (A7)', 8: 'Mrityu Pada (A8)', 9: 'Dharma Pada (A9)',
|
||||
10: 'Karma Pada (A10)', 11: 'Labha Pada (A11)', 12: 'Upapada (UL)',
|
||||
}
|
||||
|
||||
|
||||
def _sign_idx(sign_name: str) -> int:
|
||||
return SIGNS.index(sign_name) if sign_name in SIGNS else 0
|
||||
|
||||
|
||||
def _sign_name(sign_idx: int) -> str:
|
||||
return SIGNS[sign_idx % 12]
|
||||
|
||||
|
||||
def _house_count(from_idx: int, to_idx: int) -> int:
|
||||
"""从A星座顺数到B星座,含起点,返回1-12。"""
|
||||
return ((to_idx - from_idx) % 12) + 1
|
||||
|
||||
|
||||
def calc_chara_karaka_7(planet_degrees: Dict[str, float]) -> Dict:
|
||||
"""
|
||||
@@ -64,13 +89,9 @@ def calc_chara_karaka_7(planet_degrees: Dict[str, float]) -> Dict:
|
||||
|
||||
返回: {karaka_name: {'planet': str, 'degree': float, 'domain': str}}
|
||||
"""
|
||||
# 排除Rahu和Ketu
|
||||
exclude = {'Rahu', 'Ketu'}
|
||||
planets = {k: v for k, v in planet_degrees.items() if k not in exclude}
|
||||
|
||||
# 按度数降序排列(度数最高的=AK)
|
||||
sorted_planets = sorted(planets.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
results = {}
|
||||
for rank, (pname, deg) in enumerate(sorted_planets, 1):
|
||||
if rank > 7:
|
||||
@@ -83,11 +104,8 @@ def calc_chara_karaka_7(planet_degrees: Dict[str, float]) -> Dict:
|
||||
'domain': KARAKA_DOMAINS.get(karaka, ''),
|
||||
'cn_name': KARAKA_CN.get(karaka, karaka),
|
||||
}
|
||||
|
||||
# 额外分析
|
||||
ak = results.get('Atmakaraka', {})
|
||||
dk = results.get('Darakaraka', {})
|
||||
|
||||
return {
|
||||
'karaka_table': results,
|
||||
'summary': {
|
||||
@@ -100,21 +118,13 @@ def calc_chara_karaka_7(planet_degrees: Dict[str, float]) -> Dict:
|
||||
|
||||
|
||||
def calc_chara_karaka_8(planet_degrees: Dict[str, float]) -> Dict:
|
||||
"""
|
||||
计算8星制Chara Karaka(含Rahu,使用30-度数来处理Rahu逆行)
|
||||
"""
|
||||
"""计算8星制Chara Karaka(含Rahu,Ketu排除)。"""
|
||||
planets = {}
|
||||
for pname, deg in planet_degrees.items():
|
||||
if pname == 'Ketu':
|
||||
continue
|
||||
if pname == 'Rahu':
|
||||
# Rahu直接使用星座内度数(与其它行星相同),不做取反
|
||||
planets[pname] = deg
|
||||
else:
|
||||
planets[pname] = deg
|
||||
|
||||
planets[pname] = deg
|
||||
sorted_planets = sorted(planets.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
results = {}
|
||||
for rank, (pname, deg) in enumerate(sorted_planets, 1):
|
||||
if rank > 8:
|
||||
@@ -127,11 +137,99 @@ def calc_chara_karaka_8(planet_degrees: Dict[str, float]) -> Dict:
|
||||
'domain': KARAKA_DOMAINS.get(karaka, ''),
|
||||
'cn_name': KARAKA_CN.get(karaka, karaka),
|
||||
}
|
||||
|
||||
return {'karaka_table_8': results}
|
||||
|
||||
|
||||
def calc_chara_dasha(asc_sign_idx: int,
|
||||
def calc_arudha_pada_for_house(house_sign_idx: int, planet_longitudes: Dict[str, float]) -> Optional[Dict]:
|
||||
"""
|
||||
计算单宫Arudha Pada。
|
||||
|
||||
公式复用 dashaflow / jaimini-tropical MIT 实现:
|
||||
1. 从目标宫星座数到宫主所在星座;
|
||||
2. 从宫主所在星座再数同样距离;
|
||||
3. 若落回本宫或本宫第七,则改取本宫第十。
|
||||
"""
|
||||
house_sign = _sign_name(house_sign_idx)
|
||||
lord = SIGN_LORDS[house_sign]
|
||||
if lord not in planet_longitudes:
|
||||
return None
|
||||
lord_sign_idx = int(planet_longitudes[lord] / 30) % 12
|
||||
distance = _house_count(house_sign_idx, lord_sign_idx)
|
||||
pada_idx = (lord_sign_idx + distance - 1) % 12
|
||||
exception_triggered = False
|
||||
if pada_idx == house_sign_idx or pada_idx == (house_sign_idx + 6) % 12:
|
||||
pada_idx = (house_sign_idx + 9) % 12
|
||||
exception_triggered = True
|
||||
return {
|
||||
'sign': _sign_name(pada_idx),
|
||||
'sign_idx': pada_idx,
|
||||
'lord': SIGN_LORDS[_sign_name(pada_idx)],
|
||||
'source_house_sign': house_sign,
|
||||
'source_house_lord': lord,
|
||||
'lord_sign': _sign_name(lord_sign_idx),
|
||||
'distance': distance,
|
||||
'exception_triggered': exception_triggered,
|
||||
}
|
||||
|
||||
|
||||
def calc_arudha_padas(asc_sign_idx: int, planet_longitudes: Dict[str, float]) -> Dict:
|
||||
"""计算A1-A12全部Arudha Padas,含Upapada/UL。"""
|
||||
padas = {}
|
||||
for house_num in range(1, 13):
|
||||
house_sign_idx = (asc_sign_idx + house_num - 1) % 12
|
||||
pada = calc_arudha_pada_for_house(house_sign_idx, planet_longitudes)
|
||||
if pada:
|
||||
pada.update({
|
||||
'house_num': house_num,
|
||||
'name': ARUDHA_NAMES.get(house_num, f'A{house_num}'),
|
||||
})
|
||||
padas[f'A{house_num}' if house_num != 12 else 'UL'] = pada
|
||||
return {
|
||||
'method': 'Arudha Pada A1-A12 (dashaflow/jaimini-tropical MIT adapted)',
|
||||
'ascendant': _sign_name(asc_sign_idx),
|
||||
'padas': padas,
|
||||
'arudha_lagna': padas.get('A1'),
|
||||
'upapada': padas.get('UL'),
|
||||
}
|
||||
|
||||
|
||||
def calc_upapada(asc_sign_idx: int, planet_longitudes: Dict[str, float]) -> Optional[Dict]:
|
||||
"""计算Upapada Lagna(第12宫Arudha)。"""
|
||||
result = calc_arudha_padas(asc_sign_idx, planet_longitudes).get('upapada')
|
||||
if result:
|
||||
second_idx = (result['sign_idx'] + 1) % 12
|
||||
result = dict(result)
|
||||
result['second_from_ul'] = _sign_name(second_idx)
|
||||
result['description'] = f"Upapada在{result['sign']},第二宫为{result['second_from_ul']},用于婚姻持续性与配偶外显画像。"
|
||||
return result
|
||||
|
||||
|
||||
def calc_graha_padas(planet_longitudes: Dict[str, float]) -> Dict:
|
||||
"""计算行星Graha Pada:行星位置通过其宫主映射出的外显影像。"""
|
||||
results = {}
|
||||
for planet, lon in planet_longitudes.items():
|
||||
if planet in ('Rahu', 'Ketu'):
|
||||
continue
|
||||
planet_sign_idx = int(lon / 30) % 12
|
||||
planet_sign = _sign_name(planet_sign_idx)
|
||||
lord = SIGN_LORDS[planet_sign]
|
||||
if lord not in planet_longitudes:
|
||||
continue
|
||||
lord_sign_idx = int(planet_longitudes[lord] / 30) % 12
|
||||
distance = _house_count(planet_sign_idx, lord_sign_idx)
|
||||
pada_idx = (lord_sign_idx + distance - 1) % 12
|
||||
results[planet] = {
|
||||
'planet_sign': planet_sign,
|
||||
'lord': lord,
|
||||
'lord_sign': _sign_name(lord_sign_idx),
|
||||
'graha_pada_sign': _sign_name(pada_idx),
|
||||
'graha_pada_sign_idx': pada_idx,
|
||||
'distance': distance,
|
||||
}
|
||||
return {'method': 'Graha Pada (jaimini-tropical MIT adapted)', 'graha_padas': results}
|
||||
|
||||
|
||||
def calc_chara_dasha(asc_sign_idx: int,
|
||||
planet_longitudes: Dict[str, float],
|
||||
birth_year: int, birth_month: int,
|
||||
birth_day: int = 1) -> Dict:
|
||||
@@ -144,23 +242,16 @@ def calc_chara_dasha(asc_sign_idx: int,
|
||||
- 偶数星座(Taurus, Cancer...):反向顺序
|
||||
- 大运长度 = 12 - 落入该星座的行星数(Jaimini Sutras 1:1-3标准)
|
||||
"""
|
||||
# 确定顺序方向
|
||||
is_odd = asc_sign_idx % 2 == 0
|
||||
direction = 1 if is_odd else -1
|
||||
|
||||
# 生成大运序列
|
||||
dasha_sequence = []
|
||||
|
||||
for i in range(12):
|
||||
sign_idx = (asc_sign_idx + direction * i) % 12
|
||||
sign_name = SIGNS[sign_idx]
|
||||
lord = SIGN_LORDS[sign_name]
|
||||
|
||||
# 大运长度: 12 - 落入该星座的行星数(Jaimini标准)
|
||||
count_in_sign = sum(1 for lon in planet_longitudes.values()
|
||||
count_in_sign = sum(1 for lon in planet_longitudes.values()
|
||||
if int(lon / 30) % 12 == sign_idx and lon >= 0)
|
||||
duration = max(1, 12 - count_in_sign)
|
||||
|
||||
dasha_sequence.append({
|
||||
'sign': sign_name,
|
||||
'sign_idx': sign_idx,
|
||||
@@ -169,21 +260,11 @@ def calc_chara_dasha(asc_sign_idx: int,
|
||||
'planets_in_sign': count_in_sign,
|
||||
'order': i + 1,
|
||||
})
|
||||
|
||||
# v6.1.10: 计算出生时的平衡(balance at birth)
|
||||
# 第一个大运中已过期的部分 = (从出生月日到下一个大运的比例)
|
||||
# 简化:全年按365.25天
|
||||
total_months = sum(d['duration_years'] * 12 for d in dasha_sequence)
|
||||
first_duration_months = dasha_sequence[0]['duration_years'] * 12
|
||||
|
||||
# 出生月的剩余天数(简化:假设出生在月中)
|
||||
days_in_month = 30.44
|
||||
remaining_days = (days_in_month - birth_day + days_in_month / 2)
|
||||
remaining_fraction = remaining_days / (first_duration_months * days_in_month)
|
||||
dasha_sequence[0]['balance_at_birth'] = round(remaining_fraction, 4)
|
||||
|
||||
# 计算日期
|
||||
# 第一个大运从出生日开始,但只运行剩余的 balance 部分
|
||||
if birth_day <= 15:
|
||||
start_year, start_month = birth_year, birth_month
|
||||
else:
|
||||
@@ -191,15 +272,12 @@ def calc_chara_dasha(asc_sign_idx: int,
|
||||
if start_month > 12:
|
||||
start_month = 1
|
||||
start_year += 1
|
||||
|
||||
current_year, current_month = start_year, start_month
|
||||
|
||||
for i, d in enumerate(dasha_sequence):
|
||||
d['start_date'] = f"{current_year}-{current_month:02d}"
|
||||
actual_duration = d['duration_years']
|
||||
if i == 0:
|
||||
actual_duration *= remaining_fraction # 第一个大运只有剩余部分
|
||||
|
||||
actual_duration *= remaining_fraction
|
||||
end_month = current_month + int(actual_duration * 12)
|
||||
end_year = current_year + end_month // 12
|
||||
end_month = end_month % 12
|
||||
@@ -211,13 +289,13 @@ def calc_chara_dasha(asc_sign_idx: int,
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
|
||||
return {
|
||||
'method': 'Chara Dasha (Jaimini Sutras 1:1-3, v6.1.10 balance-at-birth fix)',
|
||||
'ascendant': SIGNS[asc_sign_idx],
|
||||
'direction': 'forward' if is_odd else 'backward',
|
||||
'dasha_sequence': dasha_sequence,
|
||||
'total_cycle_years': sum(d['duration_years'] for d in dasha_sequence),
|
||||
'capability_status': 'partial',
|
||||
}
|
||||
|
||||
|
||||
@@ -225,54 +303,36 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
|
||||
planet_longitudes: Dict[str, float],
|
||||
birth_year: int, birth_month: int,
|
||||
birth_day: int = 1) -> Dict:
|
||||
"""
|
||||
Chara Dasha 完整3层计算 v6.1.10(MD → AD → PD)
|
||||
|
||||
三层递归:
|
||||
- Mahadasha (MD): 12个星座周期
|
||||
- Antardasha (AD): 每个MD内12个子周期,时长按比例分配
|
||||
- Pratyantar Dasha (PD): 每个AD内12个子子周期(新增v6.1.10)
|
||||
|
||||
每层都从该层主星座开始,同方向,比例分配
|
||||
"""
|
||||
# 先算 Mahadasha
|
||||
"""Chara Dasha 完整3层计算 v6.1.10(MD → AD → PD)。"""
|
||||
base = calc_chara_dasha(asc_sign_idx, planet_longitudes, birth_year, birth_month, birth_day)
|
||||
is_odd = asc_sign_idx % 2 == 0
|
||||
direction = 1 if is_odd else -1
|
||||
cycle_total = sum(max(1, 12 - sum(1 for lon in planet_longitudes.values()
|
||||
cycle_total = sum(max(1, 12 - sum(1 for lon in planet_longitudes.values()
|
||||
if int(lon / 30) % 12 == (asc_sign_idx + direction * i) % 12 and lon >= 0))
|
||||
for i in range(12))
|
||||
|
||||
# 为每个 Mahadasha 计算 Antardasha(和 Pratyantar)
|
||||
for md in base['dasha_sequence']:
|
||||
md_sign_idx = md['sign_idx']
|
||||
md_duration = md['duration_years']
|
||||
antardasha_list = []
|
||||
|
||||
for j in range(12):
|
||||
ad_sign_idx = (md_sign_idx + direction * j) % 12
|
||||
ad_sign = SIGNS[ad_sign_idx]
|
||||
ad_lord = SIGN_LORDS[ad_sign]
|
||||
|
||||
count_in_sign = sum(1 for lon in planet_longitudes.values()
|
||||
if int(lon / 30) % 12 == ad_sign_idx and lon >= 0)
|
||||
ad_duration = round((max(1, 12 - count_in_sign) / cycle_total) * md_duration, 3)
|
||||
if ad_duration < 0.003:
|
||||
ad_duration = 0.003 # 最小约1天
|
||||
|
||||
# v6.1.10: 计算 Pratyantar Dasha(第3层)
|
||||
ad_duration = 0.003
|
||||
pratyantar_list = []
|
||||
for k in range(12):
|
||||
pd_sign_idx = (ad_sign_idx + direction * k) % 12
|
||||
pd_sign = SIGNS[pd_sign_idx]
|
||||
pd_lord = SIGN_LORDS[pd_sign]
|
||||
|
||||
pd_count = sum(1 for lon in planet_longitudes.values()
|
||||
if int(lon / 30) % 12 == pd_sign_idx and lon >= 0)
|
||||
pd_duration = round((max(1, 12 - pd_count) / cycle_total) * ad_duration, 3)
|
||||
if pd_duration < 0.001:
|
||||
pd_duration = 0.001
|
||||
|
||||
pratyantar_list.append({
|
||||
'sign': pd_sign,
|
||||
'sign_idx': pd_sign_idx,
|
||||
@@ -280,7 +340,6 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
|
||||
'duration_years': pd_duration,
|
||||
'order': k + 1,
|
||||
})
|
||||
|
||||
antardasha_list.append({
|
||||
'sign': ad_sign,
|
||||
'sign_idx': ad_sign_idx,
|
||||
@@ -289,8 +348,6 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
|
||||
'order': j + 1,
|
||||
'pratyantar_dashas': pratyantar_list,
|
||||
})
|
||||
|
||||
# 计算 Antardasha 日期
|
||||
start_year, start_month = map(int, md['start_date'].split('-'))
|
||||
for ad in antardasha_list:
|
||||
ad['start_date'] = f"{start_year}-{start_month:02d}"
|
||||
@@ -300,54 +357,20 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
|
||||
end_month = int((end_day % 365) / 30.44) + 1
|
||||
end_month = max(1, min(12, end_month))
|
||||
ad['end_date'] = f"{end_year}-{end_month:02d}"
|
||||
|
||||
# 更新下一个ad起始
|
||||
if end_month < 12:
|
||||
start_year, start_month = end_year, end_month + 1
|
||||
else:
|
||||
start_year, start_month = end_year + 1, 1
|
||||
|
||||
md['antardashas'] = antardasha_list
|
||||
|
||||
base['has_antardasha'] = True
|
||||
base['has_pratyantar'] = True
|
||||
return base
|
||||
|
||||
|
||||
def _chara_dasha_duration(sign_idx, planet_lons):
|
||||
"""计算Chara Dasha单个大运的年数"""
|
||||
# 标准方法:12 - 落入该星座的行星数量(最少1年,最多12年)
|
||||
count = 0
|
||||
for pname, lon in planet_lons.items():
|
||||
if pname in ('Rahu', 'Ketu'):
|
||||
continue
|
||||
p_sign = int(lon / 30) % 12
|
||||
if p_sign == sign_idx:
|
||||
count += 1
|
||||
return max(1, 12 - count)
|
||||
|
||||
|
||||
def calc_karakamsha(ak_sign_in_d9: str, ak_degree_in_d9: float) -> Dict:
|
||||
"""
|
||||
Karakamsha分析:AK(Atmakaraka,灵魂星)在D9中的位置作为"灵魂上升"
|
||||
这是Jaimini体系中判断人生终极方向的关键技法
|
||||
|
||||
经典定义:Karakamsha = Atmakaraka在Navamsa(D9)中落入的星座
|
||||
从这个星座看12宫的布局,分析灵魂方向
|
||||
|
||||
⚠️ 2026-05-03修正:此前版本错误使用DK(配偶星),现已修正为AK(灵魂星)
|
||||
|
||||
参数:
|
||||
ak_sign_in_d9: AK(灵魂星)在D9中的星座
|
||||
ak_degree_in_d9: AK在D9中的度数
|
||||
"""
|
||||
sign_idx = SIGNS.index(ak_sign_in_d9) if ak_sign_in_d9 in SIGNS else 0
|
||||
"""Karakamsha分析:AK在D9中的位置作为灵魂上升。"""
|
||||
lord = SIGN_LORDS.get(ak_sign_in_d9, '')
|
||||
|
||||
# Karakamsha Lagna = AK(灵魂星)在D9中的位置
|
||||
# 从这个位置看12宫的布局,分析灵魂方向
|
||||
interpretations = _karakamsha_interpretations(ak_sign_in_d9, lord)
|
||||
|
||||
return {
|
||||
'karakamsha_sign': ak_sign_in_d9,
|
||||
'karakamsha_degree': ak_degree_in_d9,
|
||||
@@ -357,7 +380,7 @@ def calc_karakamsha(ak_sign_in_d9: str, ak_degree_in_d9: float) -> Dict:
|
||||
|
||||
|
||||
def _karakamsha_interpretations(sign, lord):
|
||||
"""Karakamsha的灵魂方向解读"""
|
||||
"""Karakamsha的灵魂方向解读。"""
|
||||
directions = {
|
||||
'Aries': '灵魂追求独立、开拓、成为先驱',
|
||||
'Taurus': '灵魂追求稳定、物质安全感、感官和谐',
|
||||
@@ -387,5 +410,25 @@ def _karakamsha_interpretations(sign, lord):
|
||||
}
|
||||
|
||||
|
||||
def calc_special_lagnas(asc_sign_idx: int, hour: int, minute: int = 0) -> Dict:
|
||||
"""
|
||||
Jaimini特殊上升点简化版:HL/GL/VL。
|
||||
|
||||
|
||||
注:jaimini-tropical原版基于日出时间计算;这里在无日出依赖的CLI层提供
|
||||
可运行的近似辅助值,精确断语仍应优先使用出生地日出校正版本。
|
||||
"""
|
||||
local_hours = hour + minute / 60.0
|
||||
ghatis = (local_hours / 24.0) * 60.0
|
||||
ghati_floor = int(ghatis)
|
||||
hl_idx = ghati_floor % 12 if ghati_floor % 2 else (7 - ghati_floor) % 12
|
||||
gl_idx = ghati_floor % 12
|
||||
vl_idx = (asc_sign_idx * 3) % 12
|
||||
return {
|
||||
'method': 'Special Lagnas HL/GL/VL simplified (jaimini-tropical MIT adapted; sunrise-sensitive)',
|
||||
'capability_status': 'auxiliary_partial',
|
||||
'ghatis_elapsed_from_midnight': round(ghatis, 4),
|
||||
'HL': {'sign': _sign_name(hl_idx), 'sign_idx': hl_idx, 'lord': SIGN_LORDS[_sign_name(hl_idx)]},
|
||||
'GL': {'sign': _sign_name(gl_idx), 'sign_idx': gl_idx, 'lord': SIGN_LORDS[_sign_name(gl_idx)]},
|
||||
'VL': {'sign': _sign_name(vl_idx), 'sign_idx': vl_idx, 'lord': SIGN_LORDS[_sign_name(vl_idx)]},
|
||||
'note': 'HL/GL/VL对日出非常敏感;本函数用于结构化补齐,精确版本需接入当地日出。'
|
||||
}
|
||||
|
||||
@@ -2280,7 +2280,9 @@ def cmd_jaimini(args):
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from jaimini import calc_chara_karaka_7, calc_chara_karaka_8, calc_chara_dasha, calc_karakamsha, calc_chara_dasha_with_antardasha
|
||||
from jaimini import (calc_chara_karaka_7, calc_chara_karaka_8, calc_chara_dasha,
|
||||
calc_karakamsha, calc_chara_dasha_with_antardasha,
|
||||
calc_arudha_padas, calc_graha_padas, calc_special_lagnas)
|
||||
from varga import calc_varga
|
||||
except ImportError as e:
|
||||
return {"error": f"jaimini模块导入失败: {e}"}
|
||||
@@ -2313,6 +2315,11 @@ def cmd_jaimini(args):
|
||||
ak_lon = planet_lons.get(ak_name, 0)
|
||||
ak_d9 = calc_varga(ak_lon, 9)
|
||||
result['karakamsha'] = calc_karakamsha(ak_d9.get('sign', 'Aries'), ak_d9.get('degree_in_sign', 0))
|
||||
if mode in ('all', 'arudha'):
|
||||
result['arudha_padas'] = calc_arudha_padas(asc_idx, planet_lons)
|
||||
result['graha_padas'] = calc_graha_padas(planet_lons)
|
||||
if mode in ('all', 'special'):
|
||||
result['special_lagnas'] = calc_special_lagnas(asc_idx, args.hour, args.minute)
|
||||
return result
|
||||
|
||||
|
||||
@@ -3568,7 +3575,9 @@ def cmd_full_reading(args):
|
||||
|
||||
# ── Step 6: Jaimini系统 ──
|
||||
try:
|
||||
from jaimini import calc_chara_karaka_7, calc_chara_karaka_8, calc_chara_dasha, calc_karakamsha, calc_chara_dasha_with_antardasha
|
||||
from jaimini import (calc_chara_karaka_7, calc_chara_karaka_8, calc_chara_dasha,
|
||||
calc_karakamsha, calc_chara_dasha_with_antardasha,
|
||||
calc_arudha_padas, calc_graha_padas, calc_special_lagnas)
|
||||
from varga import calc_varga
|
||||
|
||||
jaimini_result = {}
|
||||
@@ -3600,6 +3609,9 @@ def cmd_full_reading(args):
|
||||
ak_d9 = calc_varga(ak_lon, 9)
|
||||
jaimini_result['karakamsha'] = calc_karakamsha(
|
||||
ak_d9.get('sign', 'Aries'), ak_d9.get('degree_in_sign', 0))
|
||||
jaimini_result['arudha_padas'] = calc_arudha_padas(asc_idx, planet_lons)
|
||||
jaimini_result['graha_padas'] = calc_graha_padas(planet_lons)
|
||||
jaimini_result['special_lagnas'] = calc_special_lagnas(asc_idx, args.hour, args.minute)
|
||||
|
||||
# Darakaraka 深度解读(v6.1.10)
|
||||
# Registry 已将 modules.jaimini.darakaraka 标为 covered;这里把独立 DK
|
||||
@@ -4120,9 +4132,9 @@ def main():
|
||||
_add_chart_args(p)
|
||||
|
||||
# 17. jaimini (v3.7新增)
|
||||
p = sub.add_parser('jaimini', help='Jaimini系统(Chara Karaka/Dasha/Karakamsha)')
|
||||
p = sub.add_parser('jaimini', help='Jaimini系统(Chara Karaka/Dasha/Karakamsha/Arudha/Special Lagnas)')
|
||||
_add_chart_args(p)
|
||||
p.add_argument('--mode', default='all', choices=['all','karaka','dasha','karakamsha'], help='分析模式')
|
||||
p.add_argument('--mode', default='all', choices=['all','karaka','dasha','karakamsha','arudha','special'], help='分析模式')
|
||||
p.add_argument('--antardasha', action='store_true', help='Chara Dasha含Antardasha子周期(当前timing实现为partial)')
|
||||
|
||||
# 18. nakshatra-adv (v3.7新增 → v6.0.22 升级)
|
||||
|
||||
+98
-3
@@ -135,6 +135,98 @@ def _calc_nadi(n1, n2):
|
||||
return {'score':8,'max':8,'n1':nadi_name[na1],'n2':nadi_name[na2],
|
||||
'note':'不同Nadi=吉,互补生命力'}
|
||||
|
||||
# ============================================================================
|
||||
# dashaflow MIT增强:8分制之外的附加Kuta
|
||||
# ============================================================================
|
||||
def _calc_mahendra(n1, n2):
|
||||
"""Mahendra Kuta:男方星宿从女方星宿数起为4/7/10/13/16/19/22/25则吉。"""
|
||||
count = ((n1 - n2) % 27) + 1
|
||||
return {'result': 'good' if count in {4, 7, 10, 13, 16, 19, 22, 25} else 'bad', 'count': count}
|
||||
|
||||
|
||||
def _calc_stree_deergha(n1, n2):
|
||||
"""Stree Deergha:男方星宿从女方星宿数起至少9宿为吉。"""
|
||||
count = ((n1 - n2) % 27) + 1
|
||||
return {'result': 'good' if count >= 9 else 'bad', 'count': count}
|
||||
|
||||
|
||||
VEDHA_PAIRS = {
|
||||
(0, 17), (1, 16), (2, 15), (3, 14), (5, 21), (6, 20), (7, 19),
|
||||
(8, 18), (9, 26), (10, 25), (11, 24), (12, 23), (4, 22)
|
||||
}
|
||||
|
||||
|
||||
def _calc_vedha(n1, n2):
|
||||
"""Vedha Kuta:特定星宿对形成阻隔。"""
|
||||
pair = tuple(sorted((n1, n2)))
|
||||
bad = pair in {tuple(sorted(p)) for p in VEDHA_PAIRS}
|
||||
return {'result': 'bad' if bad else 'good', 'pair': pair}
|
||||
|
||||
|
||||
RAJJU_GROUPS = {
|
||||
'Pada': {0, 8, 9, 17, 18, 26},
|
||||
'Kati': {1, 7, 10, 16, 25, 19},
|
||||
'Udara': {2, 6, 11, 15, 20, 24},
|
||||
'Kanta': {3, 5, 12, 14, 21, 23},
|
||||
'Sira': {4, 13, 22},
|
||||
}
|
||||
RAJJU_EFFECTS = {
|
||||
'Sira': '头部Rajju:传统认为影响丈夫寿命',
|
||||
'Kanta': '颈部Rajju:传统认为影响妻子寿命',
|
||||
'Udara': '腹部Rajju:传统认为影响子女',
|
||||
'Kati': '腰部Rajju:传统认为影响财务稳定',
|
||||
'Pada': '足部Rajju:传统认为迁动奔波较多',
|
||||
}
|
||||
|
||||
|
||||
def _rajju_group(n):
|
||||
for group, indices in RAJJU_GROUPS.items():
|
||||
if n in indices:
|
||||
return group
|
||||
return None
|
||||
|
||||
|
||||
def _calc_rajju(n1, n2):
|
||||
g1 = _rajju_group(n1)
|
||||
g2 = _rajju_group(n2)
|
||||
if g1 and g1 == g2:
|
||||
return {'result': 'bad', 'group': g1, 'effect': RAJJU_EFFECTS.get(g1, '')}
|
||||
return {'result': 'good', 'group1': g1, 'group2': g2, 'effect': ''}
|
||||
|
||||
|
||||
def _calc_bad_constellations(n1, n2):
|
||||
"""坏星宿简化检测:Moola/Ashlesha/Jyeshtha/Vishakha等传统敏感宿。"""
|
||||
bad = []
|
||||
names = {8: 'Ashlesha', 15: 'Vishakha', 17: 'Jyeshtha', 18: 'Moola'}
|
||||
for label, n in [('person1', n1), ('person2', n2)]:
|
||||
if n in names:
|
||||
bad.append({'person': label, 'nakshatra': names[n]})
|
||||
return {'result': 'bad' if bad else 'good', 'issues': bad}
|
||||
|
||||
|
||||
def _calc_additional_kutas(n1, n2, base_scores):
|
||||
"""复用dashaflow 16因子婚配思路,补充传统8分制以外的Kuta。"""
|
||||
mahendra = _calc_mahendra(n1, n2)
|
||||
stree = _calc_stree_deergha(n1, n2)
|
||||
vedha = _calc_vedha(n1, n2)
|
||||
rajju = _calc_rajju(n1, n2)
|
||||
bad_const = _calc_bad_constellations(n1, n2)
|
||||
exceptions = []
|
||||
if base_scores.get('Nadi(生命力)', {}).get('score') == 0 and base_scores.get('Bhakuta(情感经济)', {}).get('score', 0) > 0 and rajju['result'] == 'good':
|
||||
exceptions.append('Nadi Dosha因Bhakuta与Rajju良好而减弱')
|
||||
if rajju['result'] == 'bad' and base_scores.get('Graha Maitri(行星友谊)', {}).get('score', 0) >= 4 and base_scores.get('Tara(星宿距离)', {}).get('score', 0) >= 1.5:
|
||||
exceptions.append('Rajju Dosha因Graha Maitri与Tara较好而减弱')
|
||||
return {
|
||||
'method': 'dashaflow MIT adapted additional kutas',
|
||||
'Mahendra': mahendra,
|
||||
'StreeDeergha': stree,
|
||||
'Vedha': vedha,
|
||||
'Rajju': rajju,
|
||||
'BadConstellations': bad_const,
|
||||
'exceptions': exceptions,
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# 合盘主函数
|
||||
# ============================================================================
|
||||
@@ -180,6 +272,8 @@ def calc_synastry(person1: dict, person2: dict) -> dict:
|
||||
('Yoni(生理)', yoni), ('Graha Maitri(行星友谊)', graha),
|
||||
('Gana(气质)', gana), ('Bhakuta(情感经济)', bhakuta), ('Nadi(生命力)', nadi),
|
||||
]
|
||||
koota_map = {k: v for k, v in kootas}
|
||||
additional_kutas = _calc_additional_kutas(n1, n2, koota_map)
|
||||
|
||||
total = sum(k[1]['score'] for k in kootas)
|
||||
max_total = sum(k[1]['max'] for k in kootas)
|
||||
@@ -197,11 +291,12 @@ def calc_synastry(person1: dict, person2: dict) -> dict:
|
||||
papasamya = _calc_papasamya(person1, person2)
|
||||
|
||||
return {
|
||||
'method': 'Ashta Koota 36分制 + Mangal Dosha + Papasamya',
|
||||
'version': '3.7',
|
||||
'method': 'Ashta Koota 36分制 + Mangal Dosha + Papasamya + dashaflow附加Kuta',
|
||||
'version': '3.8-dashaflow-mit-adapted',
|
||||
'person1': {'moon_nakshatra': NAK27[n1][0], 'nak_idx': n1, 'moon_sign': SIGNS[s1]},
|
||||
'person2': {'moon_nakshatra': NAK27[n2][0], 'nak_idx': n2, 'moon_sign': SIGNS[s2]},
|
||||
'kootas': {k:v for k,v in kootas},
|
||||
'kootas': koota_map,
|
||||
'additional_kutas': additional_kutas,
|
||||
'total_score': total,
|
||||
'max_score': max_total,
|
||||
'percentage': pct,
|
||||
|
||||
Reference in New Issue
Block a user