2015-07-14 07:07:25 +00:00
|
|
|
# representation for mana costs and text with embedded mana costs
|
|
|
|
# data aggregating classes
|
|
|
|
import re
|
2015-07-16 06:40:15 +00:00
|
|
|
import random
|
2015-07-14 07:07:25 +00:00
|
|
|
|
|
|
|
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', '', 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):
|
2015-07-23 08:04:40 +00:00
|
|
|
if self.none:
|
|
|
|
return '_NOCOST_'
|
2015-07-14 07:07:25 +00:00
|
|
|
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence)
|
|
|
|
+ utils.mana_close_delimiter)
|
|
|
|
|
|
|
|
def format(self, for_forum = False):
|
2015-07-23 08:04:40 +00:00
|
|
|
if self.none:
|
|
|
|
return '_NOCOST_'
|
|
|
|
else:
|
|
|
|
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence)
|
|
|
|
+ utils.mana_close_delimiter, for_forum)
|
2015-07-14 07:07:25 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2015-07-29 08:21:34 +00:00
|
|
|
def vectorize(self, delimit = False):
|
|
|
|
if self.none:
|
|
|
|
return ''
|
|
|
|
elif delimit:
|
|
|
|
ld = '('
|
|
|
|
rd = ')'
|
|
|
|
else:
|
|
|
|
ld = ''
|
|
|
|
rd = ''
|
|
|
|
return ' '.join(map(lambda s: ld + s + rd, self.sequence))
|
|
|
|
|
|
|
|
|
2015-07-14 07:07:25 +00:00
|
|
|
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):
|
|
|
|
text = self.text
|
|
|
|
for cost in self.costs:
|
|
|
|
text = text.replace(utils.reserved_mana_marker, cost.format(for_forum = for_forum), 1)
|
|
|
|
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
|
2015-07-29 08:21:34 +00:00
|
|
|
|
|
|
|
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())
|