Merge branch 'PAK90-master'

This commit is contained in:
Bill Zorn 2015-08-11 00:16:19 -07:00
commit 77835f9f08
3 changed files with 171 additions and 8 deletions

View file

@ -1,6 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys import sys
import os import os
import zipfile
import shutil
libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib') libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib')
sys.path.append(libdir) sys.path.append(libdir)
@ -14,7 +16,8 @@ def exclude_sets(cardset):
return cardset == 'Unglued' or cardset == 'Unhinged' or cardset == 'Celebration' return cardset == 'Unglued' or cardset == 'Unhinged' or cardset == 'Celebration'
def main(fname, oname = None, verbose = True, def main(fname, oname = None, verbose = True,
gatherer = False, for_forum = False, creativity = False, norarity = False): gatherer = False, for_forum = False, for_mse = False,
creativity = False, norarity = False):
cards = [] cards = []
valid = 0 valid = 0
invalid = 0 invalid = 0
@ -107,9 +110,19 @@ def main(fname, oname = None, verbose = True,
namediff = Namediff() namediff = Namediff()
def writecards(writer): def writecards(writer):
if for_mse:
# have to prepend a massive chunk of formatting info
writer.write(utils.mse_prepend)
for card in cards: for card in cards:
writer.write((card.format(gatherer = gatherer, for_forum = for_forum)).encode('utf-8')) if for_mse:
writer.write(card.to_mse().encode('utf-8'))
else:
writer.write(card.format(gatherer = gatherer,
for_forum = for_forum).encode('utf-8'))
if creativity: if creativity:
if for_mse:
writer.write('\tnotes:\n\t\t'.encode('utf-8'))
writer.write('~~ closest cards ~~\n'.encode('utf-8')) writer.write('~~ closest cards ~~\n'.encode('utf-8'))
nearest = cbow.nearest(card) nearest = cbow.nearest(card)
for dist, cardname in nearest: for dist, cardname in nearest:
@ -126,11 +139,31 @@ def main(fname, oname = None, verbose = True,
writer.write((cardname + ': ' + str(dist) + '\n').encode('utf-8')) writer.write((cardname + ': ' + str(dist) + '\n').encode('utf-8'))
writer.write('\n'.encode('utf-8')) writer.write('\n'.encode('utf-8'))
if for_mse:
# more formatting info
writer.write('version control:\n\ttype: none\napprentice code: ')
if oname: if oname:
if verbose: if verbose:
print 'Writing output to: ' + oname print 'Writing output to: ' + oname
with open(oname, 'w') as ofile: with open(oname, 'w') as ofile:
writecards(ofile) writecards(ofile)
if for_mse:
# Copy whatever output file is produced, name the copy 'set' (yes, no extension).
if os.path.isfile('set'):
print 'ERROR: tried to overwrite existing file "set" - aborting.'
return
shutil.copyfile(oname, 'set')
# Use the freaky mse extension instead of zip.
with zipfile.ZipFile(oname+'.mse-set', mode='w') as zf:
try:
# Zip up the set file into oname.mse-set.
zf.write('set')
finally:
if verbose:
print 'Made an MSE set file called ' + oname + '.mse-set.'
# The set file is useless outside the .mse-set, delete it.
os.remove('set')
else: else:
writecards(sys.stdout) writecards(sys.stdout)
sys.stdout.flush() sys.stdout.flush()
@ -154,9 +187,10 @@ if __name__ == '__main__':
help='the card format has no rarity field; use for legacy input') help='the card format has no rarity field; use for legacy input')
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
help='verbose output') help='verbose output')
parser.add_argument('-mse', '--mse', action='store_true', help='use Magic Set Editor 2 encoding; will output as .mse-set file')
args = parser.parse_args() args = parser.parse_args()
main(args.infile, args.outfile, verbose = args.verbose, main(args.infile, args.outfile, verbose = args.verbose,
gatherer = args.gatherer, for_forum = args.forum, creativity = args.creativity, gatherer = args.gatherer, for_forum = args.forum, for_mse = args.mse,
norarity = args.norarity) creativity = args.creativity, norarity = args.norarity)
exit(0) exit(0)

View file

@ -17,6 +17,11 @@ try:
import textwrap import textwrap
import nltk.data import nltk.data
sent_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') sent_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
# This could me made smarter - MSE will capitalize for us after :,
# but we still need to capitalize the first english component of an activation
# cost that starts with symbols, such as {2U}, *R*emove a +1/+1 counter from @: etc.
def cap(s):
return s[:1].capitalize() + s[1:]
# This crazy thing is actually invoked as an unpass, so newlines are still # This crazy thing is actually invoked as an unpass, so newlines are still
# encoded. # encoded.
def sentencecase(s): def sentencecase(s):
@ -26,11 +31,26 @@ try:
for line in lines: for line in lines:
if line: if line:
sentences = sent_tokenizer.tokenize(line) sentences = sent_tokenizer.tokenize(line)
clines += [' '.join([sent.capitalize() for sent in sentences])] clines += [' '.join([cap(sent) for sent in sentences])]
return utils.newline.join(clines).replace(utils.reserved_marker, utils.x_marker) return utils.newline.join(clines).replace(utils.reserved_marker, utils.x_marker)
except ImportError: except ImportError:
# non-nltk implementation provided by PAK90
def uppercaseNewLineAndFullstop(string):
# ok, let's capitalize every letter after a full stop and newline.
# first let's find all indices of '.' and '\n'
indices = [0] # initialise with 0, since we always want to capitalise the first letter.
newlineIndices = [0] # also need to keep track of pure newlines (for planeswalkers).
for i in range (len(string)):
if string[i] == '\\':
indices.append(i + 1) # we want the index of the letter after the \n, so add one.
newlineIndices.append(i + 1)
if string[i] == '.' or string[i] == "=": # also handle the choice bullets.
indices.append(i + 2) # we want the index of the letter after the ., so we need to count the space as well.
indexSet = set(indices) # convert it to a set for the next part; the capitalisation.
return "".join(c.upper() if i in indexSet else c for i, c in enumerate(string))
def sentencecase(s): def sentencecase(s):
return s return uppercaseNewLineAndFullstop(s)
# These are used later to determine what the fields of the Card object are called. # These are used later to determine what the fields of the Card object are called.
# Define them here because they have nothing to do with the actual format. # Define them here because they have nothing to do with the actual format.
@ -109,6 +129,7 @@ def fields_check_valid(fields):
else: else:
return not field_pt in fields return not field_pt in fields
# These functions take a bunch of source data in some format and turn # These functions take a bunch of source data in some format and turn
# it into nicely labeled fields that we know how to initialize a card from. # it into nicely labeled fields that we know how to initialize a card from.
# Both return a dict that maps field names to lists of possible values, # Both return a dict that maps field names to lists of possible values,
@ -141,7 +162,7 @@ def fields_check_valid(fields):
# layout - string # layout - string
# rarity - string # rarity - string
# flavor - string # flavor - string
# artis - string # artist - string
# number - string # number - string
# multiverseid - number # multiverseid - number
# variations - list # variations - list
@ -530,7 +551,7 @@ class Card:
return outstr return outstr
def format(self, gatherer = False, for_forum = False): def format(self, gatherer = False, for_forum = False, for_mse = False):
outstr = '' outstr = ''
if gatherer: if gatherer:
cardname = titlecase(self.__dict__[field_name]) cardname = titlecase(self.__dict__[field_name])
@ -663,6 +684,111 @@ class Card:
return outstr return outstr
def to_mse(self):
outstr = ''
# need a 'card' string first
outstr += 'card:\n'
cardname = titlecase(self.__dict__[field_name])
outstr += '\tname: ' + cardname + '\n'
if self.__dict__[field_rarity]:
if self.__dict__[field_rarity] in utils.json_rarity_unmap:
rarity = utils.json_rarity_unmap[self.__dict__[field_rarity]]
else:
rarity = self.__dict__[field_rarity]
outstr += '\trarity: ' + rarity.lower() + '\n'
#if not self.parsed:
# outstr += ' _UNPARSED_'
#if not self.valid:
# outstr += ' _INVALID_'
if not self.__dict__[field_cost].none:
outstr += '\tcasting cost: ' + self.__dict__[field_cost].format().replace('{','').replace('}','')
outstr += '\n'
outstr += '\tsuper type: ' + ' '.join(self.__dict__[field_supertypes]
+ self.__dict__[field_types]).title() + '\n'
if self.__dict__[field_subtypes]:
outstr += '\tsub type: ' + ' '.join(self.__dict__[field_subtypes]).title() + '\n'
if self.__dict__[field_text].text:
mtext = self.__dict__[field_text].text
mtext = transforms.text_unpass_1_choice(mtext, delimit = False)
mtext = transforms.text_unpass_2_counters(mtext)
mtext = transforms.text_unpass_3_unary(mtext)
mtext = transforms.text_unpass_4_symbols(mtext, False)
mtext = sentencecase(mtext)
# I don't really want these MSE specific passes in transforms,
# but they could be pulled out separately somewhere else in here.
mtext = mtext.replace(utils.this_marker, '<atom-cardname><nospellcheck>'
+ utils.this_marker + '</nospellcheck></atom-cardname>')
mtext = transforms.text_unpass_5_cardname(mtext, cardname)
mtext = transforms.text_unpass_6_newlines(mtext)
newtext = Manatext('')
newtext.text = mtext
newtext.costs = self.__dict__[field_text].costs
newtext = newtext.format()
#NOT NEEDED newtext = newtext.replace(utils.this_marker, cardname) # first let's put the cardname where all the @s are.
# newtext = newtext.replace(utils.counter_rename + ".", "countered.") # then replace any 'uncast' at the end of a sentence with 'countered'.
# newtext = newtext.replace(utils.dash_marker, u'\u2014') # also replace the ~ with a u2014 for choices.
# newtext = newtext.replace(utils.counter_rename, "counter") # then replace all the mid-sentence 'uncast' with 'counter'.
# newtext = newtext.replace('{','<sym-auto>').replace('}','</sym-auto>') # now we encase mana/tap symbols with the correct tags for mse.
# linecount = newtext.count('\n') + 1 # adding 1 because no newlines means 1 line, 1 newline means 2 lines etc.
# newtext = sentencecase(newtext) # make all the things uppercase!
# # done after uppercasing everything because string[i] == u2022 doesn't work apparently.
# newtext = newtext.replace(utils.bullet_marker, u'\u2022') # replace the = with a u2022.
# used later
linecount = newtext.count('\n') + 1 # adding 1 because no newlines means 1 line, 1 newline means 2 lines etc.
# actually really important
newtext = newtext.replace('{','<sym-auto>').replace('}','</sym-auto>') # now we encase mana/tap symbols with the correct tags for mse.
newlineIndices = [0] # also need to keep track of pure newlines (for planeswalkers).
for i in range (len(newtext)):
if newtext[i] == '\n':
newlineIndices.append(i + 1)
# need to do Special Things if it's a planeswalker.
if "planeswalker" in str(self.__dict__[field_types]): # for some reason this is in types, not supertypes...
outstr += '\tstylesheet: m15-planeswalker\n' # set the proper card style for a 3-line walker.
# set up the loyalty cost fields using regex to find how many there are.
i = 0
lcost_regex = r'[-+]?\d+: ' # 1+ figures, might be 0.
for costs in re.findall(lcost_regex, newtext):
i += 1
outstr += '\tloyalty cost ' + str(i) + ': ' + costs + '\n'
# sub out the loyalty costs.
newtext = re.sub(lcost_regex, '', newtext)
#newtext = sentencecase(newtext) # we need to uppercase again; previous uppercase call didn't work due to loyalty costs being there.
if self.__dict__[field_loyalty]:
outstr += '\tloyalty: ' + utils.from_unary(self.__dict__[field_loyalty]) + '\n'
newtext = newtext.replace('\n','\n\t\t')
outstr += '\trule text:\n\t\t' + newtext + '\n'
if self.__dict__[field_pt]:
ptstring = utils.from_unary(self.__dict__[field_pt]).split('/')
if (len(ptstring) > 1): #really don't want to be accessing anything nonexistent.
outstr += '\tpower: ' + ptstring[0] + '\n'
outstr += '\ttoughness: ' + ptstring[1] + '\n'
#outstr += '\n'
# now append all the other useless fields that the setfile expects.
outstr += '\thas styling: false\n\tnotes:\n\ttime created:2015-07-20 22:53:07\n\ttime modified:2015-07-20 22:53:08\n\textra data:\n\timage:\n\tcard code text:\n\tcopyright:\n\timage 2:\n\tcopyright 2: '
return outstr
def vectorize(self): def vectorize(self):
ld = '(' ld = '('
rd = ')' rd = ')'

View file

@ -6,6 +6,9 @@ import re
import config import config
# special chunk of text that Magic Set Editor 2 requires at the start of all set files.
mse_prepend = 'mse version: 0.3.8\ngame: magic\nstylesheet: m15\nset info:\n\tsymbol:\nstyling:\n\tmagic-m15:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay:\n\tmagic-m15-clear:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-m15-extra-improved:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\tpt box symbols: magic-pt-symbols-extra.mse-symbol-font\n\t\toverlay: \n\tmagic-m15-planeswalker:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-m15-planeswalker-promo-black:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-m15-promo-dka:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-m15-token-clear:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-new-planeswalker:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-new-planeswalker-4abil:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-new-planeswalker-clear:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n\tmagic-new-planeswalker-promo-black:\n\t\ttext box mana symbols: magic-mana-small.mse-symbol-font\n\t\toverlay: \n'
# separators # separators
cardsep = config.cardsep cardsep = config.cardsep
fieldsep = config.fieldsep fieldsep = config.fieldsep