222 lines
7.9 KiB
Python
222 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Yoga规则扩展模块 v1.0
|
|
基于 dashaflow (MIT) yoga.py 补充检测规则,用于提升F1
|
|
|
|
新增检测:
|
|
- Kemadruma Yoga (孤月)
|
|
- Adhi Yoga (吉星护卫)
|
|
- Amala Yoga (10宫吉星)
|
|
- Saraswati Yoga (智慧三杰)
|
|
- Lakshmi Yoga (财富女神)
|
|
- Graha Yuddha (行星战争)
|
|
- Gandanta (业力节点)
|
|
"""
|
|
|
|
from typing import Dict, List
|
|
from aspects import TIGHT_ORB_DEGREE
|
|
|
|
SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo',
|
|
'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
|
|
KENDRA = {1,4,7,10}
|
|
TRIKONA = {1,5,9}
|
|
DUSTHANA = {6,8,12}
|
|
BENEFICS = {"Jupiter","Venus","Mercury"}
|
|
MALEFICS = {"Saturn","Mars","Sun","Rahu","Ketu"}
|
|
|
|
GANDANTA_JUNCTIONS = [(3,4),(7,8),(11,0)] # Cancer→Leo, Scorpio→Sag, Pisces→Aries
|
|
GANDANTA_ORB = 3.3333
|
|
|
|
|
|
def detect_kemadruma(planets: Dict) -> Dict:
|
|
"""Kemadruma Yoga: Moon孤立,无行星在2宫或12宫"""
|
|
moon = planets.get('Moon', {})
|
|
moon_sign = moon.get('sign', '')
|
|
if moon_sign not in SIGNS:
|
|
return {'present': False}
|
|
|
|
moon_idx = SIGNS.index(moon_sign)
|
|
sign_2nd = (moon_idx + 1) % 12
|
|
sign_12th = (moon_idx - 1) % 12
|
|
|
|
has_support = False
|
|
for pn, pd in planets.items():
|
|
if pn in ('Sun','Moon','Rahu','Ketu'):
|
|
continue
|
|
p_sign = pd.get('sign', '')
|
|
p_idx = SIGNS.index(p_sign) if p_sign in SIGNS else -1
|
|
if p_idx in (sign_2nd, sign_12th):
|
|
has_support = True
|
|
break
|
|
|
|
return {
|
|
'present': not has_support,
|
|
'name': 'Kemadruma Yoga',
|
|
'description': 'Moon孤立无援—人生孤独感强、自我依赖' if not has_support else 'Kemadruma已解除',
|
|
'planets': ['Moon'],
|
|
}
|
|
|
|
|
|
def detect_adhi_yoga(planets: Dict) -> List[Dict]:
|
|
"""Adhi Yoga: 吉星在6/7/8宫从月亮"""
|
|
moon = planets.get('Moon', {})
|
|
moon_sign = moon.get('sign', '')
|
|
if moon_sign not in SIGNS:
|
|
return []
|
|
|
|
moon_idx = SIGNS.index(moon_sign)
|
|
adhi_planets = []
|
|
target = {6,7,8}
|
|
for pn in BENEFICS:
|
|
pd = planets.get(pn)
|
|
if not pd:
|
|
continue
|
|
p_sign = pd.get('sign', '')
|
|
p_idx = SIGNS.index(p_sign) if p_sign in SIGNS else -1
|
|
house_from_moon = ((p_idx - moon_idx) % 12) + 1
|
|
if house_from_moon in target:
|
|
adhi_planets.append(pn)
|
|
|
|
if len(adhi_planets) >= 2:
|
|
return [{'name': 'Adhi Yoga', 'planets': adhi_planets,
|
|
'description': f'吉星{",".join(adhi_planets)}在6/7/8宫—宿命式成功'}]
|
|
return []
|
|
|
|
|
|
def detect_amala_yoga(planets: Dict, asc_sign: str) -> List[Dict]:
|
|
"""Amala Yoga: 天然吉星在10宫"""
|
|
asc_idx = SIGNS.index(asc_sign) if asc_sign in SIGNS else 0
|
|
yogas = []
|
|
for pn in BENEFICS:
|
|
pd = planets.get(pn)
|
|
if not pd:
|
|
continue
|
|
p_sign = pd.get('sign', '')
|
|
p_idx = SIGNS.index(p_sign) if p_sign in SIGNS else -1
|
|
house = ((p_idx - asc_idx) % 12) + 1
|
|
if house == 10:
|
|
yogas.append({'name': 'Amala Yoga', 'planet': pn,
|
|
'description': f'{pn}在10宫—善行得声望、晚年福报'})
|
|
return yogas
|
|
|
|
|
|
def detect_saraswati_yoga(planets: Dict, asc_sign: str) -> Dict:
|
|
"""Saraswati Yoga: Jupiter+Venus+Mercury在kendra/trikona/2宫 + Jupiter强"""
|
|
asc_idx = SIGNS.index(asc_sign) if asc_sign in SIGNS else 0
|
|
good_houses = KENDRA | TRIKONA | {2}
|
|
|
|
ok = []
|
|
for pn in ("Jupiter","Venus","Mercury"):
|
|
pd = planets.get(pn)
|
|
if not pd:
|
|
continue
|
|
p_sign = pd.get('sign', '')
|
|
p_idx = SIGNS.index(p_sign) if p_sign in SIGNS else -1
|
|
house = ((p_idx - asc_idx) % 12) + 1
|
|
if house in good_houses:
|
|
ok.append(pn)
|
|
|
|
if len(ok) == 3:
|
|
jup = planets.get('Jupiter', {})
|
|
jup_strong = jup.get('dignity', '') in ('own','exalted') or jup.get('house') in KENDRA
|
|
if jup_strong:
|
|
return {'present': True, 'name': 'Saraswati Yoga', 'planets': ok,
|
|
'description': '智慧三杰聚吉宫—博学多才、表达能力卓越'}
|
|
return {'present': False}
|
|
|
|
|
|
def detect_lakshmi_yoga(planets: Dict, asc_sign: str) -> Dict:
|
|
"""Lakshmi Yoga: 9宫主在own/exalted + Venus在own/exalted kendra"""
|
|
asc_idx = SIGNS.index(asc_sign) if asc_sign in SIGNS else 0
|
|
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'}
|
|
|
|
# 9宫主
|
|
h9_sign = SIGNS[(asc_idx + 8) % 12]
|
|
h9_lord = sign_lords[h9_sign]
|
|
h9_data = planets.get(h9_lord, {})
|
|
h9_strong = h9_data.get('dignity', '') in ('own','exalted')
|
|
|
|
# Venus
|
|
venus = planets.get('Venus', {})
|
|
venus_house = venus.get('house', 0)
|
|
venus_strong = venus_house in KENDRA and venus.get('dignity', '') in ('own','exalted')
|
|
|
|
if h9_strong and venus_strong:
|
|
return {'present': True, 'name': 'Lakshmi Yoga', 'planets': [h9_lord, 'Venus'],
|
|
'description': '9宫主吉+Venus强—巨大财富与繁荣'}
|
|
return {'present': False}
|
|
|
|
|
|
def detect_graha_yuddha(planets: Dict) -> List[Dict]:
|
|
"""Graha Yuddha: 两颗行星相距<1°"""
|
|
war_planets = ['Mars','Mercury','Jupiter','Venus','Saturn']
|
|
wars = []
|
|
for i in range(len(war_planets)):
|
|
for j in range(i+1, len(war_planets)):
|
|
p1, p2 = war_planets[i], war_planets[j]
|
|
d1, d2 = planets.get(p1,{}), planets.get(p2,{})
|
|
if not d1 or not d2:
|
|
continue
|
|
lon1 = d1.get('degree', 0) % 360
|
|
lon2 = d2.get('degree', 0) % 360
|
|
diff = abs(lon1 - lon2) % 360
|
|
if diff > 180:
|
|
diff = 360 - diff
|
|
if diff <= TIGHT_ORB_DEGREE:
|
|
winner = p1 if lon1 > lon2 else p2
|
|
loser = p2 if winner == p1 else p1
|
|
wars.append({
|
|
'name': 'Graha Yuddha', 'planet1': p1, 'planet2': p2,
|
|
'separation': round(diff, 3), 'winner': winner, 'loser': loser,
|
|
'description': f'{p1}-{p2}行星战争({diff:.2f}°)—{loser}被削弱',
|
|
})
|
|
return wars
|
|
|
|
|
|
def detect_gandanta(planets: Dict) -> List[Dict]:
|
|
"""Gandanta: 行星在水火交界3°20'范围内"""
|
|
points = []
|
|
for pn, pd in planets.items():
|
|
lon = pd.get('degree', 0) % 360
|
|
sign_idx = int(lon / 30) % 12
|
|
deg = lon % 30
|
|
for water_idx, fire_idx in GANDANTA_JUNCTIONS:
|
|
if sign_idx == water_idx and deg >= (30 - GANDANTA_ORB):
|
|
points.append({'name': 'Gandanta', 'planet': pn, 'sign': SIGNS[sign_idx],
|
|
'degree': round(deg, 1), 'junction': f'{SIGNS[water_idx]}-{SIGNS[fire_idx]}',
|
|
'description': f'{pn}在水火交界—业力节点、灵性转化'})
|
|
if sign_idx == fire_idx and deg <= GANDANTA_ORB:
|
|
points.append({'name': 'Gandanta', 'planet': pn, 'sign': SIGNS[sign_idx],
|
|
'degree': round(deg, 1), 'junction': f'{SIGNS[water_idx]}-{SIGNS[fire_idx]}',
|
|
'description': f'{pn}在水火交界—业力节点、灵性转化'})
|
|
return points
|
|
|
|
|
|
def detect_all_yogas(planets: Dict, asc_sign: str = 'Aries') -> List[Dict]:
|
|
"""检测所有扩展Yoga"""
|
|
results = []
|
|
|
|
r = detect_kemadruma(planets)
|
|
if r.get('present'):
|
|
results.append(r)
|
|
|
|
results.extend(detect_adhi_yoga(planets))
|
|
results.extend(detect_amala_yoga(planets, asc_sign))
|
|
|
|
r = detect_saraswati_yoga(planets, asc_sign)
|
|
if r.get('present'):
|
|
results.append(r)
|
|
|
|
r = detect_lakshmi_yoga(planets, asc_sign)
|
|
if r.get('present'):
|
|
results.append(r)
|
|
|
|
results.extend(detect_graha_yuddha(planets))
|
|
results.extend(detect_gandanta(planets))
|
|
|
|
return results
|