# Technical Specification: MTG Synergy Mapping Engine ## 1. Project Overview The goal is to create a Python-based data pipeline that processes MTG card data from MTGJSON, identifies synergistic relationships between cards, and stores these relationships in a PostgreSQL database. This "Data Map" will power a deck-building assistant that suggests cards based on mechanical and strategic complementarity. ## 2. Tech Stack - **Language:** Python 3.12+ - **Libraries:** `pandas` (data manipulation), `SQLAlchemy` (ORM), `psycopg2` (DB driver), `re` (regex for text processing). - **Database:** PostgreSQL. - **Data Source:** MTGJSON (`AllPrintings.json`, `AllSets.json`). ## 3. Phase 1: Data Ingestion & Normalization The script must flatten the nested MTGJSON structure into a relational format. ### 3.1 Extraction Extract the following fields from `AllPrintings.json`: - `name`, `manaCost`, `types`, `text` (oracle text), `colorIdentity`, `set`. ### 3.2 Text Processing (`TextProcessor` Class) Implement a class to convert raw oracle text into "Functional Tokens." - **Regex Mapping:** Use a dictionary of regex patterns to identify key actions. - *Example:* `"draw a card"` $\rightarrow$ `TOKEN_DRAW_1` - *Example:* `"destroy all creatures"` $\rightarrow$ `TOKEN_BOARD_WIPE_CREATURE` - **Tagging:** Extract subtypes (Tribes) from the `types` field (e.g., "Elf", "Zombie"). ## 4. Phase 2: The Synergy Engine (Logic) The engine must evaluate every card pair and assign a weighted connection based on three tiers of synergy. ### Tier A: Hard Synergies (Weight: 1.0) **Logic:** Direct mechanical triggers. - **Tribal Link:** If `Card_A.tags` (Tribe) $\cap$ `Card_B.text` (contains Tribe name) $\neq \emptyset$. - **Trigger-Response:** Identify "Providers" (e.g., "Whenever you gain life") and "Payoffs" (e.g., "When you gain life, [Effect]"). Link Provider $\rightarrow$ Payoff. ### Tier B: Functional Similarity (Weight: 0.6) **Logic:** Substitution/Role mapping. - **Role Dictionary:** Define roles (e.g., `RAMP`, `CARD_DRAW`, `REMOVAL`). - **Mapping:** If both cards share the same `Role_ID` based on their Functional Tokens, create a link. ### Tier C: Strategic Archetypes (Weight: 0.3) **Logic:** Thematic co-occurrence. - **Archetype Buckets:** Define keyword groups (e.g., `GRAVEYARD_STRAT` = ["mill", "graveyard", "reanimate"]). - **Density Check:** If both cards have a high overlap of keywords from the same bucket, create a link. ## 5. Phase 3: Database Schema (PSQL) Implement the following schema: ### Table: `cards` - `card_id`: UUID (Primary Key) - `name`: VARCHAR - `oracle_text`: TEXT - `mana_cost`: VARCHAR - `color_identity`: ARRAY[VARCHAR] - `tags`: ARRAY[VARCHAR] (Stored functional tokens and tribes) ### Table: `synergy_types` - `type_id`: INT (Primary Key) - `label`: VARCHAR (e.g., 'Tribal', 'Mechanical', 'Substitute') ### Table: `card_connections` - `card_id_a`: UUID (FK $\rightarrow$ cards) - `card_id_b`: UUID (FK $\rightarrow$ cards) - `type_id`: INT (FK $\rightarrow$ synergy_types) - `weight`: FLOAT - **Constraint:** `CHECK (card_id_a < card_id_b)` to prevent bidirectional duplicates. ## 6. Phase 4: Execution Pipeline The script must execute in the following order: 1. **Ingest:** Parse JSON $\rightarrow$ Bulk load into `cards` table. 2. **Analyze:** Run `TextProcessor` $\rightarrow$ Update `cards.tags`. 3. **Map:** - Iterate through card pairs. - Evaluate Tiers A, B, and C. - Insert identified synergies into `card_connections`. 4. **Index:** Create B-Tree indices on `card_id_a` and `card_id_b`. ## 7. Phase 5: Recommendation Logic (API Level) The resulting database must support the following query logic for the API: 1. **Input:** A list of `card_ids` currently in a deck. 2. **Query:** Find all `card_id_b` linked to any of the input IDs in `card_connections`. 3. **Aggregate:** Sum the `weight` for each suggested card. 4. **Filter:** Remove suggestions that do not match the `color_identity` of the deck. 5. **Output:** Return the top $N$ cards sorted by aggregate weight.