mtgencode/scripts/pairing.py
2015-12-06 20:45:52 -08:00

159 lines
5.2 KiB
Python
Executable file

#!/usr/bin/env python
import sys
import os
import random
import zipfile
import shutil
libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib')
sys.path.append(libdir)
datadir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../data')
import utils
import jdecode
import ngrams
import analysis
import mtg_validate
from cbow import CBOW
separate_lines=True
def select_card(cards, stats, i):
card = cards[i]
nearest = stats['dists']['cbow'][i]
perp = stats['ngram']['perp'][i]
perp_per = stats['ngram']['perp_per'][i]
perp_max = stats['ngram']['perp_max'][i]
if nearest > 0.9 or perp_per > 2.0 or perp_max > 10.0:
return None
((_, total_good, _, _), _) = mtg_validate.process_props([card])
if not total_good == 1:
return False
# print '===='
# print nearest
# print perp
# print perp_per
# print perp_max
# print '----'
# print card.format()
return True
def compare_to_real(card, realcard):
ctypes = ' '.join(sorted(card.types))
rtypes = ' '.join(sorted(realcard.types))
return ctypes == rtypes and realcard.cost.check_colors(card.cost.get_colors())
def writecard(card, name, writer):
gatherer = False
for_forum = True
vdump = True
fmt = card.format(gatherer = gatherer, for_forum = for_forum, vdump = vdump)
oldname = card.name
# alter name used in image
card.name = name
writer.write(card.to_mse().encode('utf-8'))
card.name = oldname
fstring = ''
if card.json:
fstring += 'JSON:\n' + card.json + '\n'
if card.raw:
fstring += 'raw:\n' + card.raw + '\n'
fstring += '\n'
fstring += fmt + '\n'
fstring = fstring.replace('<', '(').replace('>', ')')
writer.write(('\n' + fstring[:-1]).replace('\n', '\n\t\t').encode('utf-8'))
writer.write('\n'.encode('utf-8'))
def main(fname, oname, n=20, verbose=False):
cbow = CBOW()
realcards = jdecode.mtg_open_file(str(os.path.join(datadir, 'output.txt')), verbose=verbose)
real_by_name = {c.name: c for c in realcards}
lm = ngrams.build_ngram_model(realcards, 3, separate_lines=separate_lines, verbose=verbose)
cards = jdecode.mtg_open_file(fname, verbose=verbose)
stats = analysis.get_statistics(fname, lm=lm, sep=separate_lines, verbose=verbose)
selected = []
for i in range(0, len(cards)):
if select_card(cards, stats, i):
selected += [(i, cards[i])]
limit = 3000
random.shuffle(selected)
#selected = selected[:limit]
if verbose:
print('computing nearest cards for ' + str(len(selected)) + ' candindates...')
cbow_nearest = cbow.nearest_par(map(lambda (i, c): c, selected))
for i in range(0, len(selected)):
(j, card) = selected[i]
selected[i] = (j, card, cbow_nearest[i])
if verbose:
print('...done')
final = []
for (i, card, nearest) in selected:
for dist, rname in nearest:
realcard = real_by_name[rname]
if compare_to_real(card, realcard):
final += [(i, card, realcard, dist)]
break
for (i, card, realcard, dist) in final:
print '-- real --'
print realcard.format()
print '-- fake --'
print card.format()
print '-- stats --'
perp_per = stats['ngram']['perp_per'][i]
perp_max = stats['ngram']['perp_max'][i]
print dist
print perp_per
print perp_max
print '----'
if not oname is None:
with open(oname, 'wt') as ofile:
ofile.write(utils.mse_prepend)
for (i, card, realcard, dist) in final:
name = realcard.name
writecard(realcard, name, ofile)
writecard(card, name, ofile)
ofile.write('version control:\n\ttype: none\napprentice code: ')
# 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')
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('infile', #nargs='?'. default=None,
help='encoded card file or json corpus to process')
parser.add_argument('outfile', nargs='?', default=None,
help='output file, defaults to none')
parser.add_argument('-n', '--n', action='store',
help='number of cards to consider for each pairing')
parser.add_argument('-v', '--verbose', action='store_true',
help='verbose output')
args = parser.parse_args()
main(args.infile, args.outfile, n=args.n, verbose=args.verbose)
exit(0)