cubescripts/word_count.py
Dan Niemitalo e17e9a349c 2024 Fixes
1) The CubeCobra CSV headers have changed slightly, capitalizing some words.
2) Cards in the maybeboard should not be included in the averages, so this filters them out.
3) Minor simplifications made to the keyword and word count analysis files to make it a bit easier for amateurs like me to figure out how to run these scripts.
2024-06-09 10:18:30 -05:00

208 lines
No EOL
6.1 KiB
Python

import json
from collections import defaultdict
import cube_json
import cubecobra_csv
def load_cube_from_txt(filename):
f_cube_list = open(filename)
cards = []
for line in f_cube_list:
cards += [line.strip()]
return cards
TEMP_JSON = 'cube_temp.json'
ALL_CARDS_CLEAN_JSON = 'oracle_cards_clean.json'
EXPECTED_HEADER = [
'Name',
'CMC',
'Type',
'Color',
'Set',
'Collector Number',
'Rarity',
'Color Category',
'Status',
'Finish',
'Maybeboard',
'Image URL',
'Image Back URL',
'Tags',
'Notes',
'MTGO ID'
]
COLUMNS = {column_name: i for i, column_name in enumerate(EXPECTED_HEADER)}
def is_actual_mtg_card(card_dict):
return card_dict['set_type'] not in {'memorabilia', 'funny', 'token'}
def create_all_cards_json():
with open('oracle_cards.json', encoding='utf8') as f_oracle_cards:
d = json.load(f_oracle_cards)
output_filename = ALL_CARDS_CLEAN_JSON
f_cube_json = open(output_filename, 'w+', encoding='utf8')
cube_data = []
for card in d:
if is_actual_mtg_card(card):
cube_data += [card]
string_data = json.dumps(cube_data)
f_cube_json.write(string_data)
f_cube_json.close()
return ALL_CARDS_CLEAN_JSON
def wc_fo(text):
# full oracle text word count
return len(text.split())
def wc_o(text):
# word count of oracle text without keyword explanation text
if "(" in text and ")" in text:
p1 = text.find("(")
p2 = text.find(")")
o = text[:p1] + text[p2 + 1:]
return wc_o(o)
else:
return len(text.split())
def word_count(card, *, full_oracle):
if full_oracle:
wc = wc_fo
else:
wc = wc_o
if 'card_faces' in card.keys():
total_count = 0
for face in card['card_faces']:
text = face['oracle_text']
total_count += wc(text)
return total_count
else:
text = card['oracle_text']
return wc(text)
def cube_word_count(filename, *, full_oracle):
with open(filename, encoding='utf8') as f:
d = json.load(f)
wc = []
for card in d:
words = word_count(card, full_oracle=full_oracle)
wc += [words]
mean = sum(wc) / len(wc)
if full_oracle:
metric = 'Avg Words/Card (full text)'
else:
metric = 'Avg Words/Card (no reminders)'
print(f"{metric}: {mean:.1f}")
return mean
def duplicate_count(filename):
with open(filename, encoding='utf8') as f:
d = json.load(f)
unique = []
for card in d:
if card['name'] not in unique:
unique += [card['name']]
print(f"{len(unique)} unique of {len(d)} total cards")
WHEEL = str.maketrans('WUBRG', '01234')
def wheel_order(colors):
return colors.translate(WHEEL)
def print_by_color(filename, *, rank_cards, full_oracle):
cards_by_color_identity = defaultdict(list)
with open(filename, encoding='utf8') as f:
d = json.load(f)
for card in d:
words = word_count(card, full_oracle=full_oracle)
if 'Land' in card['type_line'].split('//')[0]:
identity = 'Non-basic land'
elif len(card['color_identity']) > 1:
identity = 'Multicolor'
else:
identity = ''.join(card['color_identity'])
cards_by_color_identity[identity].append((card['name'], words))
# pp(cards_by_color_identity)
# sort first by fewest colors in identity, then by WUBRG order
for identity, card_tuples in sorted(cards_by_color_identity.items(), key=lambda t:(len(t[0]), wheel_order(t[0]))):
total_words = sum(words for _, words in card_tuples)
card_count = len(card_tuples)
average_words = total_words / card_count
identity_name = 'Non-land colorless' if not identity else identity
print(f"{identity_name }: average {average_words:.2f} [of {card_count} cards]")
if rank_cards:
for card_name, card_words in sorted(card_tuples, key=lambda t: t[1], reverse=True):
print(f'{card_name}: {card_words}')
print()
print()
def get_text(card):
if 'oracle_text' in card.keys():
return card['oracle_text']
elif 'card_faces' in card.keys():
text = ""
for face in card['card_faces']:
text += face['oracle_text'] + ' '
return text
if __name__ == '__main__':
################################################################################
full_oracle = False
################################################################################
# Use either option:
# 1. If you have your cube in Cube Cobra and want to filter per tag
# csv_path = cubecobra_csv.request_cube_csv('TheElegantCube_fetched', 'elegant')
# cube_list = cubecobra_csv.load_cube_names(csv_path)
# 2. If you have your cube in Cube Cobra and want to consider only cards with a certain tag
cube_id = 'jeskaicube'
csv_path = cubecobra_csv.request_cube_csv(cube_id, cube_id)
cube_list = cubecobra_csv.load_cube_names(csv_path, tag_filter=None)
# 3. If you have a .txt of your cube
# cube_list = cube_json.load_cube_from_txt('YourCubeHere.txt')
################################################################################
# Calculate average of a cube
cube_json_handle = cube_json.create_cube_json(cube_list)
# Summary of average words by color
print_by_color(cube_json_handle, rank_cards=False, full_oracle=full_oracle)
# Individual cards by color, ranked by word count
print_by_color(cube_json_handle, rank_cards=True, full_oracle=full_oracle)
# Average words excluding reminder text
cube_word_count(cube_json_handle, full_oracle=False)
# Average words in full oracle text
cube_word_count(cube_json_handle, full_oracle=True)
################################################################################
# Calculate average of all Magic cards
# card_db_json_handle = create_all_cards_json()
# print_by_color(card_db_json_handle, rank_cards=True, full_oracle=full_oracle)
# cube_word_count(card_db_json_handle, full_oracle=full_oracle)
################################################################################
pass