Ты можешь разыграть заклинание?

22

В Magic: The Gathering, маги (известные как "planeswalker") сражаются друг с другом, используя заклинания. Заклинания стоят маны. Существует пять цветов маны: белый, синий, черный, красный и зеленый, представленные как {W}, {U}, {B}, {R} и {G} соответственно.

Стоимость заклинания немного сложнее. Стоимость может быть любой комбинацией следующего:

  • Один или несколько цветов
  • Один или несколько бесцветных, представленных как {X}, где X - положительное целое число
  • Одна или несколько гибридов, представленных как {Y / Z}, где Y и Z являются либо цветом (представленным одной из пяти букв), либо бесцветным, представленным положительным целым числом

Следующие правила применяются при попытке разыграть заклинание:

  • Цвет в стоимости должен быть удовлетворен одной маной этого цвета
  • Бесцветная стоимость {X} может быть удовлетворена за счет X маны любого цвета
  • Гибридная стоимость {Y / Z} может быть удовлетворена путем удовлетворения либо Y, либо Z
    • Обратите внимание, что фигурные скобки не являются вложенными
    • Y и Z не гибридные

Напишите программу или функцию, которая, учитывая пул маны и стоимость, печатает или возвращает истину (или некоторое истинное значение) тогда и только тогда, когда мана в этом пуле может удовлетворить стоимость, иначе ложь (или некоторое ложное значение).

Пул маны - это непустая строка в формате:

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

Стоимость - это непустая строка в формате:

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

Примеры

В формате Pool Cost -> ExpectedOutput(с пробелом между Pool и 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
Rainbolt
источник
Можно ли получить бесцветную ману в бассейне?
nutki
@nutki В настоящей игре да. В вызове нет. Для целей испытания существуют только пять цветов, определенных в задании.
Рейнболт
Я слишком долго был вдали от магии. Гибрид стоит?!?
Спарр
2
@Sparr Они были представлены в Равнице в далеком 2005 году
murgatroid99
@ murgatroid99 Я вышел, когда вышел 6E. Никто из моих друзей не пожелал адаптироваться к новым правилам :(
Спарр

Ответы:

7

Pyth, 55 53 52 50 байт

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

Попробуйте онлайн: демонстрация или тестовая привязь

Обратите внимание, что время и сложность памяти действительно плохие. Так что второй пример не работает. Я выделяю около 1,6 ГБ оперативной памяти до того, как она выйдет из строя на моей машине.

объяснение

Объяснение для 53 решения. Разница лишь в том, что первоначальный разбор происходит в середине, а не в начале.

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

Итак, вот начальный разбор.

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

Таким образом, ввод "{W},{R},{R} {2/W},{W/B}"преобразуется в ['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

Так, что это делает? Ввод затрат '2/w,w/b'преобразуется в:

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

Каждая строка в ['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w']удовлетворяет, {2/W}и каждый символ в 'wb'удовлетворяет {w/b}.

Теперь мы сгенерируем декартово произведение этих списков (или строк) и посмотрим, можно ли с помощью мана-пула создать любую комбинацию.

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
источник
1
допустимы и ложные ценности, а не только Trueи False.
Исаак
Вы можете сохранить персонажа, вставив присвоение K. Поместите, Kc-rz0"{}")где Kиспользуется в первый раз, и удалите начальное назначение K.
Исаак
@isaacg О, следовало бы это увидеть. Спасибо.
Якуб,
@Rainbolt Вы приняли нерабочее решение. Ну, это сработало, когда я его опубликовал, но Пиф сильно изменился. Я обновил его, а также сохранил еще 2 байта.
Якуб
@Jakube Спасибо, но этот ответ должен работать с использованием переводчика, который был доступен на момент публикации запроса, а не какого-либо нового обновленного переводчика.
Rainbolt
2

Python 2.7, 412 символов

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

Эта функция fвыполняет проверку. Он принимает пул маны и стоимость в качестве строковых аргументов и печатает, 1когда мана удовлетворяет стоимости, и в 0противном случае. Например, f('{R},{R},{G},{B},{R}', '{4},{R}')печатает 1.

В общем, это выглядит так

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
источник