## Registry System: Position-Based Card Details ### Overview The registry uses a **position-based lookup system** that maps card positions (1-78) to interpretive data stored in `CardDetailsRegistry`. This system is independent of card names, allowing the same registry entries to work across different deck variants. ### Design Principle **Card position is the permanent identifier**, not the card name. This means: - Card #44 is always "Magus position" in the deck order - If you rename card #44 to "Magus", "Magician", "Mage", or any other variant, it still maps to the same registry entry - Different deck variants can have completely different names but use the same spiritual/interpretive data ### File Organization Your deck files follow this numbering (which drives card position): - **1-14**: Cups (Ace, Ten, 2-9, Knight, Prince, Princess, Queen) - **15-28**: Pentacles/Disks (same structure) - **29-42**: Swords (same structure) - **43-64**: Major Arcana (43=Fool, 44=Magus, ..., 64=Universe) - **65-78**: Wands (same structure) Example: `44_Magus.webp` → Card at position 44 → Magus name → Registry position 44 → Details for position 44 ### Position-Based Lookup Process ``` Card created with number (position) ↓ card.number = 44 ↓ load_into_card(card) ↓ get_by_position(44) ↓ Position 44 maps to registry key "I" (1st trump after Fool) ↓ registry.get("I") → Returns Magician/Magus details ↓ Details loaded into card object (independent of card.name) ``` ### Position Mapping **Minor Arcana Positions:** - 1-14: Cups - Maps to "Ace of Cups" through "Queen of Cups" - 15-28: Pentacles - Maps to "Ace of Pentacles" through "Queen of Pentacles" - 29-42: Swords - Maps to "Ace of Swords" through "Queen of Swords" - 65-78: Wands - Maps to "Ace of Wands" through "Queen of Wands" **Major Arcana Positions:** - 43 → "o" (Roman for 0/Fool) - 44 → "I" (Roman for 1/Magus) - 45 → "II" (Roman for 2) - ...continuing through... - 64 → "XXI" (Roman for 21/Universe) ### Implementation ```python def _build_position_map(self) -> Dict[int, str]: """ Maps card position (1-78) to registry key: - Minor Arcana: position → card name ("Ace of Cups", etc.) - Major Arcana: position → Roman numeral ("o", "I", "II", etc.) """ # Builds complete 1-78 mapping return position_map def get_by_position(self, position: int) -> Optional[Dict[str, Any]]: """Get details for a card by its position (1-78).""" registry_key = self._position_map.get(position) return self._details.get(registry_key) def load_into_card(self, card: 'Card') -> bool: """Load card details using position-based lookup.""" details = self.get_by_position(card.number) # Populate card with: explanation, interpretation, keywords, etc. ``` ### Why Position-Based? 1. **Deck Variant Independence**: Different decks can use completely different names 2. **Stable Identity**: Card position never changes across variants 3. **Scalable**: Easily support new deck variants by just changing card names 4. **Future Proof**: New interpretations can be added keyed to positions, not names ### Example Flow File: `44_Magus.webp` ↓ Card object: number=44, name="Magus", arcana="Major" ↓ `load_into_card(card)` called ↓ `get_by_position(44)` returns registry key "I" ↓ Registry lookup: `registry.get("I")` ↓ Populates card with Magician/Magus interpretation: - keywords: ["manifestation", "resourcefulness", ...] - interpretation: "Communication; Conscious Will; ..." - guidance: "Focus your energy and intention..." ### Key Point Even if you rename card #44 to something completely different, it will still load the same interpretation because the lookup is based on **position (44)**, not **name ("Magus")**. ↓ Registry lookup: `registry.get("o")` ↓ Populates card with: explanation, interpretation, keywords, etc.