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
66 lines
2.1 KiB
YAML
66 lines
2.1 KiB
YAML
# What you supply. Everything else is derived from the card databases.
|
|
|
|
# Deck name, used as the Forge [metadata] Name= value and to match "our seat"
|
|
# in Forge's play-by-play logs. Deliberately distinct from the commander's own
|
|
# card name (which also appears in the decklist) so log matching never
|
|
# confuses "cast the commander" with "our player seat".
|
|
name: "Reaper King No More"
|
|
|
|
commander: "The Reaper, King No More"
|
|
|
|
# Which cards decks may be built from.
|
|
# Either a rank cap (popularity proxy) or an explicit curated file.
|
|
pool:
|
|
max_edhrec_rank: 1000 # ~451 cards in Jund. See howto.md "Choosing a pool size"
|
|
# file: mypool.txt # ...or curate the list yourself
|
|
min_mana_value: 0
|
|
max_mana_value: 7
|
|
|
|
# Cards you refuse to play, with reasons. See blacklist.txt.
|
|
blacklist_file: blacklist.txt
|
|
|
|
constraints:
|
|
bracket: 3 # game changers <=3, no MLD, extra turns sparse
|
|
no_vacuum_combos: true # house rule: no 2-card infinites needing no board state
|
|
lands: 36
|
|
deck_size: 100
|
|
|
|
# How many of each job a deck should contain. The generator fills to these
|
|
# targets and a variant is a deliberate deviation from them.
|
|
# Roles are detected automatically from Scryfall Tagger tags.
|
|
roles:
|
|
minus_engine: 16
|
|
sac_outlet: 6
|
|
sac_payoff: 4
|
|
opp_death: 7
|
|
drain: 5
|
|
death_trigger: 8
|
|
ramp: 9
|
|
draw: 6
|
|
removal_mass: 3
|
|
removal_spot: 8
|
|
tokens: 2
|
|
proliferate: 2
|
|
reanimate: 1
|
|
tutor: 0
|
|
|
|
# Cards the generator may never cut -- your deck's identity.
|
|
protected:
|
|
- "Hapatra, Vizier of Poisons"
|
|
- "Blowfly Infestation"
|
|
- "Nest of Scarabs"
|
|
- "Necroskitter"
|
|
- "Yawgmoth, Thran Physician"
|
|
- "Blood Artist"
|
|
- "Zulaport Cutthroat"
|
|
- "Viscera Seer"
|
|
- "Carrion Feeder"
|
|
|
|
# tools/generate.py's variant recipes -- role-budget reallocation hypotheses.
|
|
variants_file: variants.yaml
|
|
|
|
simulation:
|
|
games_per_deck: 150 # 150 = +/-6.9pp. Below 100 is noise. See howto.md
|
|
workers: 16 # ~1 core and ~1.5GB RAM each
|
|
heap: 2g # per-worker JVM heap
|
|
rotate_opponents: true # 4 precon pods, so results aren't matchup-specific
|