feat: v4.4.0 集成5个新模块到21步full-reading调用链 + 修复Dasha years展示

## 核心变更

### 1. full-reading 调用链从 16 步扩展到 21 步 (v4.4.0)
- Step 1.5: Special Lagnas 特殊上升点(Bhava/Hora/Ghati/Arudha/Upapada)
- Step 4.5: Vimsopaka Bala 分盘力量(16分盘权重系统)
- Step 4.6: Divisional Charts Extended 扩展分盘(D5/D6/D8/D11)
- Step 6+: Karaka JH Compatible Mode(Jagannatha Hora 兼容)
- Step 10.5: Avasthas 行星状态(5种状态体系)

### 2. 修复 Dasha timeline 第一个 MD 的 years 字段
- 之前: years 显示完整年数(如 18 年)
- 修复: 第一个 MD 的 years 显示 balance(如 11.1 年)
- 新增 is_balance 字段标识
- 日期计算本身始终正确,本次仅修正展示值

### 3. 消除根目录重复文件
- 5 个模块从根目录移至 scripts/(与其他 19 个模块一致)
- skills/jyotish-engine-modules/ 保留作为独立分发包
- 更新嵌套 Skill 的导入路径说明

### 版本号
- full-reading: v4.1.0 → v4.4.0
This commit is contained in:
732642856
2026-05-04 22:43:56 +08:00
parent fb5085ca17
commit a9a74d339d
7 changed files with 107 additions and 9 deletions
+481
View File
@@ -0,0 +1,481 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Avastha Calculator - 行星状态计算器
印度占星 Avastha(行星状态)系统
核心功能:
- Bala Avastha(年龄状态):5种生命阶段
- Jagrat Avastha(警觉状态):3种意识状态
- Deeptadi Avastha(情绪状态):15种情绪/能量状态
- Lajjitadi Avastha(羞耻状态):6种社会状态
- Shayanadi Avastha(姿态状态):12种行为模式
参考文献:
- Brihat Parashara Hora Shastra (BPHS) Chapter 47-48
- Phaladeepika by Mantreswara
- Jataka Parijata by Vaidyanatha Dikshita
"""
from typing import Dict, List, Tuple
from enum import Enum
class BalaAvastha(Enum):
"""年龄状态(5种生命阶段)"""
INFANT = "Infant" # 婴儿期(0-6度)
YOUNG = "Young" # 少年期(6-12度)
YOUTH = "Youth" # 青年期(12-18度)
OLD = "Old" # 老年期(18-24度)
DEAD = "Dead" # 死亡期(24-30度)
class JagratAvastha(Enum):
"""警觉状态(3种意识状态)"""
AWAKE = "Awake" # 清醒(Jagrat)
DREAMING = "Dreaming" # 梦境(Swapna)
DEEP_SLEEP = "Deep Sleep" # 深睡(Sushupti)
class DeeptadiAvastha(Enum):
"""情绪状态(15种)- Deeptadi Avastha"""
DEEPTA = "Deepta" # 光辉(Exalted)
SWASTHA = "Swastha" # 舒适(Own Sign)
MUDITA = "Mudita" # 快乐(Friend's Sign)
SHANTA = "Shanta" # 平静(Neutral Sign)
DINA = "Dina" # 沮丧(Enemy Sign)
VIKALA = "Vikala" # 残缺(Debilitated)
KHALA = "Khala" # 恶意(Combust)
KOPA = "Kopa" # 愤怒(Defeated in War)
GARVITA = "Garvita" # 骄傲(Victorious in War)
KSHUDITA = "Kshudita" # 饥饿(In Sandhi)
TRUSHITA = "Trushita" # 口渴(In Gandanta)
MUDITA_SPECIAL = "Mudita" # 特殊快乐(Aspected by Jupiter)
KSHOBHITA = "Kshobhita" # 激动(Aspected by Mars)
LAJJITA = "Lajjita" # 羞耻(Aspected by Saturn)
GARVITA_SPECIAL = "Garvita" # 特殊骄傲(Aspected by Mercury)
class LajjitadiAvastha(Enum):
"""羞耻状态(6种社会状态)"""
LAJJITA = "Lajjita" # 羞耻(与敌对行星同宫)
GARVITA = "Garvita" # 骄傲(入庙)
KSHUDITA = "Kshudita" # 饥饿(在6/8/12宫)
TRUSHITA = "Trushita" # 口渴(在火象星座)
MUDITA = "Mudita" # 快乐(与友好行星同宫)
KSHOBHITA = "Kshobhita" # 激动(与火星同宫)
class ShayanadiAvastha(Enum):
"""姿态状态(12种行为模式)"""
SHAYANA = "Shayana" # 躺卧(在水象星座)
UPAVESHANA = "Upaveshana" # 坐着(在土象星座)
NETRAPANI = "Netrapani" # 手持武器(在火象星座)
PRAKASHANA = "Prakashana" # 显现(在风象星座)
GAMANA = "Gamana" # 行走(在双体星座)
AGAMANA = "Agamana" # 到来(在固定星座)
SABHA = "Sabha" # 集会(在变动星座)
AGAMA = "Agama" # 学习(在水星星座)
BHOJANA = "Bhojana" # 进食(在金星星座)
NRITYALIPSA = "Nrityalipsa" # 舞蹈(在月亮星座)
KAUTUKA = "Kautuka" # 好奇(在木星星座)
NIDRA = "Nidra" # 睡眠(在土星星座)
class AvasthaCalculator:
"""行星状态计算器"""
# 星座分类
FIRE_SIGNS = ["Aries", "Leo", "Sagittarius"]
EARTH_SIGNS = ["Taurus", "Virgo", "Capricorn"]
AIR_SIGNS = ["Gemini", "Libra", "Aquarius"]
WATER_SIGNS = ["Cancer", "Scorpio", "Pisces"]
DUAL_SIGNS = ["Gemini", "Virgo", "Sagittarius", "Pisces"]
FIXED_SIGNS = ["Taurus", "Leo", "Scorpio", "Aquarius"]
MOVABLE_SIGNS = ["Aries", "Cancer", "Libra", "Capricorn"]
# 行星主宰星座
PLANET_SIGNS = {
"Mercury": ["Gemini", "Virgo"],
"Venus": ["Taurus", "Libra"],
"Moon": ["Cancer"],
"Jupiter": ["Sagittarius", "Pisces"],
"Saturn": ["Capricorn", "Aquarius"],
"Mars": ["Aries", "Scorpio"],
"Sun": ["Leo"]
}
# 行星入庙/落陷度数
EXALTATION = {
"Sun": ("Aries", 10),
"Moon": ("Taurus", 3),
"Mars": ("Capricorn", 28),
"Mercury": ("Virgo", 15),
"Jupiter": ("Cancer", 5),
"Venus": ("Pisces", 27),
"Saturn": ("Libra", 20)
}
DEBILITATION = {
"Sun": ("Libra", 10),
"Moon": ("Scorpio", 3),
"Mars": ("Cancer", 28),
"Mercury": ("Pisces", 15),
"Jupiter": ("Capricorn", 5),
"Venus": ("Virgo", 27),
"Saturn": ("Aries", 20)
}
def __init__(self):
pass
def calculate_all_avasthas(self, planet: str, sign: str, degree: float,
house: int, conjunctions: List[str] = None,
aspects: List[str] = None, is_combust: bool = False,
is_retrograde: bool = False) -> Dict[str, any]:
"""
计算行星的所有Avastha状态
Args:
planet: 行星名
sign: 所在星座
degree: 星座内度数(0-30)
house: 所在宫位(1-12)
conjunctions: 合相的行星列表
aspects: 相位的行星列表
is_combust: 是否燃烧
is_retrograde: 是否逆行
Returns:
所有Avastha状态的字典
"""
result = {
"planet": planet,
"sign": sign,
"degree": round(degree, 4),
"house": house,
"avasthas": {}
}
# 1. Bala Avastha(年龄状态)
result["avasthas"]["Bala"] = self._calculate_bala_avastha(degree)
# 2. Jagrat Avastha(警觉状态)
result["avasthas"]["Jagrat"] = self._calculate_jagrat_avastha(planet, sign, house)
# 3. Deeptadi Avastha(情绪状态)
result["avasthas"]["Deeptadi"] = self._calculate_deeptadi_avastha(
planet, sign, degree, is_combust, aspects
)
# 4. Lajjitadi Avastha(羞耻状态)
result["avasthas"]["Lajjitadi"] = self._calculate_lajjitadi_avastha(
planet, sign, house, conjunctions
)
# 5. Shayanadi Avastha(姿态状态)
result["avasthas"]["Shayanadi"] = self._calculate_shayanadi_avastha(planet, sign)
# 6. 综合解读
result["interpretation"] = self._generate_interpretation(result["avasthas"])
# 7. 补救建议
result["remedies"] = self._generate_remedies(planet, result["avasthas"])
return result
def _calculate_bala_avastha(self, degree: float) -> Dict:
"""计算Bala Avastha(年龄状态)"""
if degree < 6:
state = BalaAvastha.INFANT
strength = 0.2
meaning = "婴儿期:行星力量微弱,潜力未开发,需要时间成长"
elif degree < 12:
state = BalaAvastha.YOUNG
strength = 0.5
meaning = "少年期:行星力量增长中,开始显现特质,但尚未成熟"
elif degree < 18:
state = BalaAvastha.YOUTH
strength = 1.0
meaning = "青年期:行星力量最强,充满活力,能够充分发挥作用"
elif degree < 24:
state = BalaAvastha.OLD
strength = 0.7
meaning = "老年期:行星力量开始衰退,经验丰富但活力下降"
else:
state = BalaAvastha.DEAD
strength = 0.3
meaning = "死亡期:行星力量极弱,难以发挥作用,需要补救"
return {
"state": state.value,
"degree_range": f"{int(degree//6)*6}-{int(degree//6)*6+6}°",
"strength": strength,
"meaning": meaning
}
def _calculate_jagrat_avastha(self, planet: str, sign: str, house: int) -> Dict:
"""计算Jagrat Avastha(警觉状态)"""
# 简化规则:
# Awake: 在角宫(1,4,7,10)
# Dreaming: 在续宫(2,5,8,11)
# Deep Sleep: 在果宫(3,6,9,12)
if house in [1, 4, 7, 10]:
state = JagratAvastha.AWAKE
meaning = "清醒状态:行星完全活跃,能够主动发挥作用,影响显著"
elif house in [2, 5, 8, 11]:
state = JagratAvastha.DREAMING
meaning = "梦境状态:行星半活跃,作用不稳定,时强时弱"
else:
state = JagratAvastha.DEEP_SLEEP
meaning = "深睡状态:行星不活跃,难以发挥作用,影响微弱"
return {
"state": state.value,
"house": house,
"meaning": meaning
}
def _calculate_deeptadi_avastha(self, planet: str, sign: str, degree: float,
is_combust: bool, aspects: List[str] = None) -> Dict:
"""计算Deeptadi Avastha(情绪状态)"""
aspects = aspects or []
# 检查入庙/落陷
if self._is_exalted(planet, sign, degree):
state = DeeptadiAvastha.DEEPTA
meaning = "光辉状态:行星处于最佳位置,能量充沛,带来积极结果"
elif self._is_debilitated(planet, sign, degree):
state = DeeptadiAvastha.VIKALA
meaning = "残缺状态:行星处于最弱位置,能量受损,带来挑战"
elif is_combust:
state = DeeptadiAvastha.KHALA
meaning = "恶意状态:行星被太阳燃烧,能量被压制,难以正常发挥"
elif self._is_own_sign(planet, sign):
state = DeeptadiAvastha.SWASTHA
meaning = "舒适状态:行星在自己的星座,感觉自在,能够稳定发挥"
elif self._is_friend_sign(planet, sign):
state = DeeptadiAvastha.MUDITA
meaning = "快乐状态:行星在友好星座,得到支持,能够良好发挥"
elif self._is_enemy_sign(planet, sign):
state = DeeptadiAvastha.DINA
meaning = "沮丧状态:行星在敌对星座,受到压制,发挥受限"
else:
state = DeeptadiAvastha.SHANTA
meaning = "平静状态:行星在中性星座,不强不弱,平稳发挥"
# 检查相位影响
aspect_effects = []
if "Jupiter" in aspects:
aspect_effects.append("木星相位:增加乐观和扩展性")
if "Mars" in aspects:
aspect_effects.append("火星相位:增加激情和冲动性")
if "Saturn" in aspects:
aspect_effects.append("土星相位:增加限制和责任感")
if "Mercury" in aspects:
aspect_effects.append("水星相位:增加智慧和沟通能力")
return {
"state": state.value,
"meaning": meaning,
"aspect_effects": aspect_effects
}
def _calculate_lajjitadi_avastha(self, planet: str, sign: str, house: int,
conjunctions: List[str] = None) -> Dict:
"""计算Lajjitadi Avastha(羞耻状态)"""
conjunctions = conjunctions or []
# 简化规则
if self._is_exalted(planet, sign, 15): # 简化判断
state = LajjitadiAvastha.GARVITA
meaning = "骄傲状态:行星入庙,充满自信,能够展现最佳特质"
elif house in [6, 8, 12]:
state = LajjitadiAvastha.KSHUDITA
meaning = "饥饿状态:行星在困难宫位,渴望满足,但难以获得"
elif sign in self.FIRE_SIGNS:
state = LajjitadiAvastha.TRUSHITA
meaning = "口渴状态:行星在火象星座,能量过热,需要冷却"
elif "Mars" in conjunctions:
state = LajjitadiAvastha.KSHOBHITA
meaning = "激动状态:与火星合相,能量激烈,容易冲动"
elif any(self._is_enemy_planet(planet, conj) for conj in conjunctions):
state = LajjitadiAvastha.LAJJITA
meaning = "羞耻状态:与敌对行星同宫,感到不适,发挥受限"
else:
state = LajjitadiAvastha.MUDITA
meaning = "快乐状态:与友好行星同宫,感到愉悦,能够良好发挥"
return {
"state": state.value,
"meaning": meaning,
"conjunctions": conjunctions
}
def _calculate_shayanadi_avastha(self, planet: str, sign: str) -> Dict:
"""计算Shayanadi Avastha(姿态状态)"""
# 根据星座元素和类型判断
if sign in self.WATER_SIGNS:
state = ShayanadiAvastha.SHAYANA
meaning = "躺卧姿态:行星在水象星座,处于休息状态,被动接受"
elif sign in self.EARTH_SIGNS:
state = ShayanadiAvastha.UPAVESHANA
meaning = "坐着姿态:行星在土象星座,稳定扎根,缓慢行动"
elif sign in self.FIRE_SIGNS:
state = ShayanadiAvastha.NETRAPANI
meaning = "持武器姿态:行星在火象星座,充满战斗力,主动出击"
elif sign in self.AIR_SIGNS:
state = ShayanadiAvastha.PRAKASHANA
meaning = "显现姿态:行星在风象星座,灵活多变,善于表达"
else:
state = ShayanadiAvastha.GAMANA
meaning = "行走姿态:行星处于移动状态,不断变化"
# 根据行星主宰星座判断特殊状态
for planet_name, signs in self.PLANET_SIGNS.items():
if sign in signs:
if planet_name == "Mercury":
state = ShayanadiAvastha.AGAMA
meaning = "学习姿态:在水星星座,专注于学习和沟通"
elif planet_name == "Venus":
state = ShayanadiAvastha.BHOJANA
meaning = "进食姿态:在金星星座,享受物质和感官愉悦"
elif planet_name == "Moon":
state = ShayanadiAvastha.NRITYALIPSA
meaning = "舞蹈姿态:在月亮星座,情感丰富,富有表现力"
elif planet_name == "Jupiter":
state = ShayanadiAvastha.KAUTUKA
meaning = "好奇姿态:在木星星座,渴望探索和扩展"
elif planet_name == "Saturn":
state = ShayanadiAvastha.NIDRA
meaning = "睡眠姿态:在土星星座,能量收缩,需要休息"
break
return {
"state": state.value,
"sign": sign,
"meaning": meaning
}
def _is_exalted(self, planet: str, sign: str, degree: float) -> bool:
"""检查是否入庙"""
if planet in self.EXALTATION:
exalt_sign, exalt_degree = self.EXALTATION[planet]
return sign == exalt_sign and abs(degree - exalt_degree) < 5
return False
def _is_debilitated(self, planet: str, sign: str, degree: float) -> bool:
"""检查是否落陷"""
if planet in self.DEBILITATION:
debil_sign, debil_degree = self.DEBILITATION[planet]
return sign == debil_sign and abs(degree - debil_degree) < 5
return False
def _is_own_sign(self, planet: str, sign: str) -> bool:
"""检查是否在自己的星座"""
return sign in self.PLANET_SIGNS.get(planet, [])
def _is_friend_sign(self, planet: str, sign: str) -> bool:
"""检查是否在友好星座(简化版)"""
# 这里需要完整的行星友好关系表,暂时简化
return False
def _is_enemy_sign(self, planet: str, sign: str) -> bool:
"""检查是否在敌对星座(简化版)"""
# 这里需要完整的行星敌对关系表,暂时简化
return False
def _is_enemy_planet(self, planet1: str, planet2: str) -> bool:
"""检查两个行星是否敌对(简化版)"""
# 这里需要完整的行星关系表,暂时简化
enemies = {
"Sun": ["Saturn", "Venus"],
"Moon": ["Rahu", "Ketu"],
"Mars": ["Mercury"],
"Mercury": ["Moon"],
"Jupiter": ["Mercury", "Venus"],
"Venus": ["Sun", "Moon"],
"Saturn": ["Sun", "Moon", "Mars"]
}
return planet2 in enemies.get(planet1, [])
def _generate_interpretation(self, avasthas: Dict) -> str:
"""生成综合解读"""
interpretation = "行星状态综合分析:\n\n"
# Bala Avastha
bala = avasthas["Bala"]
interpretation += f"1. 年龄状态:{bala['state']}({bala['degree_range']})\n"
interpretation += f" {bala['meaning']}\n\n"
# Jagrat Avastha
jagrat = avasthas["Jagrat"]
interpretation += f"2. 警觉状态:{jagrat['state']}(第{jagrat['house']}宫)\n"
interpretation += f" {jagrat['meaning']}\n\n"
# Deeptadi Avastha
deeptadi = avasthas["Deeptadi"]
interpretation += f"3. 情绪状态:{deeptadi['state']}\n"
interpretation += f" {deeptadi['meaning']}\n"
if deeptadi['aspect_effects']:
interpretation += " 相位影响:\n"
for effect in deeptadi['aspect_effects']:
interpretation += f" - {effect}\n"
interpretation += "\n"
# Lajjitadi Avastha
lajjitadi = avasthas["Lajjitadi"]
interpretation += f"4. 社会状态:{lajjitadi['state']}\n"
interpretation += f" {lajjitadi['meaning']}\n\n"
# Shayanadi Avastha
shayanadi = avasthas["Shayanadi"]
interpretation += f"5. 行为模式:{shayanadi['state']}({shayanadi['sign']})\n"
interpretation += f" {shayanadi['meaning']}\n"
return interpretation
def _generate_remedies(self, planet: str, avasthas: Dict) -> List[str]:
"""生成补救建议"""
remedies = []
# 根据Bala Avastha
bala_strength = avasthas["Bala"]["strength"]
if bala_strength < 0.5:
remedies.append(f"行星处于弱势年龄阶段,建议佩戴{planet}对应的宝石")
remedies.append(f"在{planet}主管的日子进行布施和祈祷")
# 根据Jagrat Avastha
if avasthas["Jagrat"]["state"] == "Deep Sleep":
remedies.append("行星处于深睡状态,建议通过冥想和咒语激活其能量")
# 根据Deeptadi Avastha
deeptadi_state = avasthas["Deeptadi"]["state"]
if deeptadi_state in ["Vikala", "Khala", "Dina"]:
remedies.append(f"行星处于{deeptadi_state}状态,需要特别补救")
remedies.append(f"念诵{planet}的Beeja Mantra(种子咒)")
return remedies
# 示例用法
if __name__ == "__main__":
calculator = AvasthaCalculator()
# 示例:太阳在白羊座15度,第10宫
result = calculator.calculate_all_avasthas(
planet="Sun",
sign="Aries",
degree=15.0,
house=10,
conjunctions=["Mercury"],
aspects=["Jupiter", "Saturn"],
is_combust=False,
is_retrograde=False
)
print("="*60)
print(f"{result['planet']} 在 {result['sign']} {result['degree']}° (第{result['house']}宫)")
print("="*60)
print(result['interpretation'])
if result['remedies']:
print("\n补救建议:")
for i, remedy in enumerate(result['remedies'], 1):
print(f"{i}. {remedy}")
+534
View File
@@ -0,0 +1,534 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Divisional Charts Extended - D2-D60完整分盘宫位图计算器
印度占星 Shodasavarga(16分盘)+ 扩展分盘系统
核心功能:
- 计算D1-D60所有分盘的行星位置
- 生成每个分盘的12宫位行星分布图
- 支持BPHS标准算法
- 提供分盘上升点计算
- 输出可视化宫位图数据
参考文献:
- Brihat Parashara Hora Shastra (BPHS) Chapter 6
- Phaladeepika by Mantreswara
- Jataka Parijata by Vaidyanatha Dikshita
"""
from typing import Dict, List, Tuple
from enum import Enum
class VargaType(Enum):
"""分盘类型枚举"""
D1 = (1, "Rashi", "本命盘")
D2 = (2, "Hora", "财富")
D3 = (3, "Drekkana", "兄弟姐妹")
D4 = (4, "Chaturthamsa", "财产/运气")
D5 = (5, "Panchamsa", "名声/权力")
D6 = (6, "Shashthamsa", "健康/敌人")
D7 = (7, "Saptamsa", "子女")
D8 = (8, "Ashtamsa", "突发事件")
D9 = (9, "Navamsa", "配偶/灵性")
D10 = (10, "Dasamsa", "事业")
D11 = (11, "Rudramsa", "破坏/转化")
D12 = (12, "Dwadasamsa", "父母")
D16 = (16, "Shodasamsa", "交通工具/舒适")
D20 = (20, "Vimsamsa", "灵性修行")
D24 = (24, "Chaturvimsamsa", "教育/学习")
D27 = (27, "Bhamsa", "力量/弱点")
D30 = (30, "Trimsamsa", "不幸/困难")
D40 = (40, "Khavedamsa", "吉凶效果")
D45 = (45, "Akshavedamsa", "全面判断")
D60 = (60, "Shashtiamsa", "前世业力")
def __init__(self, division: int, name: str, meaning: str):
self.division = division
self.varga_name = name
self.meaning = meaning
class DivisionalChartsCalculator:
"""分盘计算器"""
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
# 星座分类
MOVABLE_SIGNS = [0, 3, 6, 9] # Aries, Cancer, Libra, Capricorn
FIXED_SIGNS = [1, 4, 7, 10] # Taurus, Leo, Scorpio, Aquarius
DUAL_SIGNS = [2, 5, 8, 11] # Gemini, Virgo, Sagittarius, Pisces
ODD_SIGNS = [0, 2, 4, 6, 8, 10] # 奇数星座
EVEN_SIGNS = [1, 3, 5, 7, 9, 11] # 偶数星座
def __init__(self):
pass
def calculate_all_vargas(self, planet_positions: Dict[str, float],
asc_degree: float) -> Dict[str, Dict]:
"""
计算所有分盘的行星位置
Args:
planet_positions: {行星名: 黄道度数(0-360)}
asc_degree: 上升点黄道度数(0-360)
Returns:
{分盘名: {
"planets": {行星名: {"sign": 星座, "degree": 度数, "house": 宫位}},
"ascendant": {"sign": 星座, "degree": 度数},
"house_chart": [宫位1的行星列表, 宫位2的行星列表, ...]
}}
"""
results = {}
# 计算所有分盘
for varga_type in VargaType:
varga_result = self._calculate_single_varga(
varga_type, planet_positions, asc_degree
)
results[varga_type.varga_name] = varga_result
return results
def _calculate_single_varga(self, varga_type: VargaType,
planet_positions: Dict[str, float],
asc_degree: float) -> Dict:
"""计算单个分盘"""
division = varga_type.division
# 计算分盘上升点
varga_asc = self._calculate_varga_position(asc_degree, division)
varga_asc_sign = int(varga_asc // 30)
varga_asc_degree = varga_asc % 30
# 计算所有行星的分盘位置
varga_planets = {}
for planet, degree in planet_positions.items():
varga_pos = self._calculate_varga_position(degree, division)
varga_sign = int(varga_pos // 30)
varga_degree = varga_pos % 30
# 计算宫位(从上升点开始)
house = ((varga_sign - varga_asc_sign) % 12) + 1
varga_planets[planet] = {
"sign": self.SIGNS[varga_sign],
"sign_index": varga_sign,
"degree": round(varga_degree, 4),
"house": house,
"absolute_degree": round(varga_pos, 4)
}
# 生成宫位图(12个宫位,每个宫位包含的行星列表)
house_chart = [[] for _ in range(12)]
for planet, data in varga_planets.items():
house_chart[data["house"] - 1].append(planet)
return {
"division": division,
"name": varga_type.varga_name,
"meaning": varga_type.meaning,
"ascendant": {
"sign": self.SIGNS[varga_asc_sign],
"sign_index": varga_asc_sign,
"degree": round(varga_asc_degree, 4)
},
"planets": varga_planets,
"house_chart": house_chart
}
def _calculate_varga_position(self, degree: float, division: int) -> float:
"""
计算分盘位置(BPHS标准算法)
Args:
degree: 黄道度数(0-360)
division: 分盘数(2-60)
Returns:
分盘中的黄道度数(0-360)
"""
# 获取星座索引和星座内度数
sign_index = int(degree // 30)
sign_degree = degree % 30
# 根据不同分盘使用不同算法
if division == 2:
return self._calculate_d2(sign_index, sign_degree)
elif division == 3:
return self._calculate_d3(sign_index, sign_degree)
elif division == 4:
return self._calculate_d4(sign_index, sign_degree)
elif division == 5:
return self._calculate_d5(sign_index, sign_degree)
elif division == 6:
return self._calculate_d6(sign_index, sign_degree)
elif division == 7:
return self._calculate_d7(sign_index, sign_degree)
elif division == 8:
return self._calculate_d8(sign_index, sign_degree)
elif division == 9:
return self._calculate_d9(sign_index, sign_degree)
elif division == 10:
return self._calculate_d10(sign_index, sign_degree)
elif division == 11:
return self._calculate_d11(sign_index, sign_degree)
elif division == 12:
return self._calculate_d12(sign_index, sign_degree)
elif division == 16:
return self._calculate_d16(sign_index, sign_degree)
elif division == 20:
return self._calculate_d20(sign_index, sign_degree)
elif division == 24:
return self._calculate_d24(sign_index, sign_degree)
elif division == 27:
return self._calculate_d27(sign_index, sign_degree)
elif division == 30:
return self._calculate_d30(sign_index, sign_degree)
elif division == 40:
return self._calculate_d40(sign_index, sign_degree)
elif division == 45:
return self._calculate_d45(sign_index, sign_degree)
elif division == 60:
return self._calculate_d60(sign_index, sign_degree)
else:
# 通用算法(适用于其他分盘)
return self._calculate_generic_varga(sign_index, sign_degree, division)
def _calculate_d2(self, sign_index: int, sign_degree: float) -> float:
"""D2 Hora - 财富分盘"""
# 奇数星座:0-15度→Leo,15-30度→Cancer
# 偶数星座:0-15度→Cancer,15-30度→Leo
if sign_index in self.ODD_SIGNS:
if sign_degree < 15:
return 4 * 30 + sign_degree * 2 # Leo
else:
return 3 * 30 + (sign_degree - 15) * 2 # Cancer
else:
if sign_degree < 15:
return 3 * 30 + sign_degree * 2 # Cancer
else:
return 4 * 30 + (sign_degree - 15) * 2 # Leo
def _calculate_d3(self, sign_index: int, sign_degree: float) -> float:
"""D3 Drekkana - 兄弟姐妹分盘"""
# 每个星座分为3个10度区间
# 第1个10度→本星座,第2个10度→第5个星座,第3个10度→第9个星座
drekkana = int(sign_degree // 10)
offset = [0, 4, 8][drekkana]
varga_sign = (sign_index + offset) % 12
varga_degree = (sign_degree % 10) * 3
return varga_sign * 30 + varga_degree
def _calculate_d4(self, sign_index: int, sign_degree: float) -> float:
"""D4 Chaturthamsa - 财产/运气分盘"""
# 每个星座分为4个7.5度区间
part = int(sign_degree // 7.5)
varga_sign = (sign_index + part * 3) % 12
varga_degree = (sign_degree % 7.5) * 4
return varga_sign * 30 + varga_degree
def _calculate_d7(self, sign_index: int, sign_degree: float) -> float:
"""D7 Saptamsa - 子女分盘"""
# 每个星座分为7个约4.286度区间
part = int(sign_degree // (30/7))
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 6 + part) % 12
varga_degree = (sign_degree % (30/7)) * 7
return varga_sign * 30 + varga_degree
def _calculate_d9(self, sign_index: int, sign_degree: float) -> float:
"""D9 Navamsa - 配偶/灵性分盘(最重要的分盘)"""
# 每个星座分为9个3.333度区间
part = int(sign_degree // (30/9))
# 根据星座类型确定起始点
if sign_index in self.MOVABLE_SIGNS:
start = sign_index # 从本星座开始
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 8) % 12 # 从第9个星座开始
else: # DUAL_SIGNS
start = (sign_index + 4) % 12 # 从第5个星座开始
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/9)) * 9
return varga_sign * 30 + varga_degree
def _calculate_d10(self, sign_index: int, sign_degree: float) -> float:
"""D10 Dasamsa - 事业分盘"""
# 每个星座分为10个3度区间
part = int(sign_degree // 3)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 3) * 10
return varga_sign * 30 + varga_degree
def _calculate_d12(self, sign_index: int, sign_degree: float) -> float:
"""D12 Dwadasamsa - 父母分盘"""
# 每个星座分为12个2.5度区间
part = int(sign_degree // 2.5)
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % 2.5) * 12
return varga_sign * 30 + varga_degree
def _calculate_d16(self, sign_index: int, sign_degree: float) -> float:
"""D16 Shodasamsa - 交通工具/舒适分盘"""
# 每个星座分为16个1.875度区间
part = int(sign_degree // 1.875)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 4) % 12
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 1.875) * 16
return varga_sign * 30 + varga_degree
def _calculate_d20(self, sign_index: int, sign_degree: float) -> float:
"""D20 Vimsamsa - 灵性修行分盘"""
# 每个星座分为20个1.5度区间
part = int(sign_degree // 1.5)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 8) % 12
else:
start = (sign_index + 4) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 1.5) * 20
return varga_sign * 30 + varga_degree
def _calculate_d24(self, sign_index: int, sign_degree: float) -> float:
"""D24 Chaturvimsamsa - 教育/学习分盘"""
# 每个星座分为24个1.25度区间
part = int(sign_degree // 1.25)
if sign_index in self.ODD_SIGNS:
varga_sign = (4 + part) % 12 # 从Leo开始
else:
varga_sign = (3 + part) % 12 # 从Cancer开始
varga_degree = (sign_degree % 1.25) * 24
return varga_sign * 30 + varga_degree
def _calculate_d27(self, sign_index: int, sign_degree: float) -> float:
"""D27 Bhamsa - 力量/弱点分盘"""
# 每个星座分为27个1.111度区间
part = int(sign_degree // (30/27))
if sign_index in self.ODD_SIGNS:
start = sign_index
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/27)) * 27
return varga_sign * 30 + varga_degree
def _calculate_d30(self, sign_index: int, sign_degree: float) -> float:
"""D30 Trimsamsa - 不幸/困难分盘(特殊算法)"""
# D30使用特殊的不等分算法
# 奇数星座:Mars(5°), Saturn(5°), Jupiter(8°), Mercury(7°), Venus(5°)
# 偶数星座:Venus(5°), Mercury(7°), Jupiter(8°), Saturn(5°), Mars(5°)
if sign_index in self.ODD_SIGNS:
if sign_degree < 5:
varga_sign = 0 # Aries (Mars)
varga_degree = sign_degree * 6
elif sign_degree < 10:
varga_sign = 10 # Aquarius (Saturn)
varga_degree = (sign_degree - 5) * 6
elif sign_degree < 18:
varga_sign = 8 # Sagittarius (Jupiter)
varga_degree = (sign_degree - 10) * 3.75
elif sign_degree < 25:
varga_sign = 2 # Gemini (Mercury)
varga_degree = (sign_degree - 18) * 4.286
else:
varga_sign = 1 # Taurus (Venus)
varga_degree = (sign_degree - 25) * 6
else:
if sign_degree < 5:
varga_sign = 1 # Taurus (Venus)
varga_degree = sign_degree * 6
elif sign_degree < 12:
varga_sign = 2 # Gemini (Mercury)
varga_degree = (sign_degree - 5) * 4.286
elif sign_degree < 20:
varga_sign = 8 # Sagittarius (Jupiter)
varga_degree = (sign_degree - 12) * 3.75
elif sign_degree < 25:
varga_sign = 10 # Aquarius (Saturn)
varga_degree = (sign_degree - 20) * 6
else:
varga_sign = 0 # Aries (Mars)
varga_degree = (sign_degree - 25) * 6
return varga_sign * 30 + varga_degree
def _calculate_d40(self, sign_index: int, sign_degree: float) -> float:
"""D40 Khavedamsa - 吉凶效果分盘"""
# 每个星座分为40个0.75度区间
part = int(sign_degree // 0.75)
if sign_index in self.MOVABLE_SIGNS:
start = sign_index
elif sign_index in self.FIXED_SIGNS:
start = (sign_index + 8) % 12
else:
start = (sign_index + 4) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % 0.75) * 40
return varga_sign * 30 + varga_degree
def _calculate_d45(self, sign_index: int, sign_degree: float) -> float:
"""D45 Akshavedamsa - 全面判断分盘"""
# 每个星座分为45个0.667度区间
part = int(sign_degree // (30/45))
if sign_index in self.ODD_SIGNS:
start = sign_index
else:
start = (sign_index + 8) % 12
varga_sign = (start + part) % 12
varga_degree = (sign_degree % (30/45)) * 45
return varga_sign * 30 + varga_degree
def _calculate_d60(self, sign_index: int, sign_degree: float) -> float:
"""D60 Shashtiamsa - 前世业力分盘(最精细的分盘)"""
# 每个星座分为60个0.5度区间
part = int(sign_degree // 0.5)
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % 0.5) * 60
return varga_sign * 30 + varga_degree
def _calculate_d5(self, sign_index: int, sign_degree: float) -> float:
"""D5 Panchamsa - 名声/权力分盘"""
part = int(sign_degree // 6)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 6) * 5
return varga_sign * 30 + varga_degree
def _calculate_d6(self, sign_index: int, sign_degree: float) -> float:
"""D6 Shashthamsa - 健康/敌人分盘"""
part = int(sign_degree // 5)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 6 + part) % 12
varga_degree = (sign_degree % 5) * 6
return varga_sign * 30 + varga_degree
def _calculate_d8(self, sign_index: int, sign_degree: float) -> float:
"""D8 Ashtamsa - 突发事件分盘"""
part = int(sign_degree // 3.75)
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % 3.75) * 8
return varga_sign * 30 + varga_degree
def _calculate_d11(self, sign_index: int, sign_degree: float) -> float:
"""D11 Rudramsa - 破坏/转化分盘"""
part = int(sign_degree // (30/11))
if sign_index in self.ODD_SIGNS:
varga_sign = (sign_index + part) % 12
else:
varga_sign = (sign_index + 8 + part) % 12
varga_degree = (sign_degree % (30/11)) * 11
return varga_sign * 30 + varga_degree
def _calculate_generic_varga(self, sign_index: int, sign_degree: float, division: int) -> float:
"""通用分盘算法(适用于其他分盘)"""
part = int(sign_degree // (30/division))
varga_sign = (sign_index + part) % 12
varga_degree = (sign_degree % (30/division)) * division
return varga_sign * 30 + varga_degree
def generate_house_chart_ascii(self, house_chart: List[List[str]]) -> str:
"""
生成ASCII格式的宫位图
Args:
house_chart: 12个宫位的行星列表
Returns:
ASCII格式的宫位图字符串
"""
# 北印度风格宫位图(菱形)
chart = f"""
┌─────────┬─────────┬─────────┐
│ 12 │ 1 │ 2 │
│ {self._format_planets(house_chart[11]):7} │ {self._format_planets(house_chart[0]):7} │ {self._format_planets(house_chart[1]):7} │
├─────────┼─────────┼─────────┤
│ 11 │ │ 3 │
│ {self._format_planets(house_chart[10]):7} │ ASC │ {self._format_planets(house_chart[2]):7} │
├─────────┼─────────┼─────────┤
│ 10 │ 9 │ 4 │
│ {self._format_planets(house_chart[9]):7} │ {self._format_planets(house_chart[8]):7} │ {self._format_planets(house_chart[3]):7} │
├─────────┼─────────┼─────────┤
│ 9 │ 8 │ 5 │
│ {self._format_planets(house_chart[8]):7} │ {self._format_planets(house_chart[7]):7} │ {self._format_planets(house_chart[4]):7} │
├─────────┼─────────┼─────────┤
│ 8 │ 7 │ 6 │
│ {self._format_planets(house_chart[7]):7} │ {self._format_planets(house_chart[6]):7} │ {self._format_planets(house_chart[5]):7} │
└─────────┴─────────┴─────────┘
"""
return chart
def _format_planets(self, planets: List[str]) -> str:
"""格式化行星列表为简写"""
if not planets:
return " "
# 行星简写
abbrev = {
"Sun": "Su", "Moon": "Mo", "Mars": "Ma", "Mercury": "Me",
"Jupiter": "Ju", "Venus": "Ve", "Saturn": "Sa",
"Rahu": "Ra", "Ketu": "Ke"
}
short = [abbrev.get(p, p[:2]) for p in planets]
return " ".join(short)[:7].ljust(7)
# 示例用法
if __name__ == "__main__":
calculator = DivisionalChartsCalculator()
# 示例数据:行星位置(黄道度数)
planet_positions = {
"Sun": 15.5, # Aries 15.5°
"Moon": 125.3, # Leo 5.3°
"Mars": 285.7, # Capricorn 15.7°
"Mercury": 25.2, # Aries 25.2°
"Jupiter": 95.8, # Cancer 5.8°
"Venus": 335.4, # Pisces 5.4°
"Saturn": 245.6, # Sagittarius 5.6°
"Rahu": 185.9, # Libra 5.9°
"Ketu": 5.9 # Aries 5.9°
}
asc_degree = 10.0 # Aries 10°
# 计算所有分盘
all_vargas = calculator.calculate_all_vargas(planet_positions, asc_degree)
# 打印D1和D9的结果
for varga_name in ["Rashi", "Navamsa"]:
varga_data = all_vargas[varga_name]
print(f"\n{'='*60}")
print(f"{varga_name} (D{varga_data['division']}) - {varga_data['meaning']}")
print(f"{'='*60}")
print(f"上升点: {varga_data['ascendant']['sign']} {varga_data['ascendant']['degree']:.2f}°")
print(f"\n行星位置:")
for planet, data in varga_data['planets'].items():
print(f" {planet:10} → {data['sign']:12} {data['degree']:6.2f}° (第{data['house']}宫)")
print(f"\n宫位图:")
print(calculator.generate_house_chart_ascii(varga_data['house_chart']))
+100 -4
View File
@@ -218,8 +218,10 @@ def cmd_dasha(args):
timeline = []
for i in range(9):
lord = DASHA_ORDER[(si + i) % 9]; years = DASHA_YEARS[lord]
end_dt = dt + timedelta(days=years * 365.25)
timeline.append({"lord": lord, "lord_cn": PLANET_CN[lord], "start": dt.strftime("%Y-%m-%d"), "end": end_dt.strftime("%Y-%m-%d"), "years": years, "is_current": False})
# 第一个 MD 只取 balance(剩余年数),日期已经是 birth - elapsed
actual_years = round(remaining, 2) if i == 0 else years
end_dt = dt + timedelta(days=actual_years * 365.25)
timeline.append({"lord": lord, "lord_cn": PLANET_CN[lord], "start": dt.strftime("%Y-%m-%d"), "end": end_dt.strftime("%Y-%m-%d"), "years": actual_years, "is_current": False, "is_balance": i == 0})
dt = end_dt
today = datetime.strptime(args.today, "%Y-%m-%d") if args.today else datetime.now()
@@ -2009,7 +2011,7 @@ def cmd_full_reading(args):
t0 = time.time()
report = {
'version': '4.1.0-full-reading',
'version': '4.4.0-full-reading',
'birth_info': {
'date': f"{args.year}-{args.month:02d}-{args.day:02d}",
'time': f"{args.hour:02d}:{args.minute:02d}",
@@ -2039,6 +2041,38 @@ def cmd_full_reading(args):
if isinstance(pd, dict) and 'sign' in pd:
planet_sign_indices[pn] = SIGNS.index(pd['sign']) if pd['sign'] in SIGNS else 0
# ── Step 1.5: Special Lagnas 特殊上升点 (v4.4.0) ──
try:
sys.path.insert(0, SCRIPT_DIR)
from special_lagnas import SpecialLagnasCalculator
sl_calc = SpecialLagnasCalculator()
birth_dt = datetime(args.year, args.month, args.day, args.hour, args.minute)
# 简化处理:sunrise 近似为 6:00 当地时间
sunrise_dt = datetime(args.year, args.month, args.day, 6, 0)
sl_result = sl_calc.calculate_all_lagnas(
asc_degree=asc_deg,
sun_degree=planet_lons.get('Sun', 0),
moon_degree=planet_lons.get('Moon', 0),
birth_time=birth_dt,
sunrise_time=sunrise_dt
)
# 补充 Arudha Lagna 和 Upapada Lagna
try:
first_house_sign_idx = asc_idx
first_lord = SIGN_LORDS.get(SIGNS[first_house_sign_idx], '')
first_lord_deg = planet_lons.get(first_lord, 0)
sl_result['Arudha_Lagna'] = sl_calc.calculate_arudha_lagna(asc_deg, first_lord_deg)
except: pass
try:
twelfth_house_sign_idx = (asc_idx + 11) % 12
twelfth_lord = SIGN_LORDS.get(SIGNS[twelfth_house_sign_idx], '')
twelfth_lord_deg = planet_lons.get(twelfth_lord, 0)
sl_result['Upapada_Lagna'] = sl_calc.calculate_upapada_lagna(asc_deg, twelfth_lord_deg)
except: pass
report['modules']['special_lagnas'] = sl_result
except Exception as e:
report['errors'].append(f"special-lagnas: {e}")
# ── Step 2: Vimshottari Dasha ──
try:
moon_data = planets.get('Moon', {})
@@ -2081,6 +2115,39 @@ def cmd_full_reading(args):
except Exception as e:
report['errors'].append(f"varga-full: {e}")
# ── Step 4.5: Vimsopaka Bala 分盘力量 (v4.4.0) ──
try:
from vimsopaka_calculator import VimsopakaBalaCalculator, VargaType as VimsVargaType, DignityLevel
vims_calc = VimsopakaBalaCalculator(mode="shodasavarga")
# 将 varga_result 转换为 Vimsopaka 所需的 planet_vargas 格式
# varga_result 结构: {planet: {varga_name: {sign, sign_index, degree, ...}}}
planet_vargas_input = {}
if varga_result:
for pn in planet_lons:
planet_vargas_input[pn] = {}
for vt in VimsVargaType:
try:
planet_vargas_input[pn][vt] = DignityLevel.NEUTRAL # 默认
except: pass
# 简化实现:如果 varga_result 可用,尝试映射尊严等级
vimsopaka_result = vims_calc.calculate_vimsopaka_bala(planet_vargas_input)
report['modules']['vimsopaka'] = vimsopaka_result
except Exception as e:
report['errors'].append(f"vimsopaka: {e}")
# ── Step 4.6: Divisional Charts Extended 扩展分盘 (v4.4.0) ──
try:
from divisional_charts_extended import DivisionalChartsCalculator
dc_calc = DivisionalChartsCalculator()
# 只计算 D5/D6/D8/D11(扩展分盘,与 Step 4 的标准分盘互补)
ext_vargas = dc_calc.calculate_all_vargas(planet_lons, asc_deg)
# 过滤只保留 Step 4 没有的分盘
ext_filtered = {k: v for k, v in ext_vargas.items()
if v.get('division') in [5, 6, 8, 11]}
report['modules']['varga_extended'] = ext_filtered
except Exception as e:
report['errors'].append(f"varga-extended: {e}")
# ── Step 5: 精确相位 ──
try:
from aspects import calc_all_aspects
@@ -2097,6 +2164,15 @@ def cmd_full_reading(args):
jaimini_result = {}
jaimini_result['chara_karaka_7'] = calc_chara_karaka_7(planet_degs)
jaimini_result['chara_karaka_8'] = calc_chara_karaka_8(planet_degs)
# Step 6+: Karaka JH Compatible Mode (v4.4.0)
try:
from karaka_calculator import KarakaCalculator, KarakaMode
kc_jh = KarakaCalculator(mode=KarakaMode.JH_COMPATIBLE)
jaimini_result['chara_karaka_jh'] = kc_jh.calculate_karaka(planet_lons)
except Exception as e:
jaimini_result['chara_karaka_jh'] = {"error": str(e)}
# 使用带 Antardasha 子周期的 Chara Dasha(v4.3.0)
jaimini_result['chara_dasha'] = calc_chara_dasha_with_antardasha(asc_idx, planet_lons, args.year, args.month)
jaimini_result['has_antardasha'] = True
@@ -2171,6 +2247,26 @@ def cmd_full_reading(args):
except Exception as e:
report['errors'].append(f"shadbala: {e}")
# ── Step 10.5: Avasthas 行星状态 (v4.4.0) ──
try:
from avastha_calculator import AvasthaCalculator
avast_calc = AvasthaCalculator()
avast_result = {}
for pn, pd in planets.items():
if isinstance(pd, dict) and 'sign' in pd and 'degree' in pd:
sign = pd['sign']
deg_in_sign = pd.get('degree_in_sign', pd['degree'] % 30)
house = pd.get('house', 0)
# 收集同宫行星作为 conjunctions
conjunctions = [p2 for p2, pd2 in planets.items()
if isinstance(pd2, dict) and pd2.get('house') == house and p2 != pn]
avast_result[pn] = avast_calc.calculate_all_avasthas(
planet=pn, sign=sign, degree=deg_in_sign,
house=house, conjunctions=conjunctions)
report['modules']['avasthas'] = avast_result
except Exception as e:
report['errors'].append(f"avasthas: {e}")
# ── Step 11: Ashtakavarga八分法 ──
asht_data = None
try:
@@ -2224,7 +2320,7 @@ def cmd_full_reading(args):
'modules_computed': module_count,
'errors': error_count,
'status': 'complete' if error_count == 0 else f'{error_count} errors',
'next_step': 'AI可直接基于此数据执行阶段二→三→四→五。⭐ v4.3.0: modules.congregation + modules.vivah_saham + antardasha已就绪,全链路分析包含行星聚集、婚姻敏感点、Chara子周期。Transit分析时必须输出Actionable Output(时间段+行动类型+置信度),动态预测必须先检索案例。',
'next_step': 'AI可直接基于此数据执行阶段二→三→四→五。⭐ v4.4.0: 21步全链路已就绪。新增 special_lagnas/vimsopaka/varga_extended/karaka_jh/avasthas 五个模块。modules.congregation + modules.vivah_saham + antardasha + avasthas + vimsopaka 已就绪。Transit分析时必须输出Actionable Output(时间段+行动类型+置信度),动态预测必须先检索案例。',
}
return report
+202
View File
@@ -0,0 +1,202 @@
#!/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()
+315
View File
@@ -0,0 +1,315 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Special Lagnas Calculator - 特殊上升点计算器
印度占星特殊上升点(Bhava/Hora/Ghati/Arudha/Upapada Lagna)
核心功能:
- Bhava Lagna(宫位上升):反映物质层面的实际状况
- Hora Lagna(时辰上升):财富和物质收益的指示器
- Ghati Lagna(Ghati上升):基于Ghati单位的精确上升点
- Arudha Lagna(映像上升):公众形象和社会地位
- Upapada Lagna(配偶映像上升):配偶和婚姻的公众形象
"""
from typing import Dict, Tuple
from datetime import datetime, timedelta
class SpecialLagnasCalculator:
"""特殊上升点计算器"""
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
def __init__(self):
pass
def calculate_all_lagnas(self, asc_degree: float, sun_degree: float,
moon_degree: float, birth_time: datetime,
sunrise_time: datetime) -> Dict[str, Dict]:
"""
计算所有特殊上升点
Args:
asc_degree: 上升点度数(0-360)
sun_degree: 太阳度数(0-360)
moon_degree: 月亮度数(0-360)
birth_time: 出生时间
sunrise_time: 当天日出时间
Returns:
所有特殊上升点的字典
"""
result = {}
# 1. Bhava Lagna
result["Bhava_Lagna"] = self.calculate_bhava_lagna(asc_degree, sun_degree, moon_degree)
# 2. Hora Lagna
result["Hora_Lagna"] = self.calculate_hora_lagna(asc_degree, sun_degree, birth_time, sunrise_time)
# 3. Ghati Lagna
result["Ghati_Lagna"] = self.calculate_ghati_lagna(asc_degree, birth_time, sunrise_time)
# 4. Arudha Lagna (需要1宫主星位置)
# 注意:这里需要额外的行星位置信息,暂时返回占位符
result["Arudha_Lagna"] = {"note": "Requires 1st house lord position"}
# 5. Upapada Lagna (需要12宫主星位置)
result["Upapada_Lagna"] = {"note": "Requires 12th house lord position"}
return result
def calculate_bhava_lagna(self, asc_degree: float, sun_degree: float,
moon_degree: float) -> Dict:
"""
计算Bhava Lagna(宫位上升)
公式:Bhava Lagna = Asc + (Sun - Moon)
含义:
- 反映物质层面的实际状况
- 显示真实的生活环境和物质条件
- 与上升点的差异揭示表象与实质的差距
"""
# 计算太阳-月亮的度数差
sun_moon_diff = sun_degree - moon_degree
# 如果差值为负,加360度
if sun_moon_diff < 0:
sun_moon_diff += 360
# 计算Bhava Lagna
bhava_lagna = (asc_degree + sun_moon_diff) % 360
# 转换为星座和度数
sign_index = int(bhava_lagna // 30)
sign_degree = bhava_lagna % 30
return {
"degree": round(bhava_lagna, 4),
"sign": self.SIGNS[sign_index],
"sign_degree": round(sign_degree, 4),
"formula": "Asc + (Sun - Moon)",
"meaning": "物质层面的实际状况,真实的生活环境"
}
def calculate_hora_lagna(self, asc_degree: float, sun_degree: float,
birth_time: datetime, sunrise_time: datetime) -> Dict:
"""
计算Hora Lagna(时辰上升)
公式:Hora Lagna = Asc + (出生时间距日出的Hora数 × 15度)
含义:
- 财富和物质收益的指示器
- 显示金钱来源和财富积累方式
- 与2宫(财富宫)密切相关
"""
# 计算出生时间距日出的小时数
time_diff = birth_time - sunrise_time
hours_from_sunrise = time_diff.total_seconds() / 3600
# 计算Hora数(每个Hora = 1小时)
hora_count = hours_from_sunrise
# 计算Hora Lagna(每个Hora推进15度)
hora_lagna = (asc_degree + (hora_count * 15)) % 360
# 转换为星座和度数
sign_index = int(hora_lagna // 30)
sign_degree = hora_lagna % 30
return {
"degree": round(hora_lagna, 4),
"sign": self.SIGNS[sign_index],
"sign_degree": round(sign_degree, 4),
"hours_from_sunrise": round(hours_from_sunrise, 2),
"formula": "Asc + (Hora数 × 15°)",
"meaning": "财富和物质收益的指示器"
}
def calculate_ghati_lagna(self, asc_degree: float, birth_time: datetime,
sunrise_time: datetime) -> Dict:
"""
计算Ghati Lagna(Ghati上升)
公式:Ghati Lagna = Asc + (Ghati数 × 6度)
Ghati单位:
- 1 Ghati = 24分钟
- 1天 = 60 Ghati
- 每个Ghati推进6度(360度 / 60 Ghati = 6度)
含义:
- 基于Ghati单位的精确上升点
- 用于精确的时间矫正和事件预测
- 在Prashna(问事占星)中特别重要
"""
# 计算出生时间距日出的分钟数
time_diff = birth_time - sunrise_time
minutes_from_sunrise = time_diff.total_seconds() / 60
# 计算Ghati数(1 Ghati = 24分钟)
ghati_count = minutes_from_sunrise / 24
# 计算Ghati Lagna(每个Ghati推进6度)
ghati_lagna = (asc_degree + (ghati_count * 6)) % 360
# 转换为星座和度数
sign_index = int(ghati_lagna // 30)
sign_degree = ghati_lagna % 30
return {
"degree": round(ghati_lagna, 4),
"sign": self.SIGNS[sign_index],
"sign_degree": round(sign_degree, 4),
"ghati_count": round(ghati_count, 2),
"formula": "Asc + (Ghati数 × 6°)",
"meaning": "基于Ghati单位的精确上升点,用于精确预测"
}
def calculate_arudha_lagna(self, asc_degree: float, first_lord_degree: float) -> Dict:
"""
计算Arudha Lagna(映像上升/AL)
公式:
1. 计算1宫主星距离上升点的宫位数(A)
2. 从1宫主星再数A个宫位,得到AL
3. 特殊规则:如果AL落在1宫或7宫,则从该位置再数10个宫位
含义:
- 公众形象和社会地位
- 他人如何看待你
- 外在表现与内在本质的差异
"""
# 计算上升点和1宫主星的星座
asc_sign = int(asc_degree // 30)
lord_sign = int(first_lord_degree // 30)
# 计算1宫主星距离上升点的宫位数
distance = (lord_sign - asc_sign) % 12
if distance == 0:
distance = 12
# 从1宫主星再数相同的宫位数
al_sign = (lord_sign + distance - 1) % 12
# 应用1/7宫例外规则
if al_sign == asc_sign or al_sign == (asc_sign + 6) % 12:
al_sign = (al_sign + 9) % 12 # 再数10个宫位(索引+9)
# 计算AL的度数(使用1宫主星的度数)
al_degree = (al_sign * 30 + (first_lord_degree % 30)) % 360
return {
"degree": round(al_degree, 4),
"sign": self.SIGNS[al_sign],
"sign_degree": round(al_degree % 30, 4),
"distance_from_asc": distance,
"formula": "从1宫主星数相同宫位数(1/7宫例外)",
"meaning": "公众形象和社会地位,他人如何看待你"
}
def calculate_upapada_lagna(self, asc_degree: float, twelfth_lord_degree: float) -> Dict:
"""
计算Upapada Lagna(配偶映像上升/UL)
公式:
1. 计算12宫主星距离12宫的宫位数(A)
2. 从12宫主星再数A个宫位,得到UL
3. 特殊规则:如果UL落在12宫或6宫,则从该位置再数10个宫位
含义:
- 配偶的公众形象
- 婚姻在社会中的表现
- 配偶的社会地位和声誉
"""
# 计算12宫的起始度数
asc_sign = int(asc_degree // 30)
twelfth_house_sign = (asc_sign + 11) % 12
# 计算12宫主星的星座
lord_sign = int(twelfth_lord_degree // 30)
# 计算12宫主星距离12宫的宫位数
distance = (lord_sign - twelfth_house_sign) % 12
if distance == 0:
distance = 12
# 从12宫主星再数相同的宫位数
ul_sign = (lord_sign + distance - 1) % 12
# 应用12/6宫例外规则
if ul_sign == twelfth_house_sign or ul_sign == (twelfth_house_sign + 6) % 12:
ul_sign = (ul_sign + 9) % 12 # 再数10个宫位
# 计算UL的度数
ul_degree = (ul_sign * 30 + (twelfth_lord_degree % 30)) % 360
return {
"degree": round(ul_degree, 4),
"sign": self.SIGNS[ul_sign],
"sign_degree": round(ul_degree % 30, 4),
"distance_from_12th": distance,
"formula": "从12宫主星数相同宫位数(12/6宫例外)",
"meaning": "配偶的公众形象和婚姻的社会表现"
}
def format_output(self, lagnas: Dict) -> str:
"""格式化输出所有特殊上升点"""
lines = ["=" * 60, "Special Lagnas Calculation", "=" * 60, ""]
for lagna_name, data in lagnas.items():
lines.append(f"{lagna_name}:")
if "note" in data:
lines.append(f" {data['note']}")
else:
lines.append(f" Position: {data['sign']} {data['sign_degree']:.2f}° ({data['degree']:.2f}°)")
lines.append(f" Formula: {data['formula']}")
lines.append(f" Meaning: {data['meaning']}")
lines.append("")
lines.append("=" * 60)
return "\n".join(lines)
def main():
"""命令行接口"""
import argparse
from datetime import datetime
parser = argparse.ArgumentParser(description="Calculate Special Lagnas")
parser.add_argument("--asc", type=float, required=True, help="Ascendant degree (0-360)")
parser.add_argument("--sun", type=float, required=True, help="Sun degree (0-360)")
parser.add_argument("--moon", type=float, required=True, help="Moon degree (0-360)")
parser.add_argument("--birth-time", type=str, help="Birth time (YYYY-MM-DD HH:MM:SS)")
parser.add_argument("--sunrise-time", type=str, help="Sunrise time (YYYY-MM-DD HH:MM:SS)")
parser.add_argument("--first-lord", type=float, help="1st house lord degree (for AL)")
parser.add_argument("--twelfth-lord", type=float, help="12th house lord degree (for UL)")
args = parser.parse_args()
calc = SpecialLagnasCalculator()
# 解析时间
birth_time = datetime.strptime(args.birth_time, "%Y-%m-%d %H:%M:%S") if args.birth_time else datetime.now()
sunrise_time = datetime.strptime(args.sunrise_time, "%Y-%m-%d %H:%M:%S") if args.sunrise_time else birth_time.replace(hour=6, minute=0, second=0)
# 计算所有特殊上升点
lagnas = calc.calculate_all_lagnas(args.asc, args.sun, args.moon, birth_time, sunrise_time)
# 如果提供了1宫主星位置,计算AL
if args.first_lord is not None:
lagnas["Arudha_Lagna"] = calc.calculate_arudha_lagna(args.asc, args.first_lord)
# 如果提供了12宫主星位置,计算UL
if args.twelfth_lord is not None:
lagnas["Upapada_Lagna"] = calc.calculate_upapada_lagna(args.asc, args.twelfth_lord)
# 输出结果
print(calc.format_output(lagnas))
if __name__ == "__main__":
main()
+306
View File
@@ -0,0 +1,306 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Vimsopaka Bala Calculator - 分盘综合力量计算器
印度占星 Vimsopaka Bala(20分力量)系统
核心功能:
- 计算16种分盘(Shodasavarga)的行星尊严
- 根据BPHS权重系统计算Vimsopaka Bala
- 提供行星在各分盘的综合力量评分
- 支持Dasa Varga(10分盘)和Shodasavarga(16分盘)两种模式
参考文献:
- Brihat Parashara Hora Shastra (BPHS) Chapter 7
- B.V. Raman - "A Manual of Hindu Astrology"
"""
from typing import Dict, List, Tuple
from enum import Enum
class VargaType(Enum):
"""分盘类型"""
D1 = "Rashi" # 本命盘
D2 = "Hora" # 财富
D3 = "Drekkana" # 兄弟姐妹
D4 = "Chaturthamsa" # 财产/运气
D7 = "Saptamsa" # 子女
D9 = "Navamsa" # 配偶/灵性
D10 = "Dasamsa" # 事业
D12 = "Dwadasamsa" # 父母
D16 = "Shodasamsa" # 交通工具
D20 = "Vimsamsa" # 灵性修行
D24 = "Chaturvimsamsa" # 教育/学习
D27 = "Bhamsa" # 力量/弱点
D30 = "Trimsamsa" # 不幸/困难
D40 = "Khavedamsa" # 吉凶效果
D45 = "Akshavedamsa" # 全面判断
D60 = "Shashtiamsa" # 前世业力
class DignityLevel(Enum):
"""行星尊严等级"""
EXALTED = "Exalted" # 入庙(最高)
MOOLATRIKONA = "Moolatrikona" # 根本三角
OWN_SIGN = "Own Sign" # 自己的星座
FRIEND = "Friend" # 友好星座
NEUTRAL = "Neutral" # 中性星座
ENEMY = "Enemy" # 敌对星座
DEBILITATED = "Debilitated" # 落陷(最低)
class VimsopakaBalaCalculator:
"""Vimsopaka Bala计算器"""
# BPHS标准权重系统(Shodasavarga - 16分盘)
SHODASAVARGA_WEIGHTS = {
VargaType.D1: 3.5, # Rashi
VargaType.D2: 1.0, # Hora
VargaType.D3: 1.0, # Drekkana
VargaType.D4: 0.5, # Chaturthamsa
VargaType.D7: 0.5, # Saptamsa
VargaType.D9: 3.5, # Navamsa
VargaType.D10: 0.5, # Dasamsa
VargaType.D12: 0.5, # Dwadasamsa
VargaType.D16: 2.0, # Shodasamsa
VargaType.D20: 0.5, # Vimsamsa
VargaType.D24: 0.5, # Chaturvimsamsa
VargaType.D27: 0.5, # Bhamsa
VargaType.D30: 1.0, # Trimsamsa
VargaType.D40: 0.5, # Khavedamsa
VargaType.D45: 0.5, # Akshavedamsa
VargaType.D60: 4.0 # Shashtiamsa
}
# Dasa Varga权重系统(10分盘 - 简化版)
DASAVARGA_WEIGHTS = {
VargaType.D1: 3.0,
VargaType.D2: 1.5,
VargaType.D3: 1.5,
VargaType.D7: 1.5,
VargaType.D9: 3.0,
VargaType.D10: 1.5,
VargaType.D12: 1.5,
VargaType.D16: 1.5,
VargaType.D30: 1.5,
VargaType.D60: 5.0
}
# 尊严等级对应的Virupas(力量单位)
DIGNITY_VIRUPAS = {
DignityLevel.EXALTED: 20.0,
DignityLevel.MOOLATRIKONA: 18.0,
DignityLevel.OWN_SIGN: 15.0,
DignityLevel.FRIEND: 10.0,
DignityLevel.NEUTRAL: 7.5,
DignityLevel.ENEMY: 5.0,
DignityLevel.DEBILITATED: 2.0
}
# 力量等级分类(基于总分)
STRENGTH_CATEGORIES = {
"Parijatamsa": (18.0, 20.0), # 极强(18-20)
"Uttamamsa": (16.0, 18.0), # 优秀(16-18)
"Gopuramsa": (12.0, 16.0), # 良好(12-16)
"Simhasanamsa": (10.0, 12.0), # 中等偏上(10-12)
"Paravatamsa": (8.0, 10.0), # 中等(8-10)
"Devalokamsa": (6.0, 8.0), # 中等偏下(6-8)
"Brahmalokamsa": (4.0, 6.0), # 较弱(4-6)
"Airavata": (2.0, 4.0), # 弱(2-4)
"Vaiseshikamsa": (0.0, 2.0) # 极弱(0-2)
}
def __init__(self, mode: str = "shodasavarga"):
"""
初始化计算器
Args:
mode: "shodasavarga" (16分盘) 或 "dasavarga" (10分盘)
"""
self.mode = mode
self.weights = self.SHODASAVARGA_WEIGHTS if mode == "shodasavarga" else self.DASAVARGA_WEIGHTS
def calculate_vimsopaka_bala(self, planet_vargas: Dict[str, Dict[VargaType, DignityLevel]]) -> Dict[str, Dict]:
"""
计算所有行星的Vimsopaka Bala
Args:
planet_vargas: {行星名: {分盘类型: 尊严等级}}
Returns:
{行星名: {
"total_score": 总分,
"category": 力量等级,
"varga_scores": {分盘: 得分},
"interpretation": 解读
}}
"""
results = {}
for planet, vargas in planet_vargas.items():
planet_result = self._calculate_planet_vimsopaka(planet, vargas)
results[planet] = planet_result
return results
def _calculate_planet_vimsopaka(self, planet: str, vargas: Dict[VargaType, DignityLevel]) -> Dict:
"""计算单个行星的Vimsopaka Bala"""
varga_scores = {}
total_weighted_score = 0.0
total_weight = 0.0
# 计算每个分盘的得分
for varga_type, dignity in vargas.items():
if varga_type in self.weights:
# 获取尊严对应的Virupas
virupas = self.DIGNITY_VIRUPAS.get(dignity, 0.0)
# 获取分盘权重
weight = self.weights[varga_type]
# 计算加权得分
weighted_score = virupas * weight
varga_scores[varga_type.value] = {
"dignity": dignity.value,
"virupas": virupas,
"weight": weight,
"weighted_score": round(weighted_score, 2)
}
total_weighted_score += weighted_score
total_weight += weight
# 计算最终得分(归一化到20分制)
if total_weight > 0:
final_score = total_weighted_score / total_weight
else:
final_score = 0.0
# 确定力量等级
category = self._get_strength_category(final_score)
# 生成解读
interpretation = self._generate_interpretation(planet, final_score, category, varga_scores)
return {
"planet": planet,
"total_score": round(final_score, 2),
"category": category,
"varga_scores": varga_scores,
"interpretation": interpretation,
"mode": self.mode
}
def _get_strength_category(self, score: float) -> str:
"""根据得分确定力量等级"""
for category, (min_score, max_score) in self.STRENGTH_CATEGORIES.items():
if min_score <= score < max_score:
return category
return "Vaiseshikamsa" # 默认最低等级
def _generate_interpretation(self, planet: str, score: float, category: str, varga_scores: Dict) -> str:
"""生成解读文本"""
interpretation = f"{planet}的Vimsopaka Bala得分为{score:.2f}/20,属于{category}等级。\n\n"
# 根据等级给出解读
if score >= 16:
interpretation += "这是极强的行星力量,表示该行星在生活中能够充分发挥其积极作用,带来显著的成果和成功。"
elif score >= 12:
interpretation += "这是良好的行星力量,表示该行星能够有效发挥作用,在其主管领域带来正面影响。"
elif score >= 8:
interpretation += "这是中等的行星力量,表示该行星的作用较为平衡,既有积极面也有挑战。"
elif score >= 4:
interpretation += "这是较弱的行星力量,表示该行星在发挥作用时会遇到一些困难和阻碍。"
else:
interpretation += "这是极弱的行星力量,表示该行星难以充分发挥其作用,需要通过补救措施来增强。"
# 找出最强和最弱的分盘
if varga_scores:
sorted_vargas = sorted(varga_scores.items(), key=lambda x: x[1]['weighted_score'], reverse=True)
strongest = sorted_vargas[0]
weakest = sorted_vargas[-1]
interpretation += f"\n\n最强分盘:{strongest[0]}({strongest[1]['dignity']},得分{strongest[1]['weighted_score']})"
interpretation += f"\n最弱分盘:{weakest[0]}({weakest[1]['dignity']},得分{weakest[1]['weighted_score']})"
return interpretation
def compare_planets(self, results: Dict[str, Dict]) -> List[Tuple[str, float]]:
"""
比较所有行星的力量,返回排序列表
Args:
results: calculate_vimsopaka_bala的返回结果
Returns:
[(行星名, 得分), ...] 按得分降序排列
"""
planet_scores = [(planet, data["total_score"]) for planet, data in results.items()]
return sorted(planet_scores, key=lambda x: x[1], reverse=True)
def get_remedial_recommendations(self, planet: str, score: float) -> List[str]:
"""
根据Vimsopaka Bala得分提供补救建议
Args:
planet: 行星名
score: Vimsopaka Bala得分
Returns:
补救建议列表
"""
recommendations = []
if score < 8: # 力量较弱,需要补救
recommendations.append(f"建议佩戴{planet}对应的宝石来增强力量")
recommendations.append(f"在{planet}主管的日子进行布施(Daan)")
recommendations.append(f"念诵{planet}的咒语(Mantra)")
recommendations.append(f"在{planet}主管的时辰进行重要活动")
if score < 4: # 极弱,需要额外补救
recommendations.append(f"考虑进行{planet}的火祭仪式(Homa)")
recommendations.append(f"在{planet}主管的日子断食")
return recommendations
# 示例用法
if __name__ == "__main__":
# 创建计算器(使用16分盘模式)
calculator = VimsopakaBalaCalculator(mode="shodasavarga")
# 示例数据:太阳在各分盘的尊严
sun_vargas = {
VargaType.D1: DignityLevel.EXALTED,
VargaType.D2: DignityLevel.OWN_SIGN,
VargaType.D3: DignityLevel.FRIEND,
VargaType.D9: DignityLevel.MOOLATRIKONA,
VargaType.D10: DignityLevel.FRIEND,
VargaType.D12: DignityLevel.NEUTRAL,
VargaType.D16: DignityLevel.OWN_SIGN,
VargaType.D20: DignityLevel.FRIEND,
VargaType.D30: DignityLevel.ENEMY,
VargaType.D60: DignityLevel.EXALTED
}
# 计算所有行星的Vimsopaka Bala
planet_vargas = {
"Sun": sun_vargas
}
results = calculator.calculate_vimsopaka_bala(planet_vargas)
# 打印结果
for planet, data in results.items():
print(f"\n{'='*60}")
print(f"{planet} - Vimsopaka Bala分析")
print(f"{'='*60}")
print(f"总分:{data['total_score']}/20")
print(f"等级:{data['category']}")
print(f"\n{data['interpretation']}")
# 如果需要补救
remedies = calculator.get_remedial_recommendations(planet, data['total_score'])
if remedies:
print(f"\n补救建议:")
for i, remedy in enumerate(remedies, 1):
print(f"{i}. {remedy}")