¿Puedes lanzar el hechizo?

22

En Magic: the Gathering, los magos (conocidos como "planeswalkers") luchan entre sí lanzando hechizos. Los hechizos cuestan maná. Existen cinco colores de maná: blanco, azul, negro, rojo y verde, representados como {W}, {U}, {B}, {R} y {G}, respectivamente.

El costo de un hechizo es un poco más complejo. El costo puede ser cualquier combinación de lo siguiente:

  • Uno o mas colores
  • Uno o más incoloros, representados como {X}, donde X es un entero positivo
  • Uno o más híbridos, representados como {Y / Z}, donde Y y Z son de color (representado por una de las cinco letras) o incoloro, representado por un número entero positivo

Las siguientes reglas se aplican al intentar lanzar un hechizo:

  • Un color en un costo debe ser satisfecho por un maná de ese color
  • Un coste incoloro {X} puede ser satisfecho por X mana de cualquier color
  • Un costo híbrido {Y / Z} puede satisfacerse satisfaciendo Y o Z
    • Tenga en cuenta que las llaves no están anidadas
    • Y y Z no son híbridos

Escriba un programa o función que, dado un grupo de maná y un costo, imprima o devuelva verdadero (o algún valor verdadero) si y solo si el maná en ese grupo puede satisfacer el costo, de lo contrario falso (o algún valor falso).

Un grupo de maná es una cadena no vacía del formato:

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

Un costo es una cadena no vacía del formato:

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

Ejemplos

En el formato Pool Cost -> ExpectedOutput(con un espacio entre Pool y Cost):

{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
Perno de lluvia
fuente
¿Es posible tener maná incoloro en la piscina?
nutki
@nutki En el juego real, sí. En el desafío, no. Solo los cinco colores definidos en el desafío existen para los propósitos del desafío.
Rainbolt
He estado lejos de la magia por mucho tiempo. ¿Costos híbridos?
Sparr
2
@Sparr Fueron introducidos en Rávnica, en 2005
murgatroid99
@ murgatroid99 Renuncié cuando salió 6E. Ninguno de mis amigos estaba dispuesto a adaptarse a las nuevas reglas :(
Sparr

Respuestas:

7

Pyth, 55 53 52 50 bytes

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

Pruébelo en línea: demostración o prueba de arnés

Tenga en cuenta que la complejidad del tiempo y la memoria es realmente mala. Entonces el segundo ejemplo no funciona. Asigno aproximadamente 1.6 GB de RAM antes de que se bloquee en mi máquina.

Explicación

La explicación es para la solución 53. La única diferencia es que el análisis inicial ocurre en el medio en lugar del comienzo.

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

Así que aquí está el análisis inicial.

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

Entonces la entrada "{W},{R},{R} {2/W},{W/B}"se convierte 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

Entonces que hace esto? El costo de entrada '2/w,w/b'se convierte en:

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

Cada cadena en ['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w']satisface {2/W}y cada char en 'wb'satisface {w/b}.

Ahora generamos el producto cartesiano de estas listas (o cadenas) y vemos si se puede producir alguna combinación con el grupo de maná.

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
fuente
1
Se permiten valores de verdad y falsedad, no solo Truey False.
isaacg
Puede guardar un personaje ingresando la asignación a K. Coloque Kc-rz0"{}")dónde Kse usa por primera vez y elimine la asignación inicial a K.
isaacg
@isaacg Oh, debería haber visto eso. Gracias.
Jakube
@Rainbolt Usted aceptó una solución que no funciona. Bueno, funcionó cuando lo publiqué, pero Pyth cambió mucho. Lo actualicé y también guardé 2 bytes más.
Jakube
@Jakube Gracias, pero esta respuesta debe funcionar con un intérprete que estaba disponible en el momento en que se publicó el desafío, no con un intérprete nuevo y actualizado.
Rainbolt
2

Python 2.7, 412 caracteres

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 función fes la que hace la verificación. Toma el grupo de maná y el costo como argumentos de cadena, e imprime 1cuando el maná satisface el costo y de lo 0contrario. Por ejemplo, f('{R},{R},{G},{B},{R}', '{4},{R}')impresiones 1.

Ungolfed, básicamente se ve así

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
fuente