Files
Jyotisha/scripts/dasha_analyzer.py
T
jesse-uxGrok (agent loop)Cursor
d11ee6f0dd fix(dasha): measure nakshatra index and progress on one grid
Upstream 3c2dad95, 8643bc9a, and the lon_to_nakshatra part of 9e04f0db. Exact star starts were split across int-division and modulo, so 16 of 27 openings reported a zero balance and skipped the mahadasha. Off-boundary longitudes keep the old modulo. BUG-1381.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 16:15:48 +08:00

236 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
印度占星 Dasha 推算脚本
基于用户提供的星盘数据(月亮Nakshatra + 出生日期)推算大运/小运时间线
用法:
python3 dasha_analyzer.py --nakshatra "Jyeshtha" --pada 3 --birthdate 1985-08-20
python3 dasha_analyzer.py --moon-lon 226.5 --birthdate 1985-08-20
"""
import argparse
from datetime import datetime, timedelta
# Nakshatra 对应大运主星与年限
NAKSHATRA_LIST = [
("Ashwini", "Ketu", 7),
("Bharani", "Venus", 20),
("Krittika", "Sun", 6),
("Rohini", "Moon", 10),
("Mrigashira", "Mars", 7),
("Ardra", "Rahu", 18),
("Punarvasu", "Jupiter", 16),
("Pushya", "Saturn", 19),
("Ashlesha", "Mercury", 17),
("Magha", "Ketu", 7),
("Purva Phalguni", "Venus", 20),
("Uttara Phalguni", "Sun", 6),
("Hasta", "Moon", 10),
("Chitra", "Mars", 7),
("Swati", "Rahu", 18),
("Vishakha", "Jupiter", 16),
("Anuradha", "Saturn", 19),
("Jyeshtha", "Mercury", 17),
("Mula", "Ketu", 7),
("Purva Ashadha", "Venus", 20),
("Uttara Ashadha", "Sun", 6),
("Shravana", "Moon", 10),
("Dhanishtha", "Mars", 7),
("Shatabhisha", "Rahu", 18),
("Purva Bhadrapada", "Jupiter", 16),
("Uttara Bhadrapada", "Saturn", 19),
("Revati", "Mercury", 17),
]
DASHA_ORDER = ["Ketu","Venus","Sun","Moon","Mars","Rahu","Jupiter","Saturn","Mercury"]
DASHA_YEARS = {"Ketu":7,"Venus":20,"Sun":6,"Moon":10,"Mars":7,"Rahu":18,"Jupiter":16,"Saturn":19,"Mercury":17}
PLANET_CN = {
"Ketu":"南交点 Ketu ☄️",
"Venus":"金星 Venus ♀",
"Sun":"太阳 Sun ☀️",
"Moon":"月亮 Moon 🌙",
"Mars":"火星 Mars ♂",
"Rahu":"北交点 Rahu 🐉",
"Jupiter":"木星 Jupiter ♃",
"Saturn":"土星 Saturn ♄",
"Mercury":"水星 Mercury ☿",
}
def fuzzy_match_nakshatra(name):
"""模糊匹配 Nakshatra 名称"""
name_lower = name.lower().replace(" ", "").replace("-", "")
for nak in NAKSHATRA_LIST:
if name_lower in nak[0].lower().replace(" ", ""):
return nak
if nak[0].lower().replace(" ", "").startswith(name_lower[:5]):
return nak
return None
def lon_to_nakshatra(moon_lon):
"""月亮黄经(0-360)→ Nakshatra + Pada。序号与进度来自同一把尺子。"""
try:
from nakshatra_advanced import nakshatra_index_and_progress
except ImportError:
from scripts.nakshatra_advanced import nakshatra_index_and_progress
idx, progress = nakshatra_index_and_progress(moon_lon)
if progress == 0.0:
pada = 1
else:
nak_span = 360 / 27
pada_span = nak_span / 4
pada = int((float(moon_lon) % nak_span) / pada_span) + 1
return NAKSHATRA_LIST[idx], progress, pada
def build_dasha_timeline(birth_date_str, nak_info, nak_progress):
"""构建完整大运时间线"""
birth_dt = datetime.strptime(birth_date_str, "%Y-%m-%d")
nak_name, start_lord, start_years = nak_info
# 当前大运已经走了多少年
elapsed = nak_progress * start_years
remaining = start_years - elapsed
# 当前大运的实际开始时间(往回推)
current_dasha_start = birth_dt - timedelta(days=elapsed * 365.25)
start_idx = DASHA_ORDER.index(start_lord)
timeline = []
dt = current_dasha_start
for i in range(9):
lord = DASHA_ORDER[(start_idx + i) % 9]
years = DASHA_YEARS[lord]
end_dt = dt + timedelta(days=years * 365.25)
timeline.append({
"lord": lord,
"start": dt,
"end": end_dt,
"years": years,
})
dt = end_dt
return timeline, round(elapsed, 2), round(remaining, 2), start_lord
def build_antardasha(mahadasha):
"""计算某个大运内的全部小运"""
lord = mahadasha["lord"]
total_days = (mahadasha["end"] - mahadasha["start"]).days
start_idx = DASHA_ORDER.index(lord)
sub_list = []
dt = mahadasha["start"]
for i in range(9):
sub_lord = DASHA_ORDER[(start_idx + i) % 9]
sub_years = DASHA_YEARS[sub_lord]
# 小运时长 = 大运总年数 × 小运行星年占比 / 120
sub_days = total_days * sub_years / 120
end_dt = dt + timedelta(days=sub_days)
sub_list.append({
"lord": sub_lord,
"start": dt,
"end": end_dt,
})
dt = end_dt
return sub_list
def find_current(timeline, today):
"""找到当前所处的大运"""
for i, d in enumerate(timeline):
if d["start"] <= today < d["end"]:
return i, d
return len(timeline) - 1, timeline[-1]
def find_current_sub(sub_list, today):
"""找到当前小运"""
for d in sub_list:
if d["start"] <= today < d["end"]:
return d
return sub_list[-1]
def print_timeline(timeline, today, show_sub=True):
print(f"\n{'='*62}")
print(f" 📅 Vimshottari Dasha 大运时间线")
print(f"{'='*62}")
print(f" {'大运主星':<22} {'开始':<10} {'结束':<10} {'年限':>4}")
print(f" {'-'*58}")
cur_idx, cur_dasha = find_current(timeline, today)
for i, d in enumerate(timeline):
marker = " ◀ 当前" if i == cur_idx else ""
print(f" {PLANET_CN[d['lord']]:<20} {d['start'].strftime('%Y-%m'):<10} {d['end'].strftime('%Y-%m'):<10} {d['years']:>2}年{marker}")
# 当前大运小运展开
if show_sub:
print(f"\n{'='*62}")
print(f" 🔍 当前大运 [{PLANET_CN[cur_dasha['lord']]}] 小运展开")
print(f"{'='*62}")
sub_list = build_antardasha(cur_dasha)
cur_sub = find_current_sub(sub_list, today)
print(f" {'小运主星':<22} {'开始':<10} {'结束'}")
print(f" {'-'*50}")
for s in sub_list:
marker = " ◀ 当前" if s == cur_sub else ""
print(f" {PLANET_CN[s['lord']]:<20} {s['start'].strftime('%Y-%m-%d'):<10} {s['end'].strftime('%Y-%m-%d')}{marker}")
# 当前小运剩余时间
remaining_days = (cur_sub["end"] - today).days
print(f"\n 当前小运 [{PLANET_CN[cur_sub['lord']]}] 将于 {cur_sub['end'].strftime('%Y年%m月%d日')} 结束")
print(f" 剩余约 {remaining_days} 天({round(remaining_days/30.44, 1)} 个月)")
def main():
parser = argparse.ArgumentParser(description='印度占星 Dasha 推算器(基于已知星盘)')
parser.add_argument('--nakshatra', help='月亮 Nakshatra 名称,如 "Jyeshtha"')
parser.add_argument('--pada', type=int, default=None, help='Nakshatra Pada(1-4)')
parser.add_argument('--moon-lon', type=float, help='月亮恒星黄经(0-360),与--nakshatra二选一')
parser.add_argument('--birthdate', required=True, help='出生日期 YYYY-MM-DD')
parser.add_argument('--today', default=None, help='计算基准日期 YYYY-MM-DD(默认今天)')
args = parser.parse_args()
today = datetime.strptime(args.today, "%Y-%m-%d") if args.today else datetime.now()
print(f"\n{'='*62}")
print(f" 🌙 印度占星 Vimshottari Dasha 推算器")
print(f"{'='*62}")
print(f" 出生日期:{args.birthdate}")
print(f" 计算基准:{today.strftime('%Y-%m-%d')}")
if args.nakshatra:
nak_info = fuzzy_match_nakshatra(args.nakshatra)
if not nak_info:
print(f" ❌ 未找到 Nakshatra:{args.nakshatra}")
print(f" 请检查拼写,或使用 --moon-lon 直接输入月亮黄经")
return
# 若提供了Pada,推算更精确的进度
if args.pada:
pada = max(1, min(4, args.pada))
progress = (pada - 1) / 4 + 0.125 # 每Pada约25%,取中间值
else:
progress = 0.5 # 默认取中间
print(f" 月亮星宿:{nak_info[0]}(大运主星:{nak_info[1]},{nak_info[2]}年)")
if args.pada:
print(f" Pada:第{args.pada}Pada")
elif args.moon_lon is not None:
nak_info, progress, pada = lon_to_nakshatra(args.moon_lon % 360)
print(f" 月亮黄经:{args.moon_lon:.2f}°")
print(f" 月亮星宿:{nak_info[0]}(第{pada}Pada,大运主星:{nak_info[1]})")
else:
print(" ❌ 请提供 --nakshatra 或 --moon-lon")
return
timeline, elapsed, remaining, start_lord = build_dasha_timeline(args.birthdate, nak_info, progress)
print(f"\n 出生时处于 [{PLANET_CN[start_lord]}] 大运")
print(f" 出生时已历时约 {elapsed} 年,剩余约 {remaining} 年")
print_timeline(timeline, today)
print(f"\n{'='*62}\n")
if __name__ == '__main__':
main()