feat: Add MTGJSON data loading and download scripts
- Fix MtgSet model to match database schema (removed created_at, added image column) - Create load_mtgjson_data.py script to load AllSetFiles, AllPrintings.psql, and other MTGJSON data - Create download_mtgjson_data.py script to download MTGJSON API data files - Add SPEC_synergy-mapping-engine.md documentation API endpoints are now working (200 OK) but database needs data loading via download_mtgjson_data.py then load_mtgjson_data.py
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user