4c0f5f2b26
- engine/lots.py: formuła Lot = C + A − B z odwracaniem w horoskopach nocnych (zamiana A<->B); 7 Lots hermetycznych (Fortuna, Duch, Eros, Konieczność, Odwaga, Zwycięstwo, Nemezis) — Fortuna i Duch liczone pierwsze, bo pozostałe się do nich odwołują. Dwa warianty: degree (domyślny) i sign (całe znaki). - build_chart: liczy sektę (reużyta is_day_birth z Firdarii) i zwraca lots ze znakiem, pozycją i domem; parametr lots_method. - wyszukiwarka: token [PF (tak Fortuna występuje w realnej bazie) + rozwinięcie skrótu do "Part of Fortune". - widok Horoskop: tabela Lots z formułami i sektą. Walidacja (dwie niezależne wyrocznie z notes3): - Fortuna = Can 12°35'27" vs astro-seek Can 12°35'24" (3 sekundy różnicy), dom 1; - Duch potwierdzony przez swoją antyscję (Taurus 28°14' z tabeli antyscji); - odwracanie nocne: Fortuna nocna == Duch dzienny i odwrotnie; - Lots pochodne faktycznie używają Fortuny/Ducha; wariant sign trafia w 0° znaku. 85 testów przechodzi (nowy test_lots). Odblokowuje Zodiacal Releasing (LOG-11), które startuje z Fortuny/Ducha. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
2.5 KiB
Python
72 lines
2.5 KiB
Python
"""Lots / punkty arabskie (LOG-08).
|
||
|
||
Wyrocznie z notes3 (astro-seek, horoskop referencyjny 30.04.1984, urodzenie DZIENNE):
|
||
- Fortuna wprost w tabeli obiektów: Cancer 12°35'24" = 102.5900°
|
||
- Ducha (Spirit) potwierdza jego antyscja: Taurus 28°14' -> Spirit = 180 − 58.2333
|
||
"""
|
||
import pytest
|
||
|
||
from app.engine.formats import sign_index
|
||
from app.engine.lots import LOT_DEFS, compute_lots
|
||
|
||
# natalne długości horoskopu referencyjnego
|
||
NATAL = {"Asc": 112.1786, "Sun": 40.1392, "Moon": 30.5514, "Mercury": 27.3839,
|
||
"Venus": 27.6769, "Mars": 234.5411, "Jupiter": 282.9617, "Saturn": 223.3108}
|
||
|
||
FORTUNE_REF = 102.5900 # Cancer 12°35'24"
|
||
SPIRIT_REF = 180.0 - 58.2333 # z antyscji Taurus 28°14'
|
||
|
||
|
||
def _by_name(lots):
|
||
return {lot["name"]: lot["longitude"] for lot in lots}
|
||
|
||
|
||
def _arcmin(a, b):
|
||
return abs(((a - b + 180.0) % 360.0) - 180.0) * 60.0
|
||
|
||
|
||
def test_fortune_matches_astroseek():
|
||
lots = _by_name(compute_lots(NATAL, is_day=True))
|
||
assert _arcmin(lots["Fortune"], FORTUNE_REF) < 2.0
|
||
assert sign_index(lots["Fortune"]) == 3 # Cancer
|
||
|
||
|
||
def test_spirit_matches_antiscia_reference():
|
||
lots = _by_name(compute_lots(NATAL, is_day=True))
|
||
assert _arcmin(lots["Spirit"], SPIRIT_REF) < 2.0
|
||
|
||
|
||
def test_fortune_and_spirit_reverse_at_night():
|
||
day = _by_name(compute_lots(NATAL, is_day=True))
|
||
night = _by_name(compute_lots(NATAL, is_day=False))
|
||
# nocą formuła się odwraca: Fortuna nocna = Duch dzienny (i odwrotnie)
|
||
assert _arcmin(night["Fortune"], day["Spirit"]) < 0.01
|
||
assert _arcmin(night["Spirit"], day["Fortune"]) < 0.01
|
||
|
||
|
||
def test_all_seven_hermetic_lots_present():
|
||
lots = compute_lots(NATAL, is_day=True)
|
||
assert [lot["name"] for lot in lots] == [d[0] for d in LOT_DEFS]
|
||
assert len(lots) == 7
|
||
|
||
|
||
def test_derived_lots_use_fortune_and_spirit():
|
||
lots = _by_name(compute_lots(NATAL, is_day=True))
|
||
# Necessity = Asc + Fortune − Mercury
|
||
expected = (NATAL["Asc"] + lots["Fortune"] - NATAL["Mercury"]) % 360.0
|
||
assert _arcmin(lots["Necessity"], expected) < 0.01
|
||
# Eros = Asc + Venus − Spirit
|
||
expected_eros = (NATAL["Asc"] + NATAL["Venus"] - lots["Spirit"]) % 360.0
|
||
assert _arcmin(lots["Eros"], expected_eros) < 0.01
|
||
|
||
|
||
def test_by_sign_method_lands_on_sign_start():
|
||
lots = compute_lots(NATAL, is_day=True, method="sign")
|
||
for lot in lots:
|
||
assert lot["longitude"] % 30.0 == 0.0 # 0° wyliczonego znaku
|
||
|
||
|
||
def test_unknown_method_rejected():
|
||
with pytest.raises(ValueError):
|
||
compute_lots(NATAL, is_day=True, method="bzdura")
|