TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/invvd/mtg-cheaper-deck/llms.txt
Use this file to discover all available pages before exploring further.
scoring module is responsible for two things: efficiently loading the set of legal, priced cards for a given format (the candidate pool), and ranking those candidates against a target card using a weighted similarity score. The pool is loaded once per deck run — not once per card — so the expensive SQL + JSON work happens a single time regardless of how many cards are in the deck.
Scoring combines four independent signals. Each signal is a value between 0 and 1 (or slightly above for EDHREC), then multiplied by its weight before being summed into a final score. Higher is more similar.
Scoring Weights
The four weight constants control how much each signal contributes to the total score.| Constant | Value | Signal | ||
|---|---|---|---|---|
KEYWORD_WEIGHT | 3.0 | Jaccard overlap between Scryfall evergreen keyword lists | ||
TEXT_OVERLAP_WEIGHT | 2.5 | Jaccard overlap between tokenised, stop-word-filtered oracle texts | ||
CMC_WEIGHT | 1.0 | Proximity in converted mana cost: `1 / (1 + | Δcmc | )` |
EDHREC_WEIGHT | 1.0 | Popularity signal: 1 / (1 + rank / 1000) |
KEYWORD_WEIGHT is the highest because shared evergreen keywords (Flying, Trample, Deathtouch, etc.) are the most direct signal of functional overlap. TEXT_OVERLAP_WEIGHT is almost as important because many combo or synergy pieces share no keywords at all — their function lives entirely in the oracle text.
extract_core_types
Parses a Scryfalltype_line string and returns the set of recognised core supertypes present.
A Scryfall type line string such as
"Legendary Creature — Elf Druid" or "Instant". The function only considers the portion before —. Returns an empty set when None or an empty string is passed.set[str] — a subset of the recognised core types:
suggest_alternatives() to ensure that candidate cards share at least one core type with the original (e.g. a Sorcery is not suggested as a replacement for a Creature).
CandidatePool
CandidatePool holds all legal, priced cards for a format, pre-processed for fast per-card scoring. Construct it via load_candidate_pool() rather than directly.
Constructor
A list of card row dicts, each sourced from the
cards table in the local database. Every row must have at least price_usd, keywords, and oracle_text fields. The constructor pre-computes _keywords_set (a set of keyword strings) and _text_tokens (a stop-word-filtered token set from oracle_text) on each row in place, then sorts the list ascending by price_usd.cheaper_than
Returns all cards in the pool whoseprice_usd is strictly less than the given price.
The price ceiling (exclusive). Only cards with
price_usd < price are returned.list[dict] — a slice of the sorted pool rows, all cheaper than price. Uses bisect.bisect_left on the pre-built price list for O(log n) lookup.
load_candidate_pool
Queries the local database and returns aCandidatePool containing every card with a USD price that is legal in the given format.
A Scryfall format name stored as a key inside the
legalities JSON column — for example "commander", "standard", "modern", "pioneer". Only cards where legalities[format_key] == "legal" are included.CandidatePool — pre-sorted by price_usd ascending, with _keywords_set and _text_tokens pre-computed on every row.
suggest_alternatives
Scores every candidate in the pool againstoriginal and returns the top top_n suggestions.
A local database row dict for the card being replaced. Must have at minimum
oracle_id, price_usd, color_identity_mask, type_line, keywords, oracle_text, and cmc. If price_usd is None, an empty list is returned immediately.A
CandidatePool loaded with load_candidate_pool() for the same format as the deck. Should be created once and reused for every card in the deck.Maximum number of suggestions to return. Results are sorted by score descending; only the highest-scoring
top_n candidates are returned.A set of
oracle_id values to skip — typically the oracle IDs of all cards already in the deck. Without this, a card already present elsewhere in the deck could appear as a suggestion for a different card.list[dict] — up to top_n suggestion dicts, sorted by score descending. Each dict has:
The full candidate card row from the database.
The combined weighted similarity score (sum of all four weighted signals).
A human-readable breakdown of the score:
shared_keywords— sorted list of keyword strings shared between original and candidateshared_text_terms— sorted list of up to 6 oracle-text tokens shared between original and candidatecmc_delta— absolute CMC difference (float), orNoneif either card lacks a CMCedhrec_rank— the candidate’s EDHREC rank (int), orNoneif unavailable
color_identity_mask must be a subset of the original’s (no off-colour suggestions), and they must share at least one core type with the original (no cross-type suggestions).