"""Lots / punkty arabskie (LOG-08) — 7 Lots hermetycznych. Formuła: Lot = C + A − B (od punktu C odmierzamy odległość między A i B). Większość Lots **odwraca się w horoskopach nocnych** (zamiana A↔B) — np. Fortuna: dzień Asc + Mo − Su, noc Asc + Su − Mo. Dwa warianty liczenia (notes3): - `degree` (domyślny) — dokładny stopień, - `sign` — liczone całymi znakami (Lot wypada na 0° wyliczonego znaku). Kolejność ma znaczenie: Fortuna i Duch liczone są pierwsze, bo pozostałe Lots odwołują się do nich. """ from __future__ import annotations from app.engine.formats import norm360, sign_index # (nazwa, C, A, B, odwracalny w nocy) LOT_DEFS: list[tuple[str, str, str, str, bool]] = [ ("Fortune", "Asc", "Moon", "Sun", True), ("Spirit", "Asc", "Sun", "Moon", True), ("Eros", "Asc", "Venus", "Spirit", True), ("Necessity", "Asc", "Fortune", "Mercury", True), ("Courage", "Asc", "Fortune", "Mars", True), ("Victory", "Asc", "Jupiter", "Spirit", True), ("Nemesis", "Asc", "Fortune", "Saturn", True), ] METHODS = ("degree", "sign") def compute_lots( points: dict[str, float], is_day: bool, method: str = "degree" ) -> list[dict]: """points: nazwa → długość natalna (wymagane Asc + planety formuł). Zwraca listę {name, longitude, formula} w kolejności definicji. """ if method not in METHODS: raise ValueError(f"nieznana metoda liczenia Lots: {method}") vals = dict(points) out: list[dict] = [] for name, c, a, b, reversible in LOT_DEFS: first, second = (a, b) if (is_day or not reversible) else (b, a) if any(k not in vals for k in (c, first, second)): continue # brak składnika — pomijamy if method == "sign": idx = (sign_index(vals[c]) + sign_index(vals[first]) - sign_index(vals[second])) % 12 lon = idx * 30.0 else: lon = norm360(vals[c] + vals[first] - vals[second]) vals[name] = lon # dostępny dla kolejnych Lots out.append({ "name": name, "longitude": lon, "formula": f"{c} + {first} − {second}", }) return out