mtgencode/lib/manalib.py

216 lines
7.8 KiB
Python

# representation for mana costs and text with embedded mana costs
# data aggregating classes
import re
import random
import utils
class Manacost:
'''mana cost representation with data'''
# hardcoded to be dependent on the symbol structure... ah well
def get_colors(self):
colors = ''
for sym in self.symbols:
if self.symbols[sym] > 0:
symcolors = re.sub(r'2|P|S|X|C', '', sym)
for symcolor in symcolors:
if symcolor not in colors:
colors += symcolor
# sort so the order is always consistent
return ''.join(sorted(colors))
def check_colors(self, symbolstring):
for sym in symbolstring:
if not sym in self.colors:
return False
return True
def __init__(self, src, fmt = ''):
# source fields, exactly one will be set
self.raw = None
self.json = None
# flags
self.parsed = True
self.valid = True
self.none = False
# default values for all fields
self.inner = None
self.cmc = 0
self.colorless = 0
self.sequence = []
self.symbols = {sym : 0 for sym in utils.mana_syms}
self.allsymbols = {sym : 0 for sym in utils.mana_symall}
self.colors = ''
if fmt == 'json':
self.json = src
text = utils.mana_translate(self.json.upper())
else:
self.raw = src
text = self.raw
if text == '':
self.inner = ''
self.none = True
elif not (len(text) >= 2 and text[0] == '{' and text[-1] == '}'):
self.parsed = False
self.valid = False
else:
self.inner = text[1:-1]
# structure mirrors the decoding in utils, but we pull out different data here
idx = 0
while idx < len(self.inner):
# taking this branch is an infinite loop if unary_marker is empty
if (len(utils.mana_unary_marker) > 0 and
self.inner[idx:idx+len(utils.mana_unary_marker)] == utils.mana_unary_marker):
idx += len(utils.mana_unary_marker)
self.sequence += [utils.mana_unary_marker]
elif self.inner[idx:idx+len(utils.mana_unary_counter)] == utils.mana_unary_counter:
idx += len(utils.mana_unary_counter)
self.sequence += [utils.mana_unary_counter]
self.colorless += 1
self.cmc += 1
else:
old_idx = idx
for symlen in range(utils.mana_symlen_min, utils.mana_symlen_max + 1):
encoded_sym = self.inner[idx:idx+symlen]
if encoded_sym in utils.mana_symall_decode:
idx += symlen
# leave the sequence encoded for convenience
self.sequence += [encoded_sym]
sym = utils.mana_symall_decode[encoded_sym]
self.allsymbols[sym] += 1
if sym in utils.mana_symalt:
self.symbols[utils.mana_alt(sym)] += 1
else:
self.symbols[sym] += 1
if sym == utils.mana_X:
self.cmc += 0
elif utils.mana_2 in sym:
self.cmc += 2
else:
self.cmc += 1
break
# otherwise we'll go into an infinite loop if we see a symbol we don't know
if idx == old_idx:
idx += 1
self.valid = False
self.colors = self.get_colors()
def __str__(self):
if self.none:
return '_NOCOST_'
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence)
+ utils.mana_close_delimiter)
def format(self, for_forum = False, for_html = False):
if self.none:
return '_NOCOST_'
else:
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence)
+ utils.mana_close_delimiter, for_forum, for_html)
def encode(self, randomize = False):
if self.none:
return ''
elif randomize:
# so this won't work very well if mana_unary_marker isn't empty
return (utils.mana_open_delimiter
+ ''.join(random.sample(self.sequence, len(self.sequence)))
+ utils.mana_close_delimiter)
else:
return utils.mana_open_delimiter + ''.join(self.sequence) + utils.mana_close_delimiter
def vectorize(self, delimit = False):
if self.none:
return ''
elif delimit:
ld = '('
rd = ')'
else:
ld = ''
rd = ''
return ' '.join(map(lambda s: ld + s + rd, sorted(self.sequence)))
class Manatext:
'''text representation with embedded mana costs'''
def __init__(self, src, fmt = ''):
# source fields
self.raw = None
self.json = None
# flags
self.valid = True
# default values for all fields
self.text = src
self.costs = []
if fmt == 'json':
self.json = src
manastrs = re.findall(utils.mana_json_regex, src)
else:
self.raw = src
manastrs = re.findall(utils.mana_regex, src)
for manastr in manastrs:
cost = Manacost(manastr, fmt)
if not cost.valid:
self.valid = False
self.costs += [cost]
self.text = self.text.replace(manastr, utils.reserved_mana_marker, 1)
if (utils.mana_open_delimiter in self.text
or utils.mana_close_delimiter in self.text
or utils.mana_json_open_delimiter in self.text
or utils.mana_json_close_delimiter in self.text):
self.valid = False
def __str__(self):
text = self.text
for cost in self.costs:
text = text.replace(utils.reserved_mana_marker, str(cost), 1)
return text
def format(self, for_forum = False, for_html = False):
text = self.text
for cost in self.costs:
text = text.replace(utils.reserved_mana_marker, cost.format(for_forum=for_forum, for_html=for_html), 1)
if for_html:
text = text.replace('\n', '<br>\n')
return text
def encode(self, randomize = False):
text = self.text
for cost in self.costs:
text = text.replace(utils.reserved_mana_marker, cost.encode(randomize = randomize), 1)
return text
def vectorize(self):
text = self.text
special_chars = [utils.reserved_mana_marker,
utils.dash_marker,
utils.bullet_marker,
utils.this_marker,
utils.counter_marker,
utils.choice_open_delimiter,
utils.choice_close_delimiter,
utils.newline,
#utils.x_marker,
utils.tap_marker,
utils.untap_marker,
utils.newline,
';', ':', '"', ',', '.']
for char in special_chars:
text = text.replace(char, ' ' + char + ' ')
text = text.replace('/', '/ /')
for cost in self.costs:
text = text.replace(utils.reserved_mana_marker, cost.vectorize(), 1)
return ' '.join(text.split())