Started remaking the builder module, Currently up through adding the standard/staple lands

This commit is contained in:
mwisnowski 2025-08-18 11:58:25 -07:00
parent a69a4c8384
commit a8a181c4af
7 changed files with 1337 additions and 1742 deletions

File diff suppressed because it is too large Load diff

View file

@ -122,6 +122,23 @@ OTHER_COLOR_MAP: Final[Dict[str, Tuple[str, List[str], List[str]]]] = {
'bant', 'jeskai', 'glint', 'dune', 'witch', 'yore', 'ink', 'wubrg'])
}
# Card category validation rules
CREATURE_VALIDATION_RULES: Final[Dict[str, Dict[str, Union[str, int, float, bool]]]] = {
'power': {'type': ('str', 'int', 'float'), 'required': True},
'toughness': {'type': ('str', 'int', 'float'), 'required': True},
'creatureTypes': {'type': 'list', 'required': True}
}
SPELL_VALIDATION_RULES: Final[Dict[str, Dict[str, Union[str, int, float, bool]]]] = {
'manaCost': {'type': 'str', 'required': True},
'text': {'type': 'str', 'required': True}
}
LAND_VALIDATION_RULES: Final[Dict[str, Dict[str, Union[str, int, float, bool]]]] = {
'type': {'type': ('str', 'object'), 'required': True},
'text': {'type': ('str', 'object'), 'required': False}
}
# Price checking configuration
DEFAULT_PRICE_DELAY: Final[float] = 0.1 # Delay between price checks in seconds
MAX_PRICE_CHECK_ATTEMPTS: Final[int] = 3 # Maximum attempts for price checking
@ -434,4 +451,21 @@ DATAFRAME_VALIDATION_RULES: Final[Dict[str, Dict[str, Union[str, int, float, boo
CARD_TYPE_SORT_ORDER: Final[List[str]] = [
'Planeswalker', 'Battle', 'Creature', 'Instant', 'Sorcery',
'Artifact', 'Enchantment', 'Land'
]
# Game changer cards, used to help determine bracket
GAME_CHANGERS: Final[List[str]] = [
'Ad Nauseum', 'Ancient Tomb', 'Aura Shards', 'Bolas\'s Citadel', 'Braids, Cabal Minion',
'Chrome Mox', 'Coalition Victory', 'Consecrated Sphinx', 'Crop Rotation', 'Cyclonic Rift',
'Deflecting Swat', 'Demonic Tutor', 'Drannith Magistrate', 'Enlightened Tutor', 'Expropriate',
'Field of the Dead', 'Fierce Guardianship', 'Food Chain', 'Force of Will', 'Gaea\'s Cradle',
'Gamble', 'Gifts Ungiven', 'Glacial Chasm', 'Grand Arbiter Augustin IV', 'Grim Monolith', 'Humility',
'Imperial Seal', 'Intuition', 'Jeska\'s Will', 'Jin-Gitaxias, Core Augur', 'Kinnan, Bonder Prodigy',
'Lion\'s Eye Diamond', 'Mana Vault', 'Mishra\'s Workshop', 'Mox Diamond', 'Mystical Tutor',
'Narset, Parter of Veils', 'Natural Order', 'Necropotence', 'Notion Thief', 'Opposition Agent',
'Orcish Bowmasters', 'Panoptic Mirror', 'Rhystic Study', 'Seedborn Muse', 'Serra\'s Sanctum',
'Smother Tithe', 'Survival of the Fittest', 'Sway of the Stars', 'Teferi\'s Protection',
'Tergrid, God of Fright', 'Thassa\'s Oracle', 'The One Ring', 'The Tabernacle at Pendrell Vale',
'Underworld Breach', 'Urza, Lord High Artificer', 'Vampiric Tutor', 'Vorinclex, Voice of Hunger',
'Winota, Joiner of Forces', 'Worldly Tutor', 'Yuriko, the Tiger\'s Shadow'
]

File diff suppressed because it is too large Load diff

View file

@ -17,18 +17,18 @@ __all__ = [
BANNED_CARDS: List[str] = [
# Commander banned list
'Ancestral Recall', 'Balance', 'Biorhythm', 'Black Lotus',
'Braids, Cabal Minion', 'Chaos Orb', 'Coalition Victory',
'Channel', 'Dockside Extortionist', 'Emrakul, the Aeons Torn',
'Chaos Orb', 'Channel', 'Dockside Extortionist',
'Emrakul, the Aeons Torn',
'Erayo, Soratami Ascendant', 'Falling Star', 'Fastbond',
'Flash', 'Gifts Ungiven', 'Golos, Tireless Pilgrim',
'Flash', 'Golos, Tireless Pilgrim',
'Griselbrand', 'Hullbreacher', 'Iona, Shield of Emeria',
'Karakas', 'Jeweled Lotus', 'Leovold, Emissary of Trest',
'Library of Alexandria', 'Limited Resources', 'Lutri, the Spellchaser',
'Mana Crypt', 'Mox Emerald', 'Mox Jet', 'Mox Pearl', 'Mox Ruby',
'Mox Sapphire', 'Nadu, Winged Wisdom', 'Panoptic Mirror',
'Mox Sapphire', 'Nadu, Winged Wisdom',
'Paradox Engine', 'Primeval Titan', 'Prophet of Kruphix',
'Recurring Nightmare', 'Rofellos, Llanowar Emissary', 'Shahrazad',
'Sundering Titan', 'Sway of the Stars', 'Sylvan Primordial',
'Sundering Titan', 'Sylvan Primordial',
'Time Vault', 'Time Walk', 'Tinker', 'Tolarian Academy',
'Trade Secrets', 'Upheaval', "Yawgmoth's Bargain",
# Problematic / culturally sensitive or banned in other formats

View file

@ -0,0 +1,39 @@
from deck_builder.builder import DeckBuilder
# Non-interactive harness: chooses specified commander, first tag, first bracket, accepts defaults
def run(command_name: str = "Finneas, Ace Archer"):
scripted_inputs = []
# Commander query
scripted_inputs.append(command_name) # initial query
# After showing matches, choose first candidate (index 1)
scripted_inputs.append("1") # select first candidate to inspect
scripted_inputs.append("y") # confirm commander
# Tag selection: choose eleventh tag as primary
scripted_inputs.append("11")
# Stop after primary (secondary prompt enters 1)
scripted_inputs.append("1")
# Stop after primary (tertiary prompt enters 0)
scripted_inputs.append("0")
# Bracket selection: choose 3 (Typical Casual mid default) else 2 maybe; pick 3
scripted_inputs.append("3")
# Ideal counts prompts (8 prompts) -> press Enter (empty) to accept defaults
for _ in range(8):
scripted_inputs.append("")
def scripted_input(prompt: str) -> str:
if scripted_inputs:
return scripted_inputs.pop(0)
raise RuntimeError("Ran out of scripted inputs for prompt: " + prompt)
b = DeckBuilder(input_func=scripted_input)
b.run_initial_setup()
b.run_deck_build_step1()
b.run_deck_build_step2()
b.run_land_step1()
b.run_land_step2()
b.print_card_library()
return b
if __name__ == "__main__":
run()

View file

@ -7,6 +7,7 @@ tqdm>=4.66.0
scrython>=1.10.0
numpy>=1.24.0
requests>=2.31.0
prettytable>=3.9.0
# Development dependencies
mypy>=1.3.0