Pouvez-vous lancer le sort?

22

Dans Magic: the Gathering, les mages (appelés «planeswalkers») s'affrontent en lançant des sorts. Les sorts coûtent du mana. Il existe cinq couleurs de mana: blanc, bleu, noir, rouge et vert, représentées respectivement par {W}, {U}, {B}, {R} et {G}.

Le coût d'un sort est légèrement plus complexe. Le coût peut être n'importe quelle combinaison des éléments suivants:

  • Une ou plusieurs couleurs
  • Un ou plusieurs incolores, représentés par {X}, où X est un entier positif
  • Un ou plusieurs hybrides, représentés par {Y / Z}, où Y et Z sont soit une couleur (représentée par l'une des cinq lettres) soit incolore, représentée par un entier positif

Les règles suivantes s'appliquent lorsque vous tentez de lancer un sort:

  • Une couleur dans un coût doit être satisfaite par un mana de cette couleur
  • Un coût incolore {X} peut être satisfait par X mana de n'importe quelle couleur
  • Un coût hybride {Y / Z} peut être satisfait en satisfaisant soit Y soit Z
    • Notez que les accolades ne sont pas imbriquées
    • Y et Z ne sont pas hybrides

Écrivez un programme ou une fonction qui, étant donné un pool de mana et un coût, imprime ou retourne vrai (ou une certaine valeur véridique) si et seulement si le mana dans ce pool peut satisfaire le coût, sinon faux (ou une valeur falsifiée).

Une réserve de mana est une chaîne non vide du format:

Color1,Color2,Color3,...,Colorn-1,Colorn

Un coût est une chaîne non vide du format:

Cost1,Cost2,Cost3,...,Costn-1,Costn

Exemples

Au format Pool Cost -> ExpectedOutput(avec un espace entre Pool et Coût):

{R},{R},{G},{B},{R} {4},{R} -> True
{G},{G},{G},{G},{W},{W},{W} {2/W},{2/U},{2/B},{2/R},{2/G} -> False
{G},{G},{R} {R/G},{G/B},{B/R} -> True
{R},{R},{R},{G} {1},{G},{2/G}-> True
{R} {R},{R},{R},{R},{R} -> False
{W},{R},{R} {2/W},{W/B} -> True
{U},{U} {1} -> True
{W},{R},{G} {1},{2} -> True
Rainbolt
la source
Est-il possible d'avoir du mana incolore dans la piscine?
nutki
@nutki Dans le vrai jeu, oui. Dans le défi, non. Seules les cinq couleurs définies dans le défi existent aux fins du défi.
Rainbolt
Je suis loin de la magie depuis trop longtemps. Coûts hybrides?!?
Sparr
2
@Sparr Ils ont été introduits à Ravnica, en 2005
murgatroid99
@ murgatroid99 J'ai arrêté quand 6E est sorti. Aucun de mes amis n'était prêt à s'adapter aux nouvelles règles :(
Sparr

Réponses:

7

Pyth, 55 53 52 50 octets

FN*Fmsm?k}kG^Gvkcd\/ceKc-rz0`Hd\,#=sN)I!.-NhK1B)E0

Essayez-le en ligne: démonstration ou test de harnais

Notez que la complexité du temps et de la mémoire est vraiment mauvaise. Le deuxième exemple ne fonctionne donc pas. J'alloue environ 1,6 Go de Ram avant qu'il ne plante sur ma machine.

Explication

L'explication est pour la solution 53. La seule différence est que l'analyse initiale se produit au milieu au lieu du début.

Kc-rz0"{}"dFN*Fmsm?k}kG^Gvkcd\/ceKc-rz0`H\,#=sN)I!.-NhK1B)E0

Voici donc l'analyse initiale.

Kc-rz0`Hd
   rz0     convert input() to lowercase
  -   `H   remove all curly brackets (`H = "{}")
 c      d  split at the space
K          assign to K

Ainsi, l'entrée "{W},{R},{R} {2/W},{W/B}"est convertie en ['w,r,r', '2/w,w/b'].

m               ceK\,    map each cost d of the costs split by "," to:
 s                         the sum of
  m         cd\/           map each value k of cost split by "/" to:
    k                        k
   ? }kG                     if k in "abcdef...xyz" else
        ^Gvk                 Cartesian product with "abc...yz" of int(k) repeats

Alors qu'est-ce que cela fait? L'entrée de coût '2/w,w/b'est convertie en:

[['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w'], 'wb']

Chaque chaîne ['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w']satisfait {2/W}et chaque caractère 'wb'satisfait {w/b}.

Maintenant, nous générons le produit cartésien de ces listes (ou chaînes) et voyons si une combinaison peut être produite avec le mana-pool.

FN*F...              )      for N in Cartesian product of ...:
       #   )                   while 1:
        =sN                      N = sum(N)
                               this flattens N
            I!.-NhK            if not (subtract mana pool from N):
                   1             print 1 (True)
                    B            break
                      E      else:
                       0       print 0 (False)
Jakube
la source
1
les valeurs véridiques et fausses sont autorisées, pas seulement Trueet False.
isaacg
Vous pouvez enregistrer un personnage en intégrant l'affectation à K. Placez Kc-rz0"{}")Kest utilisé en premier et supprimez l'affectation initiale à K.
isaacg
@isaacg Oh, j'aurais dû voir ça. Merci.
Jakube
@Rainbolt Vous avez accepté une solution qui ne fonctionnait pas. Eh bien, cela a fonctionné lorsque je l'ai posté, mais Pyth a beaucoup changé. Je l'ai mis à jour et j'ai également enregistré 2 octets supplémentaires.
Jakube
@Jakube Merci, mais cette réponse doit fonctionner en utilisant un interprète qui était disponible au moment où le défi a été publié, pas un nouvel interprète mis à jour.
Rainbolt
2

Python 2.7, 412 caractères

import re,collections as C
r,C=re.findall,C.Counter
def g(m,h,c,v):
 try:return t(m,h,c+int(v))
 except:
  if m[v]:return t(m-C({v:1}),h,c)
def t(m,h,c):return any(g(m,h[1:],c,v)for v in h[0].split('/'))if h else sum(m.values())>=c
def f(m,c):m=C(r(r'\w',m));c=[filter(None, x)for x in zip(*r(r'(\w+/\w+)|(\d+)|(\w)',c))];m.subtract(C(c[2]));print all(x>=0 for x in m.values())*t(m,c[0],sum(int(x)for x in c[1]))

La fonction fest celle qui effectue la vérification. Il prend le pool de mana et le coût comme arguments de chaîne et s'affiche 1lorsque le mana satisfait le coût et 0autrement. Par exemple, des f('{R},{R},{G},{B},{R}', '{4},{R}')impressions 1.

Non golfé, il ressemble essentiellement à ceci

import re
from collections import Counter
def helper(mana, hybrids, colorless, option):
  try:
    option = int(option) # See if option is an integer
    # For colorless hybrid, just add the value to the colorless amount
    # to check at the end.
    return check_hybrids(mana, hybrids, colorless + option)
  except ValueError: # Option is a mana letter
    # For colored hybrid costs, check if any of that color is
    # available, then try to pay the rest of the cost with 1 less
    # of that color.
    if mana[option] >= 0:
      return check_hybrids(mana - Counter({option: 1}), hybrids, colorless)
    else:
      return False
def check_hybrids(mana, hybrids, colorless):
  '''Check whether the given mana pool can pay the given hybrid costs and colorless costs'''
  if hybrids:
    # For each option in the first hybrid cost, check whether the
    # rest of the cost can be paid after paying that cost
    return any(helper(mana, hybrids[1:], colorless, option) for option in hybrids[0].split('/'))
  else:
    # When there are no remaining hybrid costs, if there is enough
    # remaining mana to pay the colorless costs, we have success
    return sum(m.values()) > colorless
def can_cast(mana_str, cost_str):
  mana = Counter(re.findall(r'\w', mana_str))
  # transpose to get separate lists of hybrid, colorless, and colored symbols
  cost = zip(*re.findall(r'(\w+/\w+)|(\d+)|(\w)',cost_str))
  cost = [filter(None, sublist) for sublist in cost] # Remove unfound symbols
  mana.subtract(Counter(cost[2]))
  # After subtracting the single-colored cost from the mana pool, if
  # anything in the mana pool is negative, we didn't have enough to
  # pay for that color.
  if any(x <=0 for x in mana.values()):
    return False
  return check_hybrids(mana, cost[0], sum(int(x)for x in cost[1]))
murgatroid99
la source