Adjusted some logic in setup to filter out any banned cards, as well as add the layout column to allow for easily seeing 'Normal', 'MDFC', or 'Transform cards.

Added logic for 'Kindred Support' tagging in tagger
This commit is contained in:
mwisnowski 2024-12-26 09:38:21 -08:00
parent c81a5fb64e
commit f9ae7fa41e
3 changed files with 111 additions and 111 deletions

49
main.py
View file

@ -1,10 +1,6 @@
from __future__ import annotations from __future__ import annotations
#import os
import inquirer.prompt # type: ignore import inquirer.prompt # type: ignore
#import pandas as pd # type: ignore
#import requests # type: ignore
#import scrython # type: ignore
import sys import sys
from pathlib import Path from pathlib import Path
@ -24,21 +20,29 @@ while True:
choices=['Setup', 'Build a Deck', 'Get Card Info', 'Quit'], choices=['Setup', 'Build a Deck', 'Get Card Info', 'Quit'],
carousel=True) carousel=True)
] ]
answer = inquirer.prompt(question) try:
choice = answer['menu'] answer = inquirer.prompt(question)
if answer is None:
print("Operation cancelled. Returning to menu...")
choice = 'Menu'
continue
choice = answer['menu']
except (KeyError, TypeError):
print("Invalid input. Please try again.")
choice = 'Menu'
# Run through initial setup # Run through initial setup
while choice == 'Setup': while choice == 'Setup':
setup.setup() setup.setup()
choice = 'Menu' choice = 'Menu'
break
# Make a new deck # Make a new deck
while choice == 'Build a Deck': while choice == 'Build a Deck':
print('Deck building not yet implemented') print('Deck building not yet implemented')
choice = 'Menu' choice = 'Menu'
break
# Get a cards info # Get a cards info
while choice == 'Get Card Info': while choice == 'Get Card Info':
card_info.get_card_info() card_info.get_card_info()
@ -46,16 +50,21 @@ while True:
inquirer.Confirm('continue', inquirer.Confirm('continue',
message='Would you like to look up another card?' message='Would you like to look up another card?'
) )
] ]
answer = inquirer.prompt(question) try:
new_card = answer['continue'] answer = inquirer.prompt(question)
if new_card: if answer is None:
choice == 'Get Card Info' print("Operation cancelled. Returning to menu...")
else: choice = 'Menu'
continue
new_card = answer['continue']
if new_card:
choice = 'Get Card Info' # Fixed == to = for assignment
except (KeyError, TypeError):
print("Invalid input. Returning to menu...")
choice = 'Menu' choice = 'Menu'
break
# Quit # Quit
while choice == 'Quit': while choice == 'Quit':
sys.exit() sys.exit()
break

View file

@ -37,12 +37,15 @@ def filter_by_color(df, column_name, value, new_csv_name):
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart']
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn']
for card in banned_cards:
filtered_df = filtered_df[~filtered_df['name'].str.contains(card)]
card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomenon', 'Stickers', 'Attraction', 'Hero', 'Contraption'] card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomenon', 'Stickers', 'Attraction', 'Hero', 'Contraption']
for card_type in card_types: for card_type in card_types:
filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)] filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)]
filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name']) filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name'])
filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True) filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True)
columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'text', 'power', 'toughness', 'keywords'] columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'layout', 'text', 'power', 'toughness', 'keywords']
filtered_df = filtered_df[columns_to_keep] filtered_df = filtered_df[columns_to_keep]
filtered_df.sort_values(by='name', key=lambda col: col.str.lower(), inplace=True) filtered_df.sort_values(by='name', key=lambda col: col.str.lower(), inplace=True)
@ -91,14 +94,17 @@ def set_lands():
filtered_df = filtered_df[filtered_df['availability'].str.contains('paper')] filtered_df = filtered_df[filtered_df['availability'].str.contains('paper')]
filtered_df = filtered_df.loc[filtered_df['promoTypes'] != 'playtest'] filtered_df = filtered_df.loc[filtered_df['promoTypes'] != 'playtest']
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart']
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn']
card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomenon', 'Stickers', 'Attraction', 'Hero'] for card in banned_cards:
filtered_df = filtered_df[~filtered_df['name'].str.contains(card)]
card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomenon', 'Stickers', 'Attraction', 'Hero', 'Contraption']
for card_type in card_types: for card_type in card_types:
filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)] filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)]
filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name']) filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name'])
filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True) filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True)
columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'layout', 'text'] columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'layout', 'text', 'power', 'toughness', 'keywords']
filtered_df = filtered_df[columns_to_keep] filtered_df = filtered_df[columns_to_keep]
filtered_df.sort_values(by='edhrecRank', inplace=True) filtered_df.sort_values(by='edhrecRank', inplace=True)
filtered_df.to_csv(f'{csv_directory}/land_cards.csv', index=False) filtered_df.to_csv(f'{csv_directory}/land_cards.csv', index=False)
@ -154,14 +160,17 @@ def determine_commanders():
filtered_df = filtered_df[filtered_df['availability'].str.contains('paper')] filtered_df = filtered_df[filtered_df['availability'].str.contains('paper')]
filtered_df = filtered_df.loc[filtered_df['promoTypes'] != 'playtest'] filtered_df = filtered_df.loc[filtered_df['promoTypes'] != 'playtest']
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'heart']
filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn'] filtered_df = filtered_df.loc[filtered_df['securityStamp'] != 'acorn']
card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomena', 'Stickers', 'Attraction'] for card in banned_cards:
filtered_df = filtered_df[~filtered_df['name'].str.contains(card)]
card_types = ['Plane —', 'Conspiracy', 'Vanguard', 'Scheme', 'Phenomenon', 'Stickers', 'Attraction', 'Hero', 'Contraption']
for card_type in card_types: for card_type in card_types:
filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)] filtered_df = filtered_df[~filtered_df['type'].str.contains(card_type)]
filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name']) filtered_df['faceName'] = filtered_df['faceName'].fillna(filtered_df['name'])
filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True) filtered_df.drop_duplicates(subset='faceName', keep='first', inplace=True)
columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'keywords', 'text', 'power', 'toughness'] columns_to_keep = ['name', 'faceName','edhrecRank','colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'layout', 'text', 'power', 'toughness', 'keywords']
filtered_df = filtered_df[columns_to_keep] filtered_df = filtered_df[columns_to_keep]
filtered_df.sort_values(by='name', key=lambda col: col.str.lower(), inplace=True) filtered_df.sort_values(by='name', key=lambda col: col.str.lower(), inplace=True)
filtered_df.to_csv(f'{csv_directory}/commander_cards.csv', index=False) filtered_df.to_csv(f'{csv_directory}/commander_cards.csv', index=False)
@ -181,18 +190,18 @@ def initial_setup():
r = requests.get(url) r = requests.get(url)
with open(f'{csv_directory}/cards.csv', 'wb') as outputfile: with open(f'{csv_directory}/cards.csv', 'wb') as outputfile:
outputfile.write(r.content) outputfile.write(r.content)
# Load cards.csv file into pandas dataframe so it can be further broken down # Load cards.csv file into pandas dataframe so it can be further broken down
df = pd.read_csv(f'{csv_directory}/cards.csv', low_memory=False) df = pd.read_csv(f'{csv_directory}/cards.csv', low_memory=False)
# Set frames that have nothing for color identity to be 'Colorless' instead # Set frames that have nothing for color identity to be 'Colorless' instead
df['colorIdentity'] = df['colorIdentity'].fillna('Colorless') df['colorIdentity'] = df['colorIdentity'].fillna('Colorless')
# Check for and create missing, individual color identity sorted CSVs # Check for and create missing, individual color identity sorted CSVs
print('Checking for color identity sorted files.\n') print('Checking for color identity sorted files.\n')
# For loop to iterate through the colors # For loop to iterate through the colors
for i in range(len(colors), len(color_abrv)): for i in range(min(len(colors), len(color_abrv))):
print(f'Checking for {colors[i]}_cards.csv.') print(f'Checking for {colors[i]}_cards.csv.')
try: try:
with open(f'{csv_directory}/{colors[i]}_cards.csv', 'r', encoding='utf-8'): with open(f'{csv_directory}/{colors[i]}_cards.csv', 'r', encoding='utf-8'):
@ -200,13 +209,13 @@ def initial_setup():
except FileNotFoundError: except FileNotFoundError:
print(f'{colors[i]}_cards.csv not found, creating one.\n') print(f'{colors[i]}_cards.csv not found, creating one.\n')
filter_by_color(df, 'colorIdentity', color_abrv[i], f'{csv_directory}/{colors[i]}_cards.csv') filter_by_color(df, 'colorIdentity', color_abrv[i], f'{csv_directory}/{colors[i]}_cards.csv')
# Once by-color lists have been made, Determine legendary creatures # Once by-color lists have been made, Determine legendary creatures
determine_commanders() determine_commanders()
# Lastly, create a file with all lands, or cards that have a land on at least one face # Lastly, create a file with all lands, or cards that have a land on at least one face
set_lands() set_lands()
# Once Legendary creatures are determined, generate staple lists # Once Legendary creatures are determined, generate staple lists
# generate_staple_lists() # generate_staple_lists()
@ -282,40 +291,6 @@ def regenerate_csv_by_color(color):
# Lastly, create a file with all lands, or cards that have a land on at least one face # Lastly, create a file with all lands, or cards that have a land on at least one face
set_lands() set_lands()
def generate_staple_lists():
for color in colors:
staples = []
print(f'Checking for {color} staples file.')
try:
with open(f'staples/{color}.txt', 'r') as file:
staples = file.read().split('\n')
del staples[-1]
print(f'{color.capitalize()} staples:')
print('\n'.join(staples), '\n')
except FileNotFoundError:
print(f'{color.capitalize()} staples file not found.')
print(f'Generating {color} staples list.')
df = pd.read_csv(f'{csv_directory}/{color}_cards.csv')
df['edhrecRank'] = pd.to_numeric(df['edhrecRank'], downcast='integer', errors='coerce')
df = df.dropna(subset=['edhrecRank'])
df['edhrecRank'] = df['edhrecRank'].astype(int)
columns_to_keep = ['name', 'edhrecRank', 'type']
df = df[columns_to_keep]
df.sort_values(by='edhrecRank', key=lambda col: col, inplace=True)
i = 1
y = 0
while len(staples) < 20 and y < len(df):
for index, row in df.iterrows():
if row['edhrecRank'] == i:
if 'Land' not in row['type'] and row['name'] not in banned_cards:
staples.append(row['name'])
i += 1
y += 1
with open(f'staples/{color}.txt', 'w') as f:
for items in staples:
f.write('%s\n' %items)
def add_tags(): def add_tags():
pass pass
@ -349,7 +324,7 @@ def setup():
break break
break break
#regenerate_csvs_all() regenerate_csvs_all()
#regenerate_csv_by_color('white') #regenerate_csv_by_color('white')
#determine_commanders() #determine_commanders()
#set_lands() #set_lands()

100
tagger.py
View file

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import os
import pandas as pd # type: ignore import pandas as pd # type: ignore
import settings import settings
@ -8,44 +9,45 @@ from settings import artifact_tokens, csv_directory, colors, counter_types, ench
from setup import regenerate_csv_by_color from setup import regenerate_csv_by_color
from utility import pluralize, sort_list from utility import pluralize, sort_list
karnstruct = '0/0 colorless Construct'
### Setup ### Setup
## Load the dataframe ## Load the dataframe
def load_dataframe(color): def load_dataframe(color):
# Setup an output file for card processing """Load and validate the card dataframe for a given color"""
"""f = open(f'tag_output/{color}_tagging.txt', 'w+') try:
f.write(f'Begin tagging {color}_cards.csv.\n') filepath = f'{csv_directory}/{color}_cards.csv'
f.close()"""
# Check if file exists, regenerate if needed
# Iterate through the defined {color}_cards.csv file to find spells matter cards if not os.path.exists(filepath):
print(f'Loading {color}_cards.csv as a pandas dataframe.\n')
# Setup dataframe
while True:
try:
with open(f'{csv_directory}/{color}_cards.csv', 'r', encoding='utf-8') as f:
print(f'{color}_cards.csv found.')
f.close()
break
except FileNotFoundError:
print(f'{color}_cards.csv not found, regenerating it.') print(f'{color}_cards.csv not found, regenerating it.')
regenerate_csv_by_color(color) regenerate_csv_by_color(color)
check_df = pd.read_csv(f'{csv_directory}/{color}_cards.csv')
column_checks = ['creatureTypes', 'themeTags'] # Load initial dataframe for validation
if 'themeTags' not in check_df.columns or 'creatureTypes' not in check_df.columns: check_df = pd.read_csv(filepath)
for column in column_checks:
if column in check_df.columns: # Validate required columns
print(f'"{column}" column in {color}_cards.csv.') required_columns = ['creatureTypes', 'themeTags']
elif column not in check_df.columns: missing_columns = [col for col in required_columns if col not in check_df.columns]
print(f'"{column}" column not found in {color}_cards.csv.\n')
if column == 'creatureTypes': # Handle missing columns
kindred_tagging(check_df, color) if missing_columns:
if column == 'themeTags': print(f"Missing columns: {missing_columns}")
create_theme_tags(check_df, color) if 'creatureTypes' not in check_df.columns:
if 'themeTags' in check_df.columns and 'creatureTypes' in check_df.columns: kindred_tagging(check_df, color)
df = pd.read_csv(f'{csv_directory}/{color}_cards.csv', converters={'themeTags': pd.eval, 'creatureTypes': pd.eval}) if 'themeTags' not in check_df.columns:
create_theme_tags(check_df, color)
tag_by_color(df, color)
# Load final dataframe with proper converters
df = pd.read_csv(filepath, converters={'themeTags': pd.eval, 'creatureTypes': pd.eval})
# Process the dataframe
tag_by_color(df, color)
except FileNotFoundError as e:
print(f'Error: {e}')
except pd.errors.ParserError:
print('Error parsing the CSV file.')
except Exception as e:
print(f'An unexpected error occurred: {e}')
## Tag cards on a color-by-color basis ## Tag cards on a color-by-color basis
def tag_by_color(df, color): def tag_by_color(df, color):
@ -130,6 +132,7 @@ def kindred_tagging(df, color):
df.at[index, 'creatureTypes'] = kindred_tags df.at[index, 'creatureTypes'] = kindred_tags
print(f'Creature types set in {color}_cards.csv.\n') print(f'Creature types set in {color}_cards.csv.\n')
print('==========\n') print('==========\n')
# Set outlaws # Set outlaws
print(f'Checking for and setting Outlaw types in {color}_cards.csv') print(f'Checking for and setting Outlaw types in {color}_cards.csv')
outlaws = ['Assassin', 'Mercenary', 'Pirate', 'Rogue', 'Warlock'] outlaws = ['Assassin', 'Mercenary', 'Pirate', 'Rogue', 'Warlock']
@ -144,19 +147,17 @@ def kindred_tagging(df, color):
df.at[index, 'creatureTypes'] = kindred_tags df.at[index, 'creatureTypes'] = kindred_tags
print(f'Outlaw types set in {color}_cards.csv.\n') print(f'Outlaw types set in {color}_cards.csv.\n')
print('==========\n') print('==========\n')
# Check for creature types in text (i.e. how 'Voja, Jaws of the Conclave' cares about Elves) # Check for creature types in text (i.e. how 'Voja, Jaws of the Conclave' cares about Elves)
print(f'Checking for and setting creature types found in the text of cards in {color}_cards.csv') print(f'Checking for and setting creature types found in the text of cards in {color}_cards.csv')
for index, row in df.iterrows(): for index, row in df.iterrows():
kindred_tags = row['creatureTypes'] kindred_tags = row['creatureTypes']
if pd.isna(row['text']): if pd.isna(row['text']):
continue continue
split_text = row['text'].split() split_text = row['text'].split()
ignore_list = ['Elite Inquisitor', 'Breaker of Armies', 'Cleopatra, Exiled Pharaoh', 'Nath\'s Buffoon']
for creature_type in settings.creature_types: for creature_type in settings.creature_types:
if ('Elite Inquisitor' in row['name'] if row['name'] in ignore_list:
or 'Breaker of Armies' in row['name']
or 'Cleopatra, Exiled Pharaoh' in row['name']
or 'Nath\'s Buffoon' in row['name']):
continue continue
if creature_type in row['name']: if creature_type in row['name']:
continue continue
@ -167,8 +168,6 @@ def kindred_tagging(df, color):
if creature_type not in row['name']: if creature_type not in row['name']:
if creature_type not in kindred_tags: if creature_type not in kindred_tags:
kindred_tags.append(creature_type) kindred_tags.append(creature_type)
if creature_type in outlaws:
kindred_tags.append(creature_type)
df.at[index, 'creatureTypes'] = kindred_tags df.at[index, 'creatureTypes'] = kindred_tags
# Tag for pluralized types (i.e. Elves, Wolves, etc...) in textbox # Tag for pluralized types (i.e. Elves, Wolves, etc...) in textbox
@ -176,10 +175,9 @@ def kindred_tagging(df, color):
if pluralize(f'{creature_type}') not in row['name']: if pluralize(f'{creature_type}') not in row['name']:
if creature_type not in kindred_tags: if creature_type not in kindred_tags:
kindred_tags.append(creature_type) kindred_tags.append(creature_type)
if creature_type in outlaws:
kindred_tags.append(creature_type)
df.at[index, 'creatureTypes'] = kindred_tags df.at[index, 'creatureTypes'] = kindred_tags
print(f'Creature types from text set in {color}_cards.csv.\n') print(f'Creature types from text set in {color}_cards.csv.\n')
# Overwrite file with creature type tags # Overwrite file with creature type tags
columns_to_keep = ['name', 'faceName','edhrecRank', 'colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'creatureTypes', 'text', 'power', 'toughness', 'keywords'] columns_to_keep = ['name', 'faceName','edhrecRank', 'colorIdentity', 'colors', 'manaCost', 'manaValue', 'type', 'creatureTypes', 'text', 'power', 'toughness', 'keywords']
df = df[columns_to_keep] df = df[columns_to_keep]
@ -256,6 +254,24 @@ def add_creatures_to_tags(df, color):
# Overwrite file with kindred tags added # Overwrite file with kindred tags added
print(f'Creature types added to theme tags in {color}_cards.csv.\n') print(f'Creature types added to theme tags in {color}_cards.csv.\n')
print('==========\n')
# Set Kindred Support
print(f'Checking for and setting Kindred Support tag in {color}_cards.csv')
all_kindred = ['changeling', 'choose a creature type', 'shares a creature type',
'shares at least one creature type', 'you control of the chosen type']
for index, row in df.iterrows():
if pd.isna(row['text']):
continue
theme_tags = row['themeTags']
#if all_kindred in row['text'].lower():
for item in all_kindred:
if item in row['text'].lower():
if 'Kindred Support' not in theme_tags:
theme_tags.extend(['Kindred Support'])
df.at[index, 'themeTags'] = theme_tags
print(f'"Kindred Support" tag set in {color}_cards.csv.\n')
## Add keywords to theme tags ## Add keywords to theme tags
def tag_for_keywords(df, color): def tag_for_keywords(df, color):