Kannst du den Zauber wirken?

22

In Magic: the Gathering kämpfen Magier (bekannt als "Planeswalker") miteinander, indem sie Zauber wirken. Zauber kosten Mana. Es gibt fünf Manafarben: Weiß, Blau, Schwarz, Rot und Grün, dargestellt als {W}, {U}, {B}, {R} und {G}.

Die Kosten eines Zaubers sind etwas komplexer. Die Kosten können eine beliebige Kombination der folgenden sein:

  • Eine oder mehrere Farben
  • Eine oder mehrere farblose Zahlen, dargestellt als {X}, wobei X eine positive ganze Zahl ist
  • Eine oder mehrere Hybriden, dargestellt als {Y / Z}, wobei Y und Z entweder eine Farbe (dargestellt durch einen der fünf Buchstaben) oder farblos sind, dargestellt durch eine positive ganze Zahl

Die folgenden Regeln gelten, wenn Sie versuchen, einen Zauber zu wirken:

  • Eine Farbe in einem Preis muss durch ein Mana dieser Farbe befriedigt werden
  • Ein farbloses Cost {X} kann durch X Mana einer beliebigen Farbe gedeckt werden
  • Hybridkosten {Y / Z} können erfüllt werden, indem entweder Y oder Z erfüllt werden
    • Beachten Sie, dass geschachtelte Klammern nicht vorhanden sind
    • Y und Z sind nicht hybrid

Schreiben Sie ein Programm oder eine Funktion, die bei gegebenem Manapool und gegebenen Kosten true (oder einen gewissen Wahrheitswert) ausgibt oder zurückgibt, wenn das Mana in diesem Pool die Kosten decken kann, andernfalls false (oder einen gewissen falschen Wert).

Ein Manavorrat ist eine nicht leere Zeichenfolge des Formats:

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

Ein Kostenwert ist eine nicht leere Zeichenfolge des Formats:

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

Beispiele

Im Format Pool Cost -> ExpectedOutput(mit einem Leerzeichen zwischen Pool und Kosten):

{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
Regenblitz
quelle
Kann man im Pool farbloses Mana haben?
Nutki
@nutki Im realen Spiel ja. Bei der Herausforderung nein. Für die Zwecke der Herausforderung existieren nur die fünf in der Herausforderung definierten Farben.
Rainbolt
Ich war zu lange weg von Magie. Hybridkosten?!?
Sparr
2
@Sparr Sie wurden 2005 in Ravnica vorgestellt
murgatroid99
@ murgatroid99 Ich habe aufgehört, als 6E herauskam. Keiner meiner Freunde war bereit, sich an die neuen Regeln anzupassen :(
Sparr

Antworten:

7

Pyth, 55 53 52 50 Bytes

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

Probieren Sie es online aus: Vorführ- oder Testgeschirr

Beachten Sie, dass die Zeit- und Speicherkomplexität sehr schlecht ist. Das zweite Beispiel funktioniert also nicht. Ich reserviere ungefähr 1,6 GB RAM, bevor es auf meinem Computer abstürzt.

Erläuterung

Die Erklärung gilt für die 53-Lösung. Der einzige Unterschied ist, dass das anfängliche Parsen in der Mitte und nicht am Anfang stattfindet.

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

Also hier ist die anfängliche Analyse.

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

Die Eingabe "{W},{R},{R} {2/W},{W/B}"wird also in konvertiert ['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

Also, was macht das? Der Kosteninput '2/w,w/b'wird umgewandelt in:

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

Jede Zeichenfolge ['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w']erfüllt {2/W}und jeder Buchstabe 'wb'erfüllt {w/b}.

Nun generieren wir das kartesische Produkt dieser Listen (oder Strings) und prüfen, ob mit dem Manapool eine beliebige Kombination hergestellt werden kann.

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
quelle
1
Wahrhaftige und falsche Werte sind erlaubt, nicht nur Trueund False.
Isaacg
Sie können ein Zeichen speichern, indem Sie die Zuordnung zu eingeben K. Legen Sie fest, Kc-rz0"{}")wo Kzuerst verwendet wird, und entfernen Sie die ursprüngliche Zuordnung zu K.
Isaacg
@isaacg Oh, hätte das sehen sollen. Vielen Dank.
Jakube,
@Rainbolt Sie haben eine nicht funktionierende Lösung akzeptiert. Nun, es hat funktioniert, als ich es gepostet habe, aber Pyth hat sich sehr verändert. Ich habe es aktualisiert und 2 weitere Bytes gespeichert.
Jakube
@Jakube Danke, aber diese Antwort muss mit einem Interpreter funktionieren, der zum Zeitpunkt der Veröffentlichung der Challenge verfügbar war, und nicht mit einem neuen, aktualisierten Interpreter.
Rainbolt
2

Python 2.7, 412 Zeichen

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]))

Die Funktion fist diejenige, die die Prüfung durchführt. Es nimmt den Manavorrat und die Kosten als String-Argumente und gibt aus, 1wann das Mana die Kosten erfüllt und 0ansonsten. Zum Beispiel f('{R},{R},{G},{B},{R}', '{4},{R}')Ausdrucke 1.

Ungolfed, es sieht im Grunde so aus

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
quelle