from __future__ import annotations #import inquirer.prompt # type: ignore import keyboard # type: ignore import pandas as pd # type: ignore import pprint # type: ignore import random from fuzzywuzzy import fuzz, process # type: ignore from InquirerPy import inquirer from InquirerPy.validator import EmptyInputValidator, NumberValidator from InquirerPy import prompt from settings import csv_directory from setup import determine_commanders, set_lands print('Would you like to leverage Scrython for pricing information?') choice = inquirer.confirm(message='', default=True).execute() if choice: use_scrython = True import scrython # type:ignore else: use_scrython = False print(use_scrython) pd.set_option('display.max_columns', None) pd.set_option('display.max_rows', None) pd.set_option('display.max_colwidth', 20) # Basic deck builder, initial plan will just be for kindred support. # Would like to add logic for other themes, as well as automatically go # through the commander and find suitable themes. # Will have it ask questions to determine number of creatures, lands, # interaction, ramp, etc... then adjust from there. # Land spread will ideally be handled based on pips and some adjustment # is planned based on mana curve and ramp added # Later plans to have card price taken into account will be added. Lands class DeckBuilder: def __init__(self): # Commander self.commander = '' self.commander_info = {} self.color_identity = '' self.colors = [] self.creature_types = [] self.commander_tags = [] self.commander_df = pd.DataFrame() # Library (99 cards total) self.library = [] # Number of cards that do/are what self.land_count = 0 self.creature_count = 0 self.removal = 0 self.wipes = 0 self.card_advantage = 0 self.ramp = 0 self.protection = 0 # Ideal number of cards that do/are what self.ideal_land_count = 0 self.ideal_creature_count = 0 self.ideal_removal = 0 self.ideal_wipes = 0 self.ideal_card_advantage = 0 self.ideal_ramp = 0 self.ideal_protection = 0 # Cards that are what type # Lands self.land_cards = [] # Creatures self.creature_cards = [] # Instants self.instant_cards = [] # Sorceries self.sorcery_cards = [] # Artifacts self.artifact_cards = [] # Enchantments self.enchantment_cards = [] # Planeswalkers self.planeswalker_cards = [] # Battles self.battle_cards = [] def questionnaire(self, inq_type, inq_default='', inq_choices=[]): if inq_type == 'Text': result = inquirer.text(message='', default=inq_default).execute() return result if inq_type == 'Number': result = inquirer.text(message='', default=inq_default, validate=NumberValidator(float_allowed=True)).execute() return float(result) if inq_type == 'Confirm': result = inquirer.confirm(message='', default=inq_default).execute() return result if inq_type == 'Choice': result = inquirer.select(message='', choices=inq_choices).execute() return result def price_check(self, card_name): card = scrython.cards.Named(fuzzy=f'{card_name}') card_price = card.prices('usd') #if card_price is None: # card_price = 0.0 return card_price def determine_commander(self): # Setup dataframe try: df = pd.read_csv('csv_files/commander_cards.csv', converters={'themeTags': pd.eval, 'creatureTypes': pd.eval}) except FileNotFoundError: determine_commanders() df = pd.read_csv('csv_files/commander_cards.csv', converters={'themeTags': pd.eval, 'creatureTypes': pd.eval}) # Determine the commander of the deck # Set frames that have nothing for color identity to be 'Colorless' instead df['colorIdentity'] = df['colorIdentity'].fillna('Colorless') df['colors'] = df['colors'].fillna('Colorless') commander_chosen = False while not commander_chosen: print('Enter a card name to be your commander, note that at this time only cards that have the \'Creature\' type may be chosen') card_choice = self.questionnaire('Text', '') # Logic to find the card in the commander_cards csv, then display it's information # If the card can't be found, or doesn't have enough of a match score, display a # list to choose from print(card_choice) fuzzy_chosen = False while not fuzzy_chosen: match, score, something = process.extractOne(card_choice, df['name']) if score >= 90: fuzzy_card_choice = match print(fuzzy_card_choice) fuzzy_chosen = True else: print('Multiple options found, which is correct?') fuzzy_card_choices = process.extract(card_choice, df['name'], limit=5) fuzzy_card_choices.append('Neither') print(fuzzy_card_choices) fuzzy_card_choice = self.questionnaire('Choice', inq_choices=fuzzy_card_choices) if fuzzy_card_choice != 'Neither': fuzzy_card_choice = fuzzy_card_choice[0] print(fuzzy_card_choice) fuzzy_chosen = True else: break filtered_df = df[df['name'] == fuzzy_card_choice] df_dict = filtered_df.to_dict('list') print('Is this the card you chose?') pprint.pprint(df_dict, sort_dicts=False) self.commander_df = pd.DataFrame(df_dict) # Confirm if card entered was correct commander_confirmed = self.questionnaire('Confirm', True) # If correct, set it as the commander if commander_confirmed: commander_chosen = True self.commander_info = df_dict self.commander = self.commander_df.at[0, 'name'] self.price_check(self.commander) break #print(self.commander) else: commander_chosen = False # Send commander info to setup commander, including extracting info on colors, color identity, # creature types, and other information, like keywords, abilities, etc... self.commander_setup() def commander_setup(self): # Load commander info into a dataframe df = self.commander_df # Set type line self.commander_type = str(df.at[0, 'type']) # Set text line self.commander_text = str(df.at[0, 'text']) # Set Power self.commander_power = int(df.at[0, 'power']) # Set Toughness self.commander_toughness = int(df.at[0, 'toughness']) # Set Mana Cost self.commander_mana_cost = str(df.at[0, 'manaCost']) # Set color identity self.color_identity = df.at[0, 'colorIdentity'] self.color_identity_full = '' self.determine_color_identity() # Set creature colors self.colors = df.at[0, 'colors'].split(', ') # Set creature types self.creature_types = str(df.at[0, 'creatureTypes']) # Set deck theme tags self.commander_tags = list(df.at[0, 'themeTags']) self.determine_themes() self.themes = [self.primary_theme] if not self.secondary_theme: pass else: self.themes.append(self.secondary_theme) if not self.tertiary_theme: pass else: self.themes.append(self.tertiary_theme) self.commander_dict = { 'Commander Name': self.commander, 'Mana Cost': self.commander_mana_cost, 'Color Identity': self.color_identity_full, 'Colors': self.colors, 'Type': self.commander_type, 'Creature Types': self.creature_types, 'Text': self.commander_text, 'Power': self.commander_power, 'Toughness': self.commander_toughness, 'Themes': self.themes } # Begin Building the Deck self.determine_ideals() self.add_lands() def determine_color_identity(self): # Determine the color identity for later # Mono color if self.color_identity == 'Colorless': self.color_identity_full = 'Colorless' self.files_to_load = ['colorless'] pass elif self.color_identity == 'B': self.color_identity_full = 'Black' self.files_to_load = ['colorless', 'black'] pass elif self.color_identity == 'G': self.color_identity_full = 'Green' self.files_to_load = ['colorless', 'green'] pass elif self.color_identity == 'R': self.color_identity_full = 'Red' self.files_to_load = ['colorless', 'red'] elif self.color_identity == 'U': self.color_identity_full = 'Blue' self.files_to_load = ['colorless', 'blue'] pass pass elif self.color_identity == 'W': self.color_identity_full = 'White' self.files_to_load = ['colorless', 'white'] pass # Two-color elif self.color_identity == 'B, G': self.color_identity_full = 'Golgari: Black/Green' self.color_identity_options = ['B', 'G', 'B, G'] self.files_to_load = ['colorless', 'black', 'green', 'golgari'] pass elif self.color_identity == 'B, R': self.color_identity_full = 'Rakdos: Black/Red' self.color_identity_options = ['B', 'R', 'B, R'] self.files_to_load = ['colorless', 'black', 'red', 'rakdos'] pass elif self.color_identity == 'B, U': self.color_identity_full = 'Dimir: Black/Blue' self.color_identity_options = ['B', 'U', 'B, U'] self.files_to_load = ['colorless', 'black', 'blue', 'dimir'] pass elif self.color_identity == 'B, W': self.color_identity_full = 'Orzhov: Black/White' self.color_identity_options = ['B', 'W', 'B, W'] self.files_to_load = ['colorless', 'black', 'white', 'orzhov'] pass elif self.color_identity == 'G, R': self.color_identity_full = 'Gruul: Green/Red' self.color_identity_options = ['G', 'R', 'G, R'] self.files_to_load = ['colorless', 'green', 'red', 'gruul'] pass elif self.color_identity == 'G, U': self.color_identity_full = 'Simic: Green/Blue' self.color_identity_options = ['G', 'U', 'G, U'] self.files_to_load = ['colorless', 'green', 'blue', 'simic'] pass elif self.color_identity == 'G, W': self.color_identity_full = 'Selesnya: Green/White' self.color_identity_options = ['G', 'W', 'G, W'] self.files_to_load = ['colorless', 'green', 'white', 'selesnya'] pass elif self.color_identity == 'U, R': self.color_identity_full = 'Izzet Blue/Red' self.color_identity_options = ['U', 'R', 'U, R'] self.files_to_load = ['colorless', 'blue', 'red', 'azorius'] pass elif self.color_identity == 'U, W': self.color_identity_full = 'Azorius: Blue/White' self.color_identity_options = ['U', 'W', 'U, W'] self.files_to_load = ['colorless', 'blue', 'white', 'azorius'] pass elif self.color_identity == 'R, W': self.color_identity_full = 'Boros: Red/White' self.color_identity_options = ['R', 'W', 'R, W'] self.files_to_load = ['colorless', 'red', 'white', 'boros'] pass # Thri-color elif self.color_identity == 'B, G, U': self.color_identity_full = 'Sultai: Black/Blue/Green' self.files_to_load = ['colorless', 'black', 'blue', 'green', 'dimir', 'golgari', 'simic', 'sultai'] pass elif self.color_identity == 'B, G, R': self.color_identity_full = 'Jund: Black/Green/Red' self.files_to_load = ['colorless', 'black', 'green', 'red', 'golgari', 'rakdos', 'gruul', 'jund'] pass elif self.color_identity == 'B, G, W': self.color_identity_full = 'Abzan: Black/Green/White' self.files_to_load = ['colorless', 'black', 'green', 'white', 'golgari', 'orzhov', 'selesnya', 'abzan'] pass elif self.color_identity == 'B, R, U': self.color_identity_full = 'Grixis: Black/Blue/Red' self.files_to_load = ['colorless', 'black', 'blue', 'red', 'dimir', 'rakdos', 'izzet', 'grixis'] pass elif self.color_identity == 'B, R, W': self.color_identity_full = 'Mardu: Black/Red/White' self.files_to_load = ['colorless', 'black', 'red', 'white', 'rakdos', 'orzhov', 'boros', 'mardu'] pass elif self.color_identity == 'B, U, W': self.color_identity_full = 'Esper: Black/Blue/White' self.files_to_load = ['colorless', 'black', 'blue', 'white', 'dimir', 'orzhov', 'azorius', 'esper'] pass elif self.color_identity == 'G, R, U': self.color_identity_full = 'Temur: Blue/Green/Red' self.files_to_load = ['colorless', 'green', 'red', 'blue', 'simir', 'izzet', 'gruul', 'temur'] pass elif self.color_identity == 'G, R, W': self.color_identity_full = 'Naya: Green/Red/White' self.files_to_load = ['colorless', 'green', 'red', 'white', 'gruul', 'selesnya', 'boros', 'naya'] pass elif self.color_identity == 'G, U, W': self.color_identity_full = 'Bant: Blue/Green/White' self.files_to_load = ['colorless', 'green', 'blue', 'white', 'simir', 'azorius', 'selesnya', 'bant'] pass elif self.color_identity == 'U, R, W': self.color_identity_full = 'Jeskai: Blue/Red/White' self.files_to_load = ['colorless', 'blue', 'red', 'white', 'izzet', 'azorius', 'boros', 'jeskai'] pass # Quad-color elif self.color_identity == 'B, G, R, U': self.color_identity_full = 'Glint: Black/Blue/Green/Red' self.files_to_load = ['colorless', 'black', 'blue', 'green', 'red', 'golgari', 'rakdos', 'dimir', 'gruul', 'simic', 'izzet', 'jund', 'sultai', 'grixis', 'temur', 'glint'] pass elif self.color_identity == 'B, G, R, W': self.color_identity_full = 'Dune: Black/Green/Red/White' self.files_to_load = ['colorless', 'black', 'green', 'red', 'white', 'golgari', 'rakdos', 'orzhov', 'gruul', 'selesnya', 'boros', 'jund', 'abzan', 'mardu', 'naya', 'dune'] pass elif self.color_identity == 'B, G, U, W': self.color_identity_full = 'Witch: Black/Blue/Green/White' self.files_to_load = ['colorless', 'black', 'blue', 'green', 'white', 'golgari', 'dimir', 'orzhov', 'simic', 'selesnya', 'azorius', 'sultai', 'abzan', 'esper', 'bant', 'glint'] pass elif self.color_identity == 'B, R, U, W': self.color_identity_full = 'Yore: Black/Blue/Red/White' self.files_to_load = ['colorless', 'black', 'blue', 'red', 'white', 'rakdos', 'dimir', 'orzhov', 'izzet', 'boros', 'azorius', 'grixis', 'mardu', 'esper', 'mardu', 'glint'] pass elif self.color_identity == 'G, R, U, W': self.color_identity_full = 'Ink: Blue/Green/Red/White' self.color_identity_options = ['G', 'R', 'U', 'W', 'G, R', 'G, U', 'G, W', 'R, U', 'R, W', 'U, W', 'G, R, U', 'G, R, W', 'G, U, W', 'R, U, W', 'G, R, U, W'] self.files_to_load = ['colorless', 'blue', 'green', 'red', 'white', 'gruul', 'simic', 'selesnya', 'izzet', 'boros', 'azorius', 'temur', 'naya', 'bant', 'jeskai', 'glint'] pass elif self.color_identity == 'B, G, R, U, W': self.color_identity_full = 'WUBRG: All colors' self.files_to_load = ['colorless', 'black', 'green', 'red', 'blue', 'white', 'golgari', 'rakdos',' dimir', 'orzhov', 'gruul', 'simic', 'selesnya', 'izzet', 'boros', 'azorius', 'jund', 'sultai', 'abzan', 'grixis', 'mardu', 'esper', 'temur', 'naya', 'bant', 'jeska', 'glint', 'dune','witch', 'yore', 'ink'] def determine_themes(self): themes = self.commander_tags print('Your commander deck will likely have a number of viable themes, but you\'ll want to narrow it down for focus.\n' 'This will go through the process of choosing up to three themes for the deck.\n') while True: # Choose a primary theme print('Choose a primary theme for your commander deck.\n' 'This will be the "focus" of the deck, in a kindred deck this will typically be a creature type for example.') choice = self.questionnaire('Choice', inq_choices=themes) self.primary_theme = choice themes.remove(choice) themes.append('Stop Here') secondary_theme_chosen = False tertiary_theme_chosen = False while not secondary_theme_chosen: # Secondary theme print('Choose a secondary theme for your commander deck.\n' 'This will typically be a secondary focus, like card draw for Spellslinger, or +1/+1 counters for Aggro.') choice = self.questionnaire('Choice', inq_choices=themes) while True: if choice == 'Stop Here': print('You\'ve only selected one theme, are you sure you want to stop?\n') confirm_done = self.questionnaire('Confirm', 'False') if confirm_done: secondary_theme_chosen = True self.secondary_theme = False tertiary_theme_chosen = True self.tertiary_theme = False themes.remove(choice) break else: pass else: self.secondary_theme = choice themes.remove(choice) secondary_theme_chosen = True break while not tertiary_theme_chosen: # Tertiary theme print('Choose a tertiary theme for your commander deck.\n' 'This will typically be a tertiary focus, or just something else to do that your commander is good at.') choice = self.questionnaire('Choice', inq_choices=themes) while True: if choice == 'Stop Here': print('You\'ve only selected two themes, are you sure you want to stop?\n') confirm_done = self.questionnaire('Confirm', False) if confirm_done: tertiary_theme_chosen = True self.tertiary_theme = False themes.remove(choice) break else: pass else: self.tertiary_theme = choice tertiary_theme_chosen = True break break def determine_ideals(self): # "Free" slots that can be used for anything that isn't the ideals self.free_slots = 99 if use_scrython: print('Would you like to set an intended max price of the deck?\n' 'There will be some leeway of ~10%, with a couple alternative options provided.') choice = self.questionnaire('Confirm', False) if choice: self.set_max_deck_price = True print('What would you like the max price to be?') self.max_deck_price = float(self.questionnaire('Number', '400')) else: self.set_max_deck_price = False print('Would you like to set a max price per card?\n' 'There will be some leeway of ~10% when choosing cards and you can choose to keep it or not.') choice = self.questionnaire('Confirm', False) if choice: self.set_max_card_price = True print('What would you like the max price to be?') answer = self.questionnaire('Number', '20') self.max_card_price = float(answer) else: self.set_max_card_price = False # Determine ramp print('How many pieces of ramp would you like to include?\n' 'You\'re gonna want a decent amount of ramp, both getting lands or mana rocks/dorks.\n' 'A good baseline is 8-12, scaling up with average CMC.') answer = self.questionnaire('Number', '8') self.ideal_ramp = int(answer) self.free_slots -= self.ideal_ramp # Determine ideal land count print('How many lands would you like to include?\n' 'Before ramp is taken into account, 38-40 would be "normal" for a deck. I personally use 35.\n' 'Broadly speaking, for every mana produced per 3 mana spent on ramp could reduce land count by 1.\n' 'If you\'re playing landfall, probably consider 40 as baseline before ramp.') answer = self.questionnaire('Number', '35') self.ideal_land_count = int(answer) self.free_slots -= self.ideal_land_count # Determine minimum basics to have print('How many basic lands would you like to have at minimum?\n' 'This can vary widely depending on your commander, colors in color identity, and what you want to do.\n' 'Some decks may be fine with as low as 10, others may want 25.') answer = self.questionnaire('Number', '20') self.min_basics = int(answer) # Determine ideal creature count print('How many creatures would you like to include?\n' 'Something like 25-30 would be a good starting point.\n' 'If you\'re going for a kindred theme, going past 30 is likely normal.\n' 'Also be sure to take into account token generation, but remember you\'ll want enough to stay safe') answer = self.questionnaire('Number', '25') self.ideal_creature_count = int(answer) self.free_slots -= self.ideal_creature_count # Determine spot/targetted removal print('How many spot removal pieces would you like to include?\n' 'A good starting point is about 8-12 pieces of spot removal.\n' 'Counterspells can be consisdered proactive removal and protection.\n' 'If you\'re going spellslinger, more would be a good idea as you might have less cretaures.') answer = self.questionnaire('Number', '10') self.ideal_removal = int(answer) self.free_slots -= self.ideal_removal # Determine board wipes print('How many board wipes would you like to include?\n' 'Somewhere around 2-3 is good to help eliminate threats, but also prevent the game from running long\n.' 'This can include damaging wipes like \'Blasphemous Act\' or toughness reduction like \'Meathook Massacre\'.') answer = self.questionnaire('Number', '2') self.ideal_wipes = int(answer) self.free_slots -= self.ideal_wipes # Determine card advantage print('How many pieces of card advantage would you like to include?\n' '10 pieces of card advantage is good, up to 14 is better.\n' 'Try to have a majority of it be non-conditional, and only have a couple of \'Rhystic Study\' style effects.') answer = self.questionnaire('Number', '10') self.ideal_card_advantage = int(answer) self.free_slots -= self.ideal_card_advantage # Determine how many protection spells print('How protection spells would you like to include?\n' 'This can be individual protection, board protection, fogs, or similar effects.\n' 'Things that grant indestructible, hexproof, phase out, or event just counterspells.\n' 'This can be a widely variable ideal count, and can be as low as 5, and up past 15,\n' 'it depends on your commander and how important your wincons are.') answer = self.questionnaire('Number', '8') self.ideal_protection = int(answer) self.free_slots -= self.ideal_protection print(f'Free slots that aren\'t part of the ideals: {self.free_slots}') print('Keep in mind that many of the ideals can also cover multiple roles, but this will give a baseline POV.') def add_lands(self): while True: try: with open(f'{csv_directory}/land_cards.csv', 'r', encoding='utf-8') as f: print('land_cards.csv found.') f.close() break except FileNotFoundError: print('land_cards.csv not found, regenerating it.') set_lands() self.land_df = pd.read_csv(f'{csv_directory}/land_cards.csv') # Begin the process to add lands, the number will depend on ideal land count, ramp, # and if any utility lands may be helpful. # By default, ({self.ideal_land_count} - 5) basic lands will be added, distributed # across the commander color identity. These will be removed for utility lands, # multi-color producing lands, fetches, and any MDFCs added later self.land_count = 0 self.add_basics() self.add_standard_non_basics() self.add_fetches() if 'Kindred' in ' '.join(self.themes): self.add_kindred_lands() if len(self.colors) >= 2: self.add_dual_lands() keyboard.wait('space') if len(self.colors) >= 3: pass self.add_misc_lands() rows_to_drop = [] for index, row in self.land_df.iterrows(): for land in self.land_cards: if land in row['name']: rows_to_drop.append(index) self.land_df = self.land_df.drop(rows_to_drop) self.land_df.to_csv(f'{csv_directory}/test_lands.csv', index=False) # If over ideal land count, remove random basics until ideal land count while self.land_count > self.ideal_land_count: self.remove_basic() #if self.land_cards < self.ideal_land_count: # pass basic_lands = ['Plains', 'Island', 'Swamp', 'Forest', 'Mountain'] total_basics = 0 for basic_land in basic_lands: num_basics = 0 if basic_land in self.land_cards: while basic_land in self.land_cards: num_basics += 1 self.land_cards.remove(basic_land) self.land_cards.append(f'{basic_land} x {num_basics}') total_basics += num_basics print(*self.land_cards, sep='\n') print(f'Total lands: {self.land_count}') print(total_basics) def add_basics(self): self.land_count = 0 base_basics = self.ideal_land_count - 5 # Reserve 5 slots for utility lands basics_per_color = base_basics // len(self.colors) remaining_basics = base_basics % len(self.colors) color_to_basic = { 'W': 'Plains', 'U': 'Island', 'B': 'Swamp', 'R': 'Mountain', 'G': 'Forest' } if 'Snow' in self.commander_tags: color_to_basic = { 'W': 'Snow-Covered Plains', 'U': 'Snow-Covered Island', 'B': 'Snow-Covered Swamp', 'R': 'Snow-Covered Mountain', 'G': 'Snow-Covered Forest' } print(f'Adding {base_basics} basic lands distributed across {len(self.colors)} colors') # Add equal distribution first for color in self.colors: basic = color_to_basic.get(color) if basic: for _ in range(basics_per_color): self.land_cards.append(basic) self.land_count += 1 # Distribute remaining basics based on color requirements if remaining_basics > 0: for color in self.colors[:remaining_basics]: basic = color_to_basic.get(color) if basic: self.land_cards.append(basic) self.land_count += 1 def add_standard_non_basics(self): # Add lands that are good in most any commander deck print('Adding "standard" non-basics') lands_to_remove = [] self.land_cards.append('Reliquary Tower') lands_to_remove.append('Reliquary Tower') self.land_count += 1 if 'Landfall' not in self.commander_tags: self.land_cards.append('Ash Barrens') lands_to_remove.append('Ash Barrens') self.land_count += 1 if len(self.colors) > 1: # Adding command Tower self.land_cards.append('Command Tower') lands_to_remove.append('Command Tower') self.land_count += 1 # Adding Exotic Orchard self.land_cards.append('Exotic Orchard') lands_to_remove.append('Exotic Orchard') self.land_count += 1 if len(self.colors) <= 2: self.land_cards.append('War Room') self.land_cards.append('War Room') self.land_count += 1 if self.commander_power >= 5: self.land_cards.append('Rogue\'s Passage') lands_to_remove.append('Rogue\'s Passage') self.land_count += 1 for index, row in self.land_df.iterrows(): if row['name'] in lands_to_remove: self.land_df = self.land_df.drop(index) def add_fetches(self): # Determine how many fetches in total print('How many fetch lands would you like to include?\n' 'For most decks you\'ll likely be good with 3 or 4, just enough to thin the deck and help ensure the color availability.\n' 'If you\'re doing Landfall, more fetches would be recommended just to get as many Landfall triggers per turn.') answer = self.questionnaire('Number', '5') desired_fetches = int(answer) chosen_fetches = [] generic_fetches = ['Evolving Wilds', 'Terramorphic Expanse', 'Shire Terrace', 'Escape Tunnel', 'Promising Vein','Myriad Landscape', 'Fabled Passage', 'Terminal Moraine'] fetches = generic_fetches fetches_to_remove = generic_fetches # Adding in expensive fetches """if (use_scrython and self.set_max_card_price): if self.price_check('Prismatic Vista') <= self.max_card_price: fetches_to_remove.append('Prismatic Vista') fetches.append('Prismatic Vista') else: fetches_to_remove.append('Prismatic Vista') pass else: fetches_to_remove.append('Prismatic Vista') fetches.append('Prismatic Vista')""" # White Fetches if 'W' in self.colors: white_fetches = ['Flooded Strand', 'Windswept Heath', 'Marsh Flats', 'Arid Mesa'] for fetch in white_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Blue fetches if 'U' in self.colors: blue_fetches = ['Flooded Strand', 'Polluted Delta', 'Scalding Tarn', 'Misty Rainforest'] for fetch in blue_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Black fetches if 'B' in self.colors: black_fetches = ['Polluted Delta', 'Bloodstained Mire', 'Marsh Flats', 'Verdant Catacombs'] for fetch in black_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # REd fetches if 'R' in self.colors: red_fetches = ['Bloodstained Mire', 'Wooded Foothills', 'Scalding Tarn', 'Arid Mesa'] for fetch in red_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Green fetches if 'G' in self.colors: green_fetches = ['Wooded Foothills', 'Windswept Heath', 'Verdant Catacombs', 'Misty Rainforest'] for fetch in green_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Adding in New Capenna Fetches # White New Capenna fetches if 'W' in self.colors: white_fetches = ['Brokers Hideout', 'Obscura Storefront', 'Cabaretti Courtyard'] for fetch in white_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Blue New Capenna Fetches if 'U' in self.colors: blue_fetches = ['Brokers Hideout', 'Obscura Storefront', 'Maestros Theater'] for fetch in blue_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Black New Capenna Fetches if 'B' in self.colors: black_fetches = ['Obscura Storefront', 'Maestros Theater', 'Riveteers Overlook'] for fetch in black_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Red New Capenna Fetches if 'R' in self.colors: red_fetches = ['Maestros Theater', 'Riveteers Overlook', 'Cabaretti Courtyard'] for fetch in red_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) # Green New Capenna Fetches if 'G' in self.colors: green_fetches = ['Brokers Hideout', 'Riveteers Overlook', 'Cabaretti Courtyard'] for fetch in green_fetches: if (use_scrython and self.set_max_card_price): if self.price_check(fetch) is None: fetches_to_remove.append(fetch) continue else: if float(self.price_check(fetch)) <= self.max_card_price: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) else: continue else: if fetch not in fetches: fetches_to_remove.append(fetch) fetches.append(fetch) fetches_chosen = False # Randomly choose fetches up to the desired number while not fetches_chosen: while len(chosen_fetches) < desired_fetches + 3: fetch_choice = random.choice(fetches) if fetch_choice not in chosen_fetches: chosen_fetches.append(fetch_choice) print('These are the fetch lands that have been found for you:') print(chosen_fetches) print('Do they look good for you?') answer = self.questionnaire('Confirm', True) if not answer: print('Reselecting fetches to use.') chosen_fetches = [] else: fetches_to_add = [] while len(fetches_to_add) < desired_fetches: print(f'Please choose {desired_fetches} of them to add to your deck.') choice = self.questionnaire('Choice', inq_choices=chosen_fetches) fetches_to_add.append(choice) chosen_fetches.remove(choice) fetches_chosen = True break break # Add fetches to deck for fetch in fetches_to_add: if fetch not in self.land_cards: self.land_cards.append(fetch) self.land_count += 1 # Remove Fetches from land_df for index, row in self.land_df.iterrows(): if row['name'] in fetches_to_remove: self.land_df = self.land_df.drop(index) def add_kindred_lands(self): print('Adding lands that care about the commander having a Kindred theme.') print('Adding general Kindred lands.') kindred_lands = ['Path of Ancestry'] lands_to_remove = kindred_lands if (use_scrython and self.set_max_card_price): for land in ['Three Tree City', 'Cavern of Souls']: if float(self.price_check(land)) <= self.max_card_price: kindred_lands.append(land) lands_to_remove.append(land) else: lands_to_remove.append(land) for land in kindred_lands: if land not in self.land_cards: self.land_cards.append(land) self.land_count += 1 for index, row in self.land_df.iterrows(): if row['name'] in lands_to_remove: self.land_df = self.land_df.drop(land) def add_dual_lands(self): # Determine dual-color lands available dual_options = [] for index, row in self.land_df.iterrows(): # Azorius Duals if ('W' in self.colors and 'U' in self.colors): if ('Land — Plains Island' == row['type'] or 'Snow Land — Plains Island' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Orzohv Duals if ('W' in self.colors and 'B' in self.colors): if ('Land — Plains Swamp' == row['type'] or 'Snow Land — Plains Swamp' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Dimir Duals if ('U' in self.colors and 'B' in self.colors): if ('Land — Island Swamp' == row['type'] or 'Snow Land — Island Swamp' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Golgari Duals if ('G' in self.colors and 'B' in self.colors): if ('Land — Forest Swamp' == row['type'] or 'Snow Land — Forest Swamp' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Rakdos Duals if ('B' in self.colors and 'R' in self.colors): if ('Land — Swamp Mountain' == row['type'] or 'Snow Land — Swamp Mountain' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Simic Duals if ('G' in self.colors and 'U' in self.colors): if ('Land — Forest Island' == row['type'] or 'Snow Land — Forest Island' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Gruul Duals if ('R' in self.colors and 'G' in self.colors): if ('Land — Mountain Forest' == row['type'] or 'Snow Land — Mountain Forest' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Izzet Duals if ('U' in self.colors and 'R' in self.colors): if ('Land — Island Mountain' == row['type'] or 'Snow Land — Island Mountain' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Selesnya Duals if ('G' in self.colors and 'W' in self.colors): if ('Land — Forest Plains' == row['type'] or 'Snow Land — Forest Plains' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Boros Duals if ('R' in self.colors and 'W' in self.colors): if ('Land — Mountain Plains' == row['type'] or 'Snow Land — Mountain Plains' == row['type'] ): self.land_df = self.land_df.drop(index) if (use_scrython and self.set_max_card_price): if self.price_check(row['name']) is None: continue else: if float(self.price_check(row['name'])) <= self.max_card_price: dual_options.append(row['name']) else: continue else: dual_options.append(row['name']) # Determine if using the dual-type lands print('Would you like to include dual-type lands (i.e. lands that count as both a Plains and a Swamp for example)?') choice = self.questionnaire('Confirm', True) # Add the Duals to a list while choice: print('Here\'s all the dual-type lands in your commander\'s color identity:') print(*dual_options, sep='\n') print('\n') for land in dual_options: if land not in self.land_cards: self.land_cards.append(land) self.land_count += 1 break def add_misc_lands(self): # Add other remaining lands that match color identity rows_to_drop = [] for index, row in self.land_df.iterrows(): if row['colorIdentity'] not in self.color_identity_options: rows_to_drop.append(index) filtered_lands_df = self.land_df.drop(rows_to_drop) # Take the first 35 matches based on EDHRec popularity filtered_lands_df = filtered_lands_df.head(35) lands_to_add = [] # Randomly grab 10 lands def remove_basic(self): basic_lands = [] for color in self.colors: if color == 'W': basic = 'Plains' elif color == 'U': basic = 'Island' elif color == 'B': basic = 'Swamp' elif color == 'R': basic = 'Mountain' elif color == 'G': basic = 'Forest' if basic not in basic_lands: basic_lands.append(basic) basic_land = random.choice(basic_lands) #print(basic_land) self.land_cards.remove(basic_land) self.land_count -= 1 def add_creatures(self): # Begin the process to add creatures, the number added will depend on what the # deck plan is, the commander, creature types, etc... print(f'Adding the creatures to deck, a baseline based on the ideal creature count of {self.ideal_creature_count} will be used.') build_deck = DeckBuilder() build_deck.determine_commander() """print(f'Commander: {build_deck.commander}') print(f'Color Identity: {build_deck.color_identity}') print(f'Commander Colors: {build_deck.colors}') print(f'Commander Creature Types: {build_deck.creature_types}') print(f'Commander Primary Theme: {build_deck.primary_theme}') if not build_deck.secondary_theme: pass else: print(f'Commander Secondary Theme: {build_deck.secondary_theme}') if not build_deck.tertiary_theme: pass else: print(f'Commander Tertiary Theme: {build_deck.tertiary_theme}')""" pprint.pprint(build_deck.commander_dict, sort_dicts = False) #build_deck.determine_commander() #build_deck.ideal_land_count = 35 #build_deck.add_lands()