174 lines
6.4 KiB
Python
174 lines
6.4 KiB
Python
|
# representation for mana costs and text with embedded mana costs
|
||
|
# data aggregating classes
|
||
|
import random
|
||
|
import re
|
||
|
|
||
|
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):
|
||
|
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence)
|
||
|
+ utils.mana_close_delimiter)
|
||
|
|
||
|
def format(self, for_forum = False):
|
||
|
return utils.mana_untranslate(utils.mana_open_delimiter + ''.join(self.sequence, for_forum)
|
||
|
+ utils.mana_close_delimiter)
|
||
|
|
||
|
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
|
||
|
|
||
|
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
|