Migrates the reaper-king-no-more proof of concept into decks/reaper-king-no-more/
as the first deck under a shared tools/ engine, so the repo can hold many
Commander decks instead of one implicit one.
- tools/deckctx.py: new shared DeckContext, resolves --deck / $MTG_DECK / cwd,
loads a deck's config.yaml, and derives color identity from the commander's
own card data (never a hardcoded color combination).
- cards.py: drop the JUND=frozenset("BRG") constant; jund_legal() renamed to
identity_legal(card, identity); DB() takes an explicit blacklist_path since
the blacklist is per-deck, not shared.
- combos.py, roles.py, similar.py, similar_text.py, bracket_check.py: take
--deck, use the deck's real identity instead of Jund/BRG.
- power.py, card_stats.py, forge_report.py: OURS deck-name constant now comes
from the deck's config (name: / commander), matched via DeckContext instead
of hardcoded "Reaper King No More".
- to_dck.py, batch_run.py, ab_test.py: .dck filename and [metadata] Name= are
derived from the deck (slug / config name), not a hardcoded "reaper.dck".
- generate.py: RECIPES and make_variants.py's VARIANTS (deck-specific
hypotheses) moved out of Python into decks/reaper-king-no-more/variants.yaml;
protected cards now come from config.yaml's protected: list instead of a
hardcoded set.
- New tools/mtg dispatcher: `tools/mtg decks/<name> <tool> [args...]` runs any
tool against any deck without cd-ing into its directory.
- data/ (Scryfall/MTGJSON/Spellbook bulk, ~1.2GB, gitignored) and embeddings.npz
move to the repo root as shared, commander-format-wide data.
- docs/howto.md: moved from the deck dir (it documents the tool, not the deck)
and updated its example commands to the real generalized CLI.
- README.md: rewritten to describe the multi-deck repo and point at
decks/reaper-king-no-more as the reference example.
Verified after the change: bracket_check, combos, and roles against
reaper-king-no-more reproduce the exact PASS/11-combos/role-profile numbers
from before the move; generate.py --list now loads recipes from YAML;
make_variants.py reproduces all 7 hand-curated variants including the
mikaeus FAIL control case; to_dck.py derives the right Name= and filename;
variant.py and compare.py reproduce decks/README.md's original numbers
exactly. The original POC at ~/mtg/reaper-king-no-more is untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPKgLYpMR8szWNFXyK1XNu
141 lines
4.9 KiB
YAML
141 lines
4.9 KiB
YAML
# Variant recipes for tools/generate.py -- role-budget reallocation hypotheses.
|
|
#
|
|
# Each recipe is a reallocation: shift N slots from one role to another, then
|
|
# let tools/generate.py pick which specific cards to cut and add. Cuts come
|
|
# from the weakest cards in the over-served role; adds come from the best
|
|
# unused cards in the under-served one.
|
|
#
|
|
# Deltas for each recipe must sum to zero so the deck stays at 100 cards.
|
|
#
|
|
# python3 tools/generate.py --deck decks/reaper-king-no-more --list
|
|
# python3 tools/generate.py --deck decks/reaper-king-no-more
|
|
# python3 tools/generate.py --deck decks/reaper-king-no-more --only aggro-hate
|
|
|
|
recipes:
|
|
aggro-hate:
|
|
why: >
|
|
15 of 17 losses were life hitting 0 against aggro. Trade combo
|
|
redundancy for sweepers and spot removal.
|
|
deltas:
|
|
removal_mass: 3
|
|
removal_spot: 2
|
|
minus_engine: -3
|
|
sac_outlet: -2
|
|
|
|
card-engine:
|
|
why: >
|
|
Only 1 real draw engine in 99 cards. An aristocrats deck that draws
|
|
off its own deaths should never run out of gas.
|
|
deltas:
|
|
draw: 5
|
|
death_trigger: 2
|
|
minus_engine: -4
|
|
ramp: -3
|
|
|
|
opponent-facing:
|
|
why: >
|
|
The commander only steals from OPPONENTS' creatures. Maximise cards
|
|
that trigger on their deaths and put counters on their board.
|
|
deltas:
|
|
opp_death: 5
|
|
removal_spot: 2
|
|
sac_outlet: -3
|
|
ramp: -2
|
|
minus_engine: -2
|
|
|
|
go-wide:
|
|
why: >
|
|
Token swarms feed sac outlets and the -1/-1 engine simultaneously.
|
|
Tests whether bodies beat individually stronger cards.
|
|
deltas:
|
|
tokens: 5
|
|
sac_payoff: 2
|
|
minus_engine: -3
|
|
removal_spot: -2
|
|
ramp: -2
|
|
|
|
proliferate:
|
|
why: >
|
|
Proliferate multiplies -1/-1 counters, turning one trigger into many.
|
|
A different engine for the same theme.
|
|
deltas:
|
|
proliferate: 5
|
|
minus_engine: 1
|
|
ramp: -3
|
|
sac_outlet: -3
|
|
|
|
grindy:
|
|
why: >
|
|
Recursion + drain: never combo, just refuse to lose and bleed the
|
|
table out. Tests whether this deck wants to be a value pile.
|
|
deltas:
|
|
reanimate: 3
|
|
drain: 3
|
|
draw: 2
|
|
minus_engine: -4
|
|
sac_outlet: -2
|
|
ramp: -2
|
|
|
|
# Hand-curated variants for tools/make_variants.py -- explicit cut/add lists
|
|
# against the baseline, rather than a role-budget reallocation. Each is a
|
|
# specific hypothesis about specific cards (see plan.md section 6b/6c for
|
|
# how these were chosen).
|
|
#
|
|
# python3 tools/make_variants.py --deck decks/reaper-king-no-more --list
|
|
# python3 tools/make_variants.py --deck decks/reaper-king-no-more
|
|
handwritten:
|
|
no-mikaeus:
|
|
why: "Baseline. Aristocrats + -1/-1, every combo needs board state."
|
|
cut: []
|
|
add: []
|
|
|
|
mikaeus:
|
|
why: >
|
|
Does the highest-leverage combo card (28 combos) stay legal?
|
|
Expected FAIL: goes infinite with every sac outlet.
|
|
cut: ["Humble Defector"]
|
|
add: ["Mikaeus, the Unhallowed"]
|
|
|
|
lean-outlets:
|
|
why: >
|
|
The deck runs 8 sac outlets and probably needs ~5. Cut 3 for
|
|
interaction and card advantage -- does consistency actually drop?
|
|
cut: ["Woe Strider", "Yahenni, Undying Partisan", "Greater Good"]
|
|
add: ["Bloodchief Ascension", "Toshiro Umezawa", "Fiery Cannonade"]
|
|
|
|
commander-focus:
|
|
why: >
|
|
The commander only steals from OPPONENTS' creatures, but the deck's
|
|
-1/-1 engine mostly counters our own. Push counters onto their board.
|
|
cut: ["Putrid Goblin", "Cauldron of Souls", "Murderous Redcap", "Woe Strider"]
|
|
add: ["Mari, the Killing Quill", "Sangromancer", "Patron of the Vein",
|
|
"Slaughter Specialist"]
|
|
|
|
heavy-removal:
|
|
why: >
|
|
Bracket 3 pods interact. Trade combo redundancy for removal and see
|
|
whether surviving longer beats assembling faster.
|
|
cut: ["Flourishing Defenses", "Nest of Scarabs", "Obelisk Spider",
|
|
"Persistent Constrictor"]
|
|
add: ["Fiery Cannonade", "Vraska, the Silencer", "Meathook Massacre II",
|
|
"Go for the Throat"]
|
|
|
|
fast-ramp:
|
|
why: >
|
|
6 of 10 ramp pieces cost 3+, and the deck already has 22 three-drops.
|
|
T3 ramp means NOT deploying an engine piece. Swap the 3-mana fetch
|
|
spells for 1-mana dorks -- which are also creatures, so they feed the
|
|
sac outlets and the -1/-1 engine instead of being do-nothing sorceries.
|
|
cut: ["Cultivate", "Kodama's Reach", "Springbloom Druid", "Wood Elves",
|
|
"Binding the Old Gods"]
|
|
add: ["Llanowar Elves", "Elvish Mystic", "Fyndhorn Elves",
|
|
"Ignoble Hierarch", "Delighted Halfling"]
|
|
|
|
low-curve:
|
|
why: >
|
|
Avg MV is 3.02 and the engine lands ~T6. Cut the top of the curve
|
|
entirely -- does the deck come online sooner and win more?
|
|
cut: ["Massacre Wurm", "Overseer of the Damned", "Archfiend of Ifnir",
|
|
"Grim Poppet", "Cauldron of Souls"]
|
|
add: ["Malakir Cullblade", "Slaughter Specialist", "Bloodchief Ascension",
|
|
"Nurgle's Rot", "Chevill, Bane of Monsters"]
|