Files
Jyotisha/skills/jyotish-engine-modules/scripts/karaka_calculator.py
T
732642856 3314f244f2 feat: 新增两个 Hermes Skills
- jyotish-engine-modules: 5个核心排盘引擎模块完整代码
  - karaka_calculator.py (Karaka分配计算器,支持BPHS/JH兼容模式)
  - special_lagnas.py (特殊上升点计算)
  - vimsopaka_calculator.py (Vimsopaka Bala分盘力量)
  - avastha_calculator.py (Avasthas行星状态)
  - divisional_charts_extended.py (D2-D60完整分盘)

- jyotish-full-reading-integration: v4.4.0集成方案
  - 21步调用链完整流程
  - 5个新模块插入点详解
  - JH兼容模式使用指南
  - 集成检查清单
  - 自动化测试脚本
  - v4.4.0 CHANGELOG

版本:v4.4.0
调用链:16步 → 21步
新增:special_lagnas/vimsopaka/varga_extended/karaka_jh/avasthas
2026-05-03 20:50:05 +08:00

203 lines
7.2 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
# -*- coding: utf-8 -*-
"""
Karaka Calculator - Jaimini Chara Karaka System
印度占星 Karaka(象征星)计算器
支持两种模式:
1. BPHS标准模式(8-Karaka):Sun > Moon > Mars > Mercury > Jupiter > Venus > Saturn > Rahu
2. Jagannatha Hora兼容模式(7-Karaka + Rahu限制):Rahu只能是Matrukaraka(MK)
核心功能:
- 计算7大Chara Karaka(可变象征星)
- 支持8-Karaka系统(包含Rahu
- 自动识别Karaka模式
- 提供详细的度数排序和Karaka分配
"""
import sys
from typing import Dict, List, Tuple, Optional
from enum import Enum
class KarakaMode(Enum):
"""Karaka计算模式"""
BPHS_8_KARAKA = "bphs" # 标准BPHS 8-Karaka系统
JH_COMPATIBLE = "jh" # Jagannatha Hora兼容模式(Rahu限制在MK
BPHS_7_KARAKA = "bphs7" # 标准BPHS 7-Karaka系统(不含Rahu
class KarakaType(Enum):
"""7大Chara Karaka类型"""
ATMAKARAKA = "AK" # 灵魂象征星(最高度数)
AMATYAKARAKA = "AmK" # 事业象征星(第二高)
BHRATRUKARAKA = "BK" # 兄弟象征星(第三高)
MATRUKARAKA = "MK" # 母亲象征星(第四高)
PUTRAKARAKA = "PK" # 子女象征星(第五高)
GNATIKARAKA = "GK" # 敌人/疾病象征星(第六高)
DARAKARAKA = "DK" # 配偶象征星(最低度数)
EXTRA_KARAKA = "XK" # 额外象征星(仅在8-Karaka系统中)
class KarakaCalculator:
"""Karaka计算器"""
SEVEN_PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
EIGHT_PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu"]
def __init__(self, mode: KarakaMode = KarakaMode.BPHS_8_KARAKA):
self.mode = mode
def calculate_karaka(self, planet_positions: Dict[str, float]) -> Dict[str, any]:
"""
计算Chara Karaka
Args:
planet_positions: 行星位置字典 {行星名: 黄道度数}
Returns:
Karaka分配结果字典
"""
result = {
"mode": self.mode.value,
"karakas": {},
"sorted_planets": [],
"warnings": []
}
# 1. 提取有效行星
valid_planets = self._extract_valid_planets(planet_positions, result)
if not valid_planets:
result["warnings"].append("No valid planets found")
return result
# 2. 转换为星座内度数(0-30度)
sign_degrees = {p: d % 30.0 for p, d in valid_planets.items()}
# 3. 按度数排序(降序)
sorted_planets = sorted(sign_degrees.items(), key=lambda x: x[1], reverse=True)
result["sorted_planets"] = [(p, round(d, 4)) for p, d in sorted_planets]
# 4. 分配Karaka
result["karakas"] = self._assign_karakas(sorted_planets, result)
# 5. 验证
self._validate_karakas(result)
return result
def _extract_valid_planets(self, positions: Dict[str, float], result: Dict) -> Dict[str, float]:
"""提取有效行星"""
valid = {}
planets = self.SEVEN_PLANETS if self.mode == KarakaMode.BPHS_7_KARAKA else self.EIGHT_PLANETS
for planet in planets:
if planet in positions:
valid[planet] = positions[planet]
else:
result["warnings"].append(f"Missing planet: {planet}")
return valid
def _assign_karakas(self, sorted_planets: List[Tuple[str, float]], result: Dict) -> Dict:
"""分配Karaka"""
karakas = {}
if self.mode == KarakaMode.JH_COMPATIBLE:
# JH模式:强制Rahu为MK
rahu_idx = next((i for i, (p, _) in enumerate(sorted_planets) if p == "Rahu"), None)
if rahu_idx is not None and rahu_idx != 3:
result["warnings"].append(f"JH Mode: Rahu forced to MK (was rank {rahu_idx + 1})")
adjusted = [p for p in sorted_planets if p[0] != "Rahu"]
adjusted.insert(3, sorted_planets[rahu_idx])
sorted_planets = adjusted
# 分配Karaka
karaka_types = [
("AK", "灵魂象征星"),
("AmK", "事业象征星"),
("BK", "兄弟象征星"),
("MK", "母亲象征星"),
("PK", "子女象征星"),
("GK", "敌人/疾病象征星"),
]
if self.mode == KarakaMode.BPHS_8_KARAKA:
karaka_types.append(("XK", "额外象征星"))
karaka_types.append(("DK", "配偶象征星"))
for i, (planet, degree) in enumerate(sorted_planets[:len(karaka_types)]):
code, name = karaka_types[i]
karakas[code] = {
"planet": planet,
"sign_degree": round(degree, 4),
"name": name,
"rank": i + 1
}
return karakas
def _validate_karakas(self, result: Dict):
"""验证Karaka分配"""
expected = 7 if self.mode != KarakaMode.BPHS_8_KARAKA else 8
if len(result["karakas"]) != expected:
result["warnings"].append(f"Expected {expected} Karakas, got {len(result['karakas'])}")
def format_output(self, result: Dict) -> str:
"""格式化输出"""
lines = ["=" * 60, "Chara Karaka Calculation", "=" * 60]
lines.append(f"Mode: {result['mode'].upper()}\n")
lines.append("Karaka Assignment:")
for code, data in result['karakas'].items():
lines.append(f" {code:4s} = {data['planet']:10s} ({data['sign_degree']:6.2f}°) - {data['name']}")
if result['warnings']:
lines.append("\nWarnings:")
for w in result['warnings']:
lines.append(f" ⚠️ {w}")
lines.append("=" * 60)
return "\n".join(lines)
def main():
"""命令行接口"""
import argparse
parser = argparse.ArgumentParser(description="Calculate Jaimini Chara Karaka")
parser.add_argument("--mode", choices=["bphs", "jh", "bphs7"], default="bphs")
parser.add_argument("--planets", type=str, help="Format: Sun:45.5,Moon:120.3,...")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
# 解析行星位置
if args.planets:
positions = {}
for pair in args.planets.split(","):
planet, degree = pair.split(":")
positions[planet.strip()] = float(degree.strip())
else:
# 示例数据
positions = {
"Sun": 45.5, "Moon": 120.3, "Mars": 200.1,
"Mercury": 50.8, "Jupiter": 180.5, "Venus": 90.2,
"Saturn": 250.7, "Rahu": 150.4
}
print("Using example data\n")
# 计算
mode_map = {"bphs": KarakaMode.BPHS_8_KARAKA, "jh": KarakaMode.JH_COMPATIBLE, "bphs7": KarakaMode.BPHS_7_KARAKA}
calc = KarakaCalculator(mode=mode_map[args.mode])
result = calc.calculate_karaka(positions)
# 输出
if args.json:
import json
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(calc.format_output(result))
if __name__ == "__main__":
main()