From 110ac8473c1e42f53429c9a31395fda0ab5e0dae Mon Sep 17 00:00:00 2001 From: Bill Zorn Date: Mon, 6 Jul 2015 00:15:12 -0700 Subject: [PATCH] added base config file, it should work but it isn't used yet. otherwise things are back to normal. minor output updates, removed conspiracies --- config.py | 402 ++++++++++++++++++++++++++++++++++++++++++++++++++ encode.py | 20 +-- output.txt | 28 ---- unscramble.py | 2 +- 4 files changed, 413 insertions(+), 39 deletions(-) create mode 100644 config.py diff --git a/config.py b/config.py new file mode 100644 index 0000000..9551d4e --- /dev/null +++ b/config.py @@ -0,0 +1,402 @@ +import re + +# Don't be intimidated by the massive size of this file. It provides both the +# raw character decisions made about the encoding scheme as variables, and +# a bunch of tables and functions to make dealing with mana costs and unary +# numbers easier. For the most part the functions should adapt if you change +# the specific delimiters and markers used. + +# The decoding from mtgjson format is dependent on the specific structure of +# the internally used mana symbol strings, so if you want to change that you'll +# also have to change the json decoding functions. + +# separators +cardsep = '\n\n' +fieldsep = '|' +bsidesep = '\n' +newline = '\\' + +# special indicators +dash_marker = '~' +bullet_marker = '=' +this_marker = '@' +counter_marker = '%' +reserved_marker = '\r' +x_marker = 'X' +tap_marker = 'T' +untap_marker = 'Q' + +# unambiguous synonyms +counter_rename = 'uncast' + +# unicode / ascii conversion +unicode_trans = { + u'\u2014' : dash_marker, # unicode long dash + u'\u2022' : bullet_marker, # unicode bullet + u'\u2019' : '"', # single quote + u'\u2018' : '"', # single quote + u'\u2212' : '-', # minus sign + u'\xe6' : 'ae', # ae symbol + u'\xfb' : 'u', # u with caret + u'\xfa' : 'u', # u with accent + u'\xe9' : 'e', # e with accent + u'\xe1' : 'a', # a with accent + u'\xe0' : 'a', # a with accent going the other way + u'\xe2' : 'a', # a with caret + u'\xf6' : 'o', # o with umlaut + u'\xed' : 'i', # i with accent +} +# this one is one-way only +def to_ascii(s): + for uchar in unicode_trans: + s = s.replace(uchar, unicode_trans(uchar)) + return s + +# unary numbers +unary_marker = '&' +unary_counter = '^' +unary_max = 20 +unary_exceptions = { + 25 : 'twenty' + dash_marker + 'five', + 30 : 'thirty', + 40 : 'forty', + 50 : 'fifly', + 100: 'one hundred', + 200: 'two hundred', +} + +def to_unary(s, warn = False): + numbers = re.findall(r'[0123456789]+', s) + # replace largest first to avoid accidentally replacing shared substrings + for n in sorted(numbers, cmp = lambda x,y: cmp(int(x), int(y)), reverse = True): + i = int(n) + if i in unary_exceptions: + s = s.replace(n, unary_exceptions[n]) + elif i > unary_max: + i = unary_max + if warn: + print s + s = s.replace(n, unary_marker + unary_counter * i) + else: + s = s.replace(n, unary_marker + unary_counter * i) + return s + +def from_unary(s): + numbers = re.findall(re.escape(unary_marker + unary_counter) + '*', s) + # again, largest first so we don't replace substrings and break everything + for n in sorted(numbers, cmp = lambda x,y: cmp(len(x), len(y)), reverse = True): + i = (len(n) - len(unary_marker)) / len(unary_counter) + s = s.replace(n, str(i)) + return s + +# mana syntax +mana_open_delimiter = '{' +mana_close_delimiter = '}' +mana_json_open_delimiter = mana_open_delimiter +mana_json_close_delimiter = mana_close_delimiter +mana_json_hybrid_delimiter = '/' +mana_forum_open_delimiter = '[mana]' +mana_forum_close_delimiter = '[/mana]' +mana_unary_marker = '' # if the same as unary_marker, from_unary WILL replace numbers in mana costs +mana_unary_counter = unary_counter + +# individual mana symbols +mana_W = 'W' # single color +mana_U = 'U' +mana_B = 'B' +mana_R = 'R' +mana_G = 'G' +mana_P = 'P' # colorless phyrexian +mana_S = 'S' # snow +mana_X = 'X' # colorless X +mana_WP = 'WP' # single color phyrexian +mana_UP = 'UP' +mana_BP = 'BP' +mana_RP = 'RP' +mana_GP = 'GP' +mana_2W = '2W' # single color hybrid +mana_2U = '2U' +mana_2B = '2B' +mana_2R = '2R' +mana_2G = '2G' +mana_WU = 'WU' # dual color hybrid +mana_WB = 'WB' +mana_RW = 'RW' +mana_GW = 'GW' +mana_UB = 'UB' +mana_UR = 'UR' +mana_GU = 'GU' +mana_BR = 'BR' +mana_BG = 'BG' +mana_RG = 'RG' +# alternative order symbols +mana_WP_alt = 'PW' # single color phyrexian +mana_UP_alt = 'PU' +mana_BP_alt = 'PB' +mana_RP_alt = 'PR' +mana_GP_alt = 'PG' +mana_2W_alt = 'W2' # single color hybrid +mana_2U_alt = 'U2' +mana_2B_alt = 'B2' +mana_2R_alt = 'R2' +mana_2G_alt = 'G2' +mana_WU_alt = 'UW' # dual color hybrid +mana_WB_alt = 'BW' +mana_RW_alt = 'WR' +mana_GW_alt = 'WG' +mana_UB_alt = 'BU' +mana_UR_alt = 'RU' +mana_GU_alt = 'UG' +mana_BR_alt = 'RB' +mana_BG_alt = 'GB' +mana_RG_alt = 'GR' +# special +mana_2 = '2' # use with 'in' to identify single color hybrid + +# master symbol lists +mana_syms = [ + mana_W, + mana_U, + mana_B, + mana_R, + mana_G, + mana_P, + mana_S, + mana_X, + mana_WP, + mana_UP, + mana_BP, + mana_RP, + mana_GP, + mana_2W, + mana_2U, + mana_2B, + mana_2R, + mana_2G, + mana_WU, + mana_WB, + mana_RW, + mana_GW, + mana_UB, + mana_UR, + mana_GU, + mana_BR, + mana_BG, + mana_RG, +] +mana_symalt = [ + mana_WP_alt, + mana_UP_alt, + mana_BP_alt, + mana_RP_alt, + mana_GP_alt, + mana_2W_alt, + mana_2U_alt, + mana_2B_alt, + mana_2R_alt, + mana_2G_alt, + mana_WU_alt, + mana_WB_alt, + mana_RW_alt, + mana_GW_alt, + mana_UB_alt, + mana_UR_alt, + mana_GU_alt, + mana_BR_alt, + mana_BG_alt, + mana_RG_alt, +] +mana_symall = mana_syms + mana_symalt + +# alt symbol conversion +def mana_alt(sym): + if not sym in mana_symall: + raise ValueError('invalid mana symbol for mana_alt(): ' + repr(sym)) + if len(sym) < 2: + return sym + else: + return sym[::-1] + +# produce intended neural net output format +def mana_sym_to_encoding(sym): + if not sym in mana_symall: + raise ValueError('invalid mana symbol for mana_sym_to_encoding(): ' + repr(sym)) + if len(sym) < 2: + return sym * 2 + else: + return sym + +# produce json formatting used in mtgjson +def mana_sym_to_json(sym): + if not sym in mana_symall: + raise ValueError('invalid mana symbol for mana_sym_to_json(): ' + repr(sym)) + if len(sym) < 2: + return mana_json_open_delimiter + sym + mana_json_close_delimiter + else: + return (mana_json_open_delimiter + sym[0] + mana_json_hybrid_delimiter + + sym[1] + mana_json_close_delimiter) + +# produce pretty formatting that renders on mtgsalvation forum +# converts individual symbols; surrounding [mana][/mana] tags are added elsewhere +def mana_sym_to_forum(sym): + if not sym in mana_symall: + raise ValueError('invalid mana symbol for mana_sym_to_forum(): ' + repr(sym)) + if sym in mana_symalt: + sym = mana_alt(sym) + if len(sym) < 2: + return sym + else: + return mana_json_open_delimiter + sym + mana_json_close_delimiter + +# forward symbol tables for encoding +mana_syms_encode = {sym : mana_sym_to_encoding(sym) for sym in mana_syms} +mana_symalt_encode = {sym : mana_sym_to_encoding(sym) for sym in mana_symalt} +mana_symall_encode = {sym : mana_sym_to_encoding(sym) for sym in mana_symall} +mana_syms_jencode = {sym : mana_sym_to_json(sym) for sym in mana_syms} +mana_symalt_jencode = {sym : mana_sym_to_json(sym) for sym in mana_symalt} +mana_symall_jencode = {sym : mana_sym_to_json(sym) for sym in mana_symall} + +# reverse symbol tables for decoding +mana_syms_decode = {mana_sym_to_encoding(sym) : sym for sym in mana_syms} +mana_symalt_decode = {mana_sym_to_encoding(sym) : sym for sym in mana_symalt} +mana_symall_decode = {mana_sym_to_encoding(sym) : sym for sym in mana_symall} +mana_syms_jdecode = {mana_sym_to_json(sym) : sym for sym in mana_syms} +mana_symalt_jdecode = {mana_sym_to_json(sym) : sym for sym in mana_symalt} +mana_symall_jdecode = {mana_sym_to_json(sym) : sym for sym in mana_symall} + +# going straight from json to encoding and vice versa +def mana_encode_direct(jsym): + if not jsym in mana_symall_jdecode: + raise ValueError('json string not found in decode table for mana_encode_direct(): ' + + repr(jsym)) + else: + return mana_symall_encode[mana_symall_jdecode[jsym]] + +def mana_decode_direct(sym): + if not sym in mana_symall_decode: + raise ValueError('mana symbol not found in decode table for mana_decode_direct(): ' + + repr(sym)) + else: + return mana_symall_jencode[mana_symall_decode[sym]] + +# hacked in support for mtgsalvation forum +def mana_decode_direct_forum(sym): + if not sym in mana_symall_decode: + raise ValueError('mana symbol not found in decode table for mana_decode_direct_forum(): ' + + repr(sym)) + else: + return mana_sym_to_forum(mana_symall_decode[sym]) + +# processing entire strings +def unique_string(s): + return ''.join(set(s)) + +mana_charset_special = mana_unary_marker + mana_unary_counter +mana_charset_strict = unique_string(''.join(mana_symall) + mana_charset_special) +mana_charset = unique_string(mana_charset_strict + mana_charset_strict.lower()) + +mana_regex_strict = (re.escape(mana_open_delimiter) + '[' + + re.escape(mana_charset_strict) + + ']*' + re.escape(mana_close_delimiter)) +mana_regex = (re.escape(mana_open_delimiter) + '[' + + re.escape(mana_charset) + + ']*' + re.escape(mana_close_delimiter)) + +# as a special case, we let unary or decimal numbers exist in json mana strings +mana_jcharset_special = '0123456789' + mana_unary_marker + mana_unary_counter +mana_jcharset_strict = unique_string(''.join(mana_symall_jdecode) + mana_jcharset_special) +mana_jcharset = unique_string(mana_jcharset_strict + mana_jcharset_strict.lower()) + +# note that json mana strings can't be empty between the delimiters +mana_jregex_strict = (re.escape(mana_json_open_delimiter) + '[' + + re.escape(mana_jcharset_strict) + + ']+' + re.escape(mana_json_close_delimiter)) +mana_jregex = (re.escape(mana_json_open_delimiter) + '[' + + re.escape(mana_jcharset) + + ']+' + re.escape(mana_json_close_delimiter)) + +number_decimal_regex = r'[0123456789]+' +number_unary_regex = re.escape(unary_marker) + re.escape(unary_counter) + '*' +mana_decimal_regex = (re.escape(mana_json_open_delimiter) + number_decimal_regex + + re.escape(mana_json_close_delimiter)) +mana_unary_regex = (re.escape(mana_json_open_delimiter) + number_unary_regex + + re.escape(mana_json_close_delimiter)) + +# convert a json mana string to the proper encoding +def mana_translate(jmanastr): + manastr = jmanastr + for n in re.findall(mana_unary_regex, manastr): + ns = re.findall(number_unary_regex, n) + i = (len(ns[0]) - len(mana_unary_marker)) / len(mana_unary_counter) + manastr = manastr.replace(n, mana_unary_marker + mana_unary_counter * i) + for n in re.findall(mana_decimal_regex, manastr): + ns = re.findall(number_decimal_regex, n) + i = int(ns[0]) + manastr = manastr.replace(n, mana_unary_marker + mana_unary_counter * i) + for jsym in mana_symall_jdecode: + if jsym in manastr: + manastr = manastr.replace(jsym, mana_encode_direct(jsym)) + return mana_open_delimiter + manastr + mana_close_delimiter + +# convert an encoded mana string back to json +mana_symlen_min = min([len(sym) for sym in mana_symall_decode]) +mana_symlen_max = max([len(sym) for sym in mana_symall_decode]) +def mana_untranslate(manastr, for_forum = False): + inner = manastr[1:-1] + jmanastr = '' + colorless_total = 0 + idx = 0 + while idx < len(inner): + # taking this branch is an infinite loop if unary_marker is empty + if len(mana_unary_marker) > 0 and inner[idx:idx+len(mana_unary_marker)] == mana_unary_marker: + idx += len(mana_unary_marker) + elif inner[idx:idx+len(mana_unary_counter)] == mana_unary_counter: + idx += len(mana_unary_counter) + colorless_total += 1 + else: + old_idx = idx + for symlen in range(mana_symlen_min, mana_symlen_max + 1): + sym = inner[idx:idx+symlen] + if sym in mana_symall_decode: + idx += symlen + if for_forum: + jmanastr = jmanastr + mana_decode_direct_forum(sym) + else: + jmanastr = jmanastr + mana_decode_direct(sym) + break + # otherwise we'll go into an infinite loop if we see a symbol we don't know + if idx == old_idx: + idx += 1 + if for_forum: + if jmanastr == '': + return mana_forum_open_delimiter + str(colorless_total) + mana_forum_close_delimiter + else: + return (mana_forum_open_delimiter + ('' if colorless_total == 0 + else str(colorless_total)) + + jmanastr + mana_forum_close_delimiter) + else: + if jmanastr == '': + return mana_json_open_delimiter + str(colorless_total) + mana_json_close_delimiter + else: + return (('' if colorless_total == 0 else + mana_json_open_delimiter + str(colorless_total) + mana_json_close_delimiter) + + jmanastr) + +# finally, replacing all instances in a string +# notice the calls to .upper(), this way we recognize lowercase symbols as well just in case +def to_mana(s): + jmanastrs = re.findall(mana_jregex, s) + for jmanastr in jmanastrs: + s = s.replace(jmanastr, mana_translate(jmanastr.upper())) + return s + +def from_mana(s, for_forum = False): + manastrs = re.findall(mana_regex, s) + for manastr in manastrs: + s = s.replace(manastr, mana_untranslate(manastr.upper(), for_forum = for_forum)) + return s + +# Translation could also be accomplished using the datamine.Manacost object's +# display methods, but these direct string transformations are retained for +# quick scripting and convenience (and used under the hood by that class to +# do its formatting). diff --git a/encode.py b/encode.py index b701437..17eee57 100644 --- a/encode.py +++ b/encode.py @@ -9,7 +9,7 @@ valid_encoded_char = r'[abcdefghijklmnopqrstuvwxyz\'+\-*",.:;WUBRGPV/XTQ|\\&^\{\ dash_marker = '~' bullet_marker = '=' -reserved_indicator = '\r' +reserved_marker = '\r' def to_ascii(s): s = s.replace(u'\u2014', dash_marker) # unicode long dash @@ -96,7 +96,9 @@ def to_unary(s): s = s.replace(n, 'two hundred') else: if i > unary_max: + # truncate to unary_max i = unary_max + # warn, because we probably don't want this to happen print s s = s.replace(n, unary_marker + unary_counter * i) @@ -135,8 +137,6 @@ def compress_mana(manastring): '{r/g}' : 'RG', '{s}' : 'SS', '{x}' : x_marker * 2, - #'{xx}' : x_marker * 4, - #'{xxx}' : x_marker * 6, '{t}' : tap_marker, '{q}' : untap_marker, } @@ -434,9 +434,9 @@ def rename_uncast(s): # run only after doing unary conversion def fix_dashes(s): - s = s.replace('-' + unary_marker, reserved_indicator) + s = s.replace('-' + unary_marker, reserved_marker) s = s.replace('-', dash_marker) - s = s.replace(reserved_indicator, '-' + unary_marker) + s = s.replace(reserved_marker, '-' + unary_marker) # level up is annoying levels = re.findall(r'level &\^*\-&', s) @@ -468,8 +468,6 @@ def fix_x(s): return s - - # run after fixing dashes, it makes the regexes better, but before replacing newlines def reformat_choice(s): # the idea is to take 'choose n ~\n=ability\n=ability\n' @@ -537,6 +535,8 @@ def encode(card): # filter out vanguard cards if card['layout'] in ['token', 'plane', 'scheme', 'phenomenon', 'vanguard']: return + if card['type'] in ['Conspiracy']: # just for now? + return encoding = fieldsep name = card['name'].lower() @@ -576,9 +576,9 @@ def encode(card): encoding += fieldsep # HACK: put the cost again after the text - if 'manaCost' in card: - encoding += replace_mana(card['manaCost'].lower()) - encoding += fieldsep + # if 'manaCost' in card: + # encoding += replace_mana(card['manaCost'].lower()) + # encoding += fieldsep # if 'flavor' in card: # encoding += card['flavor'].lower() diff --git a/output.txt b/output.txt index f99aa1f..5bca364 100644 --- a/output.txt +++ b/output.txt @@ -2117,8 +2117,6 @@ |goblin tinkerer||creature||goblin artificer|&^/&^^|{^RR}|{RR}, T: destroy target artifact. that artifact deals damage equal to its converted mana cost to @.| -|unexpected potential||conspiracy|||||hidden agenda \you may spend mana as though it were mana of any color to cast spells with the chosen name.| - |war elemental||creature||elemental|&^/&^|{RRRRRR}|when @ enters the battlefield, sacrifice it unless an opponent was dealt damage this turn.\whenever an opponent is dealt damage, put that many +&^/+&^ counters on @.| |ensoul artifact||enchantment||aura||{^UU}|enchant artifact\enchanted artifact is a creature with base power and toughness &^^^^^/&^^^^^ in addition to its other types.| @@ -2305,8 +2303,6 @@ |feast of flesh||sorcery||||{BB}|@ deals X damage to target creature and you gain X life, where X is &^ plus the number of cards named @ in all graveyards.| -|secret summoning||conspiracy|||||hidden agenda \whenever a creature with the chosen name enters the battlefield under your control, you may search your library for any number of cards with that name, reveal them, put them into your hand, then shuffle your library.| - |spellshift||instant||||{^^^UU}|uncast target instant or sorcery spell. its controller reveals cards from the top of his or her library until he or she reveals an instant or sorcery card. that player may cast that card without paying its mana cost. then he or she shuffles his or her library.| |grandmother sengir|legendary|creature||human wizard|&^^^/&^^^|{^^^^BB}|{^BB}, T: target creature gets -&^/-&^ until end of turn.| @@ -4525,8 +4521,6 @@ |pine barrens||land|||||@ enters the battlefield tapped.\T: add {^} to your mana pool.\T: add {BB} or {GG} to your mana pool. @ deals &^ damage to you.| -|double stroke||conspiracy|||||hidden agenda \whenever you cast an instant or sorcery spell with the chosen name, you may copy it. you may choose new targets for the copy.| - |dark betrayal||instant||||{BB}|destroy target black creature.| |scarred vinebreeder||creature||elf shaman|&^/&^|{^BB}|{^^BB}, exile an elf card from your graveyard: @ gets +&^^^/+&^^^ until end of turn.| @@ -5841,8 +5835,6 @@ |volrath's laboratory||artifact||||{^^^^^}|as @ enters the battlefield, choose a color and a creature type.\{^^^^^}, T: put a &^^/&^^ creature token of the chosen color and type onto the battlefield.| -|muzzio's preparations||conspiracy|||||hidden agenda \each creature you control with the chosen name enters the battlefield with an additional +&^/+&^ counter on it.| - |illumination||instant||||{WWWW}|uncast target artifact or enchantment spell. its controller gains life equal to its converted mana cost.| |cursed rack||artifact||||{^^^^}|as @ enters the battlefield, choose an opponent.\the chosen player's maximum hand size is four.| @@ -8176,8 +8168,6 @@ |centaur glade||enchantment||||{^^^GGGG}|{^^GGGG}: put a &^^^/&^^^ green centaur creature token onto the battlefield.| -|sultai ascendacy||enchantment||||{UUBBGG}|at the beginning of your upkeep, look at the top two cards of your library. put any number of them into your graveyard and the rest back on top of your library in any order.| - |deathgaze cockatrice||creature||cockatrice|&^^/&^^|{^^BBBB}|flying\deathtouch| |brimstone dragon||creature||dragon|&^^^^^^/&^^^^^^|{^^^^^^RRRR}|flying, haste| @@ -8452,8 +8442,6 @@ |heroic defiance||enchantment||aura||{^WW}|enchant creature\enchanted creature gets +&^^^/+&^^^ unless it shares a color with the most common color among all permanents or a color tied for most common.| -|worldknit||conspiracy|||||\as long as every card in your card pool started the game in your library or in the command zone, lands you control have "T: add one mana of any color to your mana pool."| - |okiba~gang shinobi||creature||rat ninja|&^^^/&^^|{^^^BBBB}|ninjutsu {^^^BB} \whenever @ deals combat damage to a player, that player discards two cards.| |rhystic syphon||sorcery||||{^^^BBBB}|unless target player pays {^^^}, he or she loses &^^^^^ life and you gain &^^^^^ life.| @@ -15212,14 +15200,10 @@ |sparkcaster||creature||kavu|&^^^^^/&^^^|{^^RRGG}|when @ enters the battlefield, return a red or green creature you control to its owner's hand.\when @ enters the battlefield, it deals &^ damage to target player.| -|advantageous proclamation||conspiracy|||||\your minimum deck size is reduced by five.| - |precursor golem||artifact creature||golem|&^^^/&^^^|{^^^^^}|when @ enters the battlefield, put two &^^^/&^^^ colorless golem artifact creature tokens onto the battlefield.\whenever a player casts an instant or sorcery spell that targets only a single golem, that player copies that spell for each other golem that spell could target. each copy targets a different one of those golems.| |sarcomancy||enchantment||||{BB}|when @ enters the battlefield, put a &^^/&^^ black zombie creature token onto the battlefield.\at the beginning of your upkeep, if there are no zombies on the battlefield, @ deals &^ damage to you.| -|iterative analysis||conspiracy|||||hidden agenda \whenever you cast an instant or sorcery spell with the chosen name, you may draw a card.| - |monastery flock||creature||bird|&/&^^^^^|{^^UU}|defender, flying\morph {UU}| |beck||sorcery||||{GGUU}|whenever a creature enters the battlefield this turn, you may draw a card.\fuse| @@ -15944,8 +15928,6 @@ |chain of vapor||instant||||{UU}|return target nonland permanent to its owner's hand. then that permanent's controller may sacrifice a land. if the player does, he or she may copy this spell and may choose a new target for that copy.| -|secrets of paradise||conspiracy|||||hidden agenda \creatures you control with the chosen name have "T: add one mana of any color to your mana pool."| - |wall of hope||creature||wall|&/&^^^|{WW}|defender \whenever @ is dealt damage, you gain that much life.| |griffin guide||enchantment||aura||{^^WW}|enchant creature\enchanted creature gets +&^^/+&^^ and has flying.\when enchanted creature dies, put a &^^/&^^ white griffin creature token with flying onto the battlefield.| @@ -20005,8 +19987,6 @@ |ink~treader nephilim||creature||nephilim|&^^^/&^^^|{RRGGWWUU}|whenever a player casts an instant or sorcery spell, if that spell targets only @, copy the spell for each other creature that spell could target. each copy targets a different one of those creatures.| -|sentinel dispatch||conspiracy|||||\at the beginning of the first upkeep, put a &^/&^ colorless construct artifact creature token with defender onto the battlefield.| - |chasm drake||creature||drake|&^^^/&^^^|{^^^^UU}|flying\whenever @ attacks, target creature you control gains flying until end of turn.| |primitive justice||sorcery||||{^RR}|as an additional cost to cast @, you may pay {^RR} and/or {^GG} any number of times.\destroy target artifact. for each additional {^RR} you paid, destroy another target artifact. for each additional {^GG} you paid, destroy another target artifact, and you gain &^ life.| @@ -22568,8 +22548,6 @@ |myr incubator||artifact||||{^^^^^^}|{^^^^^^}, T, sacrifice @: search your library for any number of artifact cards, exile them, then put that many &^/&^ colorless myr artifact creature tokens onto the battlefield. then shuffle your library.| -|immediate action||conspiracy|||||hidden agenda \creatures you control with the chosen name have haste.| - |distant melody||sorcery||||{^^^UU}|choose a creature type. draw a card for each permanent you control of that type.| |symbiotic wurm||creature||wurm|&^^^^^^^/&^^^^^^^|{^^^^^GGGGGG}|when @ dies, put seven &^/&^ green insect creature tokens onto the battlefield.| @@ -23859,8 +23837,6 @@ |igneous golem||artifact creature||golem|&^^^/&^^^^|{^^^^^}|{^^}: @ gains trample until end of turn.| -|backup plan||conspiracy|||||\draw an additional hand of seven cards as the game begins. before taking mulligans, shuffle all but one of your hands into your library.| - |cloudcrest lake||land|||||T: add {^} to your mana pool.\T: add {WW} or {UU} to your mana pool. @ doesn't untap during your next untap step.| |endoskeleton||artifact||||{^^}|you may choose not to untap @ during your untap step.\{^^}, T: target creature gets +&/+&^^^ for as long as @ remains tapped.| @@ -26072,8 +26048,6 @@ |crumbling colossus||artifact creature||golem|&^^^^^^^/&^^^^|{^^^^^}|trample \when @ attacks, sacrifice it at end of combat.| -|brago's favor||conspiracy|||||hidden agenda \spells with the chosen name you cast cost {^} less to cast.| - |caustic hound||creature||hound|&^^^^/&^^^^|{^^^^^BB}|when @ dies, each player loses &^^^^ life.| |eldrazi conscription||tribal enchantment||eldrazi aura||{^^^^^^^^}|enchant creature\enchanted creature gets +&^^^^^^^^^^/+&^^^^^^^^^^ and has trample and annihilator &^^.| @@ -29179,8 +29153,6 @@ |ruination||sorcery||||{^^^RR}|destroy all nonbasic lands.| -|power play||conspiracy|||||\you are the starting player. if multiple players would be the starting player, one of those players is chosen at random.| - |fresh volunteers||creature||human rebel|&^^/&^^|{^WW}|| |stormsurge kraken||creature||kraken|&^^^^^/&^^^^^|{^^^UUUU}|hexproof\lieutenant ~ as long as you control your commander, @ gets +&^^/+&^^ and has "whenever @ becomes blocked, you may draw two cards."| diff --git a/unscramble.py b/unscramble.py index 83600b3..20b5ed7 100644 --- a/unscramble.py +++ b/unscramble.py @@ -6,7 +6,7 @@ import sys def from_unary(s): numbers = re.findall(r'&\^*', s) - for number in sorted(numbers, cmp = lambda x,y: cmp(len(x), len(y)) * -1): + for number in sorted(numbers, cmp = lambda x,y: cmp(len(x), len(y)), reverse = True): i = len(number) - 1 s = s.replace(number, str(i)) return s