Você pode lançar o feitiço?

22

Em Magic: the Gathering, magos (conhecidos como "planeswalkers") lutam entre si lançando feitiços. Feitiços custam mana. Existem cinco cores de mana: branco, azul, preto, vermelho e verde, representados como {W}, {U}, {B}, {R} e {G}, respectivamente.

O custo de um feitiço é um pouco mais complexo. O custo pode ser qualquer combinação do seguinte:

  • Uma ou mais cores
  • Um ou mais incolor, representado como {X}, em que X é um número inteiro positivo
  • Um ou mais híbridos, representados como {Y / Z}, em que Y e Z são uma cor (representada por uma das cinco letras) ou incolores, representados por um número inteiro positivo

As regras a seguir se aplicam ao tentar lançar um feitiço:

  • Uma cor em um custo deve ser satisfeita por um mana dessa cor
  • Um custo incolor {X} pode ser satisfeito por X mana de qualquer cor
  • Um custo híbrido {Y / Z} pode ser satisfeito satisfazendo Y ou Z
    • Observe que chaves não estão aninhadas
    • Y e Z não são híbridos

Escreva um programa ou função que, dado um conjunto de mana e um custo, imprima ou retorne verdadeiro (ou algum valor verdadeiro) se e somente se o mana nesse conjunto puder satisfazer o custo, caso contrário, falso (ou algum valor falso).

Um pool de mana é uma sequência não vazia do formato:

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

Um custo é uma sequência não vazia do formato:

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

Exemplos

No formato Pool Cost -> ExpectedOutput(com um espaço entre Pool e 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
fonte
É possível ter mana incolor na piscina?
nutki
@nutki No jogo real, sim. No desafio, não. Apenas as cinco cores definidas no desafio existem para os propósitos do desafio.
Rainbolt
Estive longe da magia por muito tempo. Custos híbridos?!?
Sparr
2
@Sparr Eles foram introduzidos em Ravnica, em 2005
murgatroid99
@ murgatroid99 Eu parei quando o 6E saiu. Nenhum de meus amigos estava disposto a se adaptar às novas regras :(
Sparr

Respostas:

7

Pitão, 55 53 52 50 bytes

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

Experimente on-line: demonstração ou equipamento de teste

Observe que a complexidade do tempo e da memória é muito ruim. Portanto, o segundo exemplo não funciona. Aloco cerca de 1,6 GB de RAM antes de travar na minha máquina.

Explicação

A explicação é para a solução 53. A única diferença é que a análise inicial acontece no meio, e não no começo.

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

Então aqui está a análise 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

Portanto, a entrada "{W},{R},{R} {2/W},{W/B}"é convertida em ['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

Então, o que isso faz? A entrada de custo '2/w,w/b'é convertida em:

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

Toda corda ['aa', 'ab', 'ac', ..., 'zx', 'zy', 'zz', 'w']satisfaz {2/W}e todo caractere 'wb'satisfaz {w/b}.

Agora, geramos o produto cartesiano dessas listas (ou cadeias) e verificamos se alguma combinação pode ser produzida com o pool de mana.

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
fonte
1
valores de verdade e falsidade são permitidos, não apenas Truee False.
Isaacg
Você pode salvar um personagem inserindo a tarefa em K. Coloque Kc-rz0"{}")onde Ké usado pela primeira vez e remova a atribuição inicial para K.
Isaacg
@isaacg Oh, deveria ter visto isso. Obrigado.
Jakube 6/15
@Rainbolt Você aceitou uma solução não útil. Bem, funcionou quando eu publiquei, mas Pyth mudou muito. Eu atualizei e também salvei mais 2 bytes.
Jakube 18/06
@Jakube Obrigado, mas esta resposta precisa funcionar usando um intérprete que estava disponível no momento em que o desafio foi lançado, e não um novo intérprete atualizado.
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]))

A função fé a que faz a verificação. Ele pega o pool de mana e o custo como argumentos de sequência e imprime 1quando o mana satisfaz o custo ou 0não. Por exemplo, f('{R},{R},{G},{B},{R}', '{4},{R}')imprime 1.

Sem jogar, basicamente se parece com isso

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
fonte