Magic: The Gathering Combat con habilidades

16

Relacionado

Objetivo:

Dadas dos criaturas con habilidades de combate opcionales, devuelve valores únicos pero consistentes que representan qué criaturas murieron, si las hay.

Entrada:

#Longest form:
[[P,T, "<abilities>"], [P,T, "<abilities>"]]
#Shortest form:
[[P,T], [P,T]]

Cada criatura se dará en forma de [P,T,"<abilities>"]. Estará en la forma [P,T], [P,T,""]o [P,T,0]si no tiene habilidades, su elección en la forma. P es un entero> = 0, T es un entero> = 1. <abilities>es un subconjunto de "DFI", o puede representarse a través de un solo número / cadena de bits si lo desea. El orden de las banderas también depende de usted.

Mecánica de combate:

Cada criatura tiene dos estadísticas, Poder y Resistencia en ese orden, y habilidades opcionales. El poder de una criatura es> = 0. La resistencia de una criatura es> = 1.

Cada criatura hará simultáneamente daño igual a su poder a la criatura oponente (a menos que uno tenga el primer golpe). Si el valor es mayor o igual que la resistencia del oponente, morirá (a menos que sea indestructible).

Ejemplo: Alice es un 2/2, Bob es un 3/4, ambos sin habilidades. Alice hará 2 daños a Bob y recibirá 3 daños a cambio. La dureza de Alice es 2, por lo que morirá, la dureza de Bob es 4, por lo que vivirá.

Solo hay 3 habilidades opcionales que consideraremos para esto (aunque hay más en el juego). Estas serán banderas de un personaje:

  • [D] eathtouch: cualquier cantidad de daño (X> 0) se considera letal.
  • [F] primer Golpe: Primero hará daño, capaz de matar a la otra criatura antes de que pueda atacar. Si ambas criaturas tienen First Strike, resuelve el combate como de costumbre.
  • [I] ndestructible: Ninguna cantidad de daño se considera letal, incluido Deathtouch.

Salida:

Cualquier valor consistente para cada uno de los siguientes cuatro casos. Indique los cuatro valores en su respuesta, por favor. Ejemplo de valor de retorno en parens:

  • Ninguna criatura murió (0)
  • La primera criatura murió (1)
  • La segunda criatura murió (2)
  • Ambas criaturas murieron (3)

Reglas:

  • Se garantiza que la entrada tiene dos criaturas formateadas correctamente.
  • Si está usando personajes para habilidades, puede suponer que están ordenados como desee, pero publique el orden utilizado si es relevante.
  • Si está utilizando un número / cadena de bits para las habilidades, publique la codificación que está utilizando. por ejemplo: 111es D/F/I, 7es D/F/I, etc.
  • Si una criatura no tiene habilidades, también se puede tomar como un [P,T, ""]número equivalente
  • Lagunas estándar prohibidas
  • Este es el por lo que gana el código más corto.

Ejemplos:

Input: [[2,2], [1,1]]
Output: 2nd Dies

Input: [[0,2], [0,1]] #0/2 vs 0/1
Output: Neither Die

Input: [[2,1], [2,1]] #2/1 vs 2/1
Output: Both Die

Input: [[1,1, "D"], [2,2]] #1/1 Deathtoucher vs 2/2 
Output: Both Die

Input: [[2,2], [0,1, "D"]] #2/2 vs 0/1 Deathtoucher
Output: 2nd Dies

Input: [[2,2], [1,1, "DF"]] #2/2 vs 1/1 Deathtouch First-striker 
Output: 1st Dies

Input: [[0,2, "D"], [0,1, "DF"]] #0/2 Deathtoucher vs 0/1 Deathtouch First-striker
Output: Neither Die

Input: [[2,2], [2,2, "F"]] #2/2 vs 2/2 First-striker
Output: 1st Dies

Input: [[2,2, "I"], [1,1, "DF"]] #2/2 Indestructible vs 1/1 Deathtouch First-striker
Output: 2nd Dies

Input: [[9999,9999], [1,1, "I"]] #9999/9999 vs 1/1 Indestructible
Output: Neither Die

Input: [[2,2, "F"], [1,1, "F"]] #2/2 First-Striker vs 1/1 First-Striker
Output: 2nd Dies

#9/9 Deathtouch, Indestructible First-Striker vs 9/9 Deathtouch, Indestructible First-Striker
Input: [[9,9, "DFI"], [9,9, "DFI"]] 
Output: Neither Die
Veskah
fuente
1
@ user71546 Sí. Hay un poco más de reglas involucradas, pero en MtG, "No se puede" triunfar sobre "Latas". Funcionalmente, Indestructible ignora Deathstrike. Editado para ser más explícito
Veskah
1
@ fəˈnɛtɪk, todavía sufre daños, simplemente no muere por ello. Eso sí, la pregunta también expresa mal la regla. Debería ser "los permanentes [indestructibles] no son destruidos por el daño letal, e ignoran la acción basada en el estado que verifica el daño letal ".
Peter Taylor
44
" Si una criatura no tiene habilidades, debe analizarse como [P, T]. [P, T," "] no es válido " es una mala regla. Discrimina los idiomas con una tipificación fuerte sin ningún beneficio.
Peter Taylor
2
@PeterTaylor Quiero mantener matrices irregulares pero tienes razón en que no lo mejora. Por lo tanto, la regla ha sido eliminada
Veskah
1
@Veskah ¿Puedo tomar "D", "F", "I" como números? D => 0, F => 1, I => 2
Luis felipe De jesus Munoz

Respuestas:

6

Perl 5 , 248 bytes

... sin espacios y nuevas líneas:

sub c{eval'
(P,T,A,p,t,a)=@_;
     A=~/F/&&a!~/F/&&a!~/I/ ? c( P,2e9,A=~s/F//r,p,t, a         )
    :a=~/F/&&A!~/F/&&A!~/I/ ? c( P,T, A,        p,2e9,a=~s/F//r )
    : do{
        P=1e9 ifA=~/D/&&P>0;
        p=1e9 ifa=~/D/&&p>0;
        T=3e9 ifA=~/I/;
        t=3e9 ifa=~/I/;
        T-=p;
        t-=P;
        T>0&&t>0  ? 0
            : T>0 ? 2
            : t>0 ? 1
            :       3
}'=~s,[pta],\$$&,gri }

Pruébalo en línea!

Mi versión sin golf con las diez pruebas de @Veskah (OP), pasa las pruebas:

sub co { #combat
    my($p1,$t1,$a1, $p2,$t2,$a2)=@_; #p=power, t=toughness, a=abilities
    $a1=~s/F// and $a2=~s/F// if "$a1$a2"=~/F.*F/; #both F, no F
    return co($p1,2e9,$a1=~s/F//r, $p2,$t2,$a2        ) if $a1=~/F/ && $a2!~/I/;
    return co($p1,$t1,$a1,         $p2,2e9,$a2=~s/F//r) if $a2=~/F/ && $a1!~/I/;
    $p1=1e9 if $a1=~/D/ and $p1>0;
    $p2=1e9 if $a2=~/D/ and $p2>0;
    $t1=3e9 if $a1=~/I/;
    $t2=3e9 if $a2=~/I/;
    $t1-=$p2;
    $t2-=$p1;
    $t1<=0 && $t2<=0 ? "Both Die"
   :$t1<=0           ? "1st Dies"
   :$t2<=0           ? "2nd Dies"
                     : "Neither Die"
}

my @test=map{[/Input: .*? (\d+),(\d+)(?:,\s*"([FDI]+)")?
                      .*? (\d+),(\d+)(?:,\s*"([FDI]+)")?
           .*? Output: \s* (1st.Dies|2nd.Dies|Both.Die|Neither.Die)? /xsi]}
         split/\n\n/,join"",<DATA>;
my $t=0;
for(@test){ $t++;
  my $r=co(@$_);#result
  $r=~s,0,Neither Die,; $r=~s,3,Both Die,;
  print $$_[-1]=~/^$r/
    ? "Ok $t\n"
    : "Not ok, combat $t --> $r, wrong! (".join(",",@$_).")\n"
}
__DATA__
Input: [[2,2], [1,1]]
Output: 2nd Dies

Input: [[0,2], [0,1]] #0/2 vs 0/1
Output: Neither Die

Input: [[2,1], [2,1]] #2/1 vs 2/1
Output: Both Die

Input: [[1,1, "D"], [2,2]] #1/1 Deathtoucher vs 2/2
Output: Both Die

Input: [[2,2], [0,1, "D"]] #2/2 vs 0/1 Deathtoucher
Output: 2nd Dies

Input: [[2,2], [1,1, "DF"]] #2/2 vs 1/1 First-strike, Deathtoucher
Output: 1st Dies

Input: [[2,2], [2,2, "F"]] #2/2 vs 2/2 First-striker
Output: 1st Dies

Input: [[2,2, "I"], [1,1, "DF"]] #2/2 Indestructible vs 1/1 First-strike, Deatht.
Output: 2nd Dies

Input: [[99999,99999], [1,1, "I"]] #99999/99999 vs 1/1 Indestructible
Output: Neither Die

Input: [[2,2, "F"], [1,1, "F"]] #2/2 First-Striker vs 1/1 First-Striker
Output: 2nd Dies
Kjetil S.
fuente
4

JavaScript, 137 125 120 111 bytes

i=>(k=(a,b)=>!(b[2]%2)&&a[0]/(a[2]<=3)>=b[1],[c,d]=i,g=c[2]&2,h=k(c,d),j=k(d,c),d[2]&2-g&&(g?h&&2:j&&1)||j+2*h)

Estoy usando números de mapa de bits para habilidades D = 4 F = 2 I = 1 do "DFI"sería 7. Mi salida es Ni Murió 0, Primero Murió 1, Segundo Murió 2, Ambos murieron 3.

Pruebas con:

f([[2, 2, 0], [1,1, 0]]); // 2
f([[0, 2, 0], [0,1, 0]]); // 0
f([[2, 1, 0], [2,1, 0]]); // 3
f([[1, 1, 4], [2,2, 0]]); // 3
f([[2, 2, 0], [0,1, 4]]); // 2
f([[2, 2, 0], [1,1, 6]]); // 1
f([[2, 2, 0], [2,2, 2]]); // 1
f([[2, 2, 1], [1,1, 6]]); // 2
f([[99999, 99999, 0], [1,1, 1]]); // 0
f([[2, 2, 2], [1,1, 2]]); // 2)

Este fue mi primer código de trabajo

const kills = (c1, c2) => { // Return true if c1 kills c2
    if (c2[2] % 2) {
        console.log("Indestructible");
        return false;
    }
    const c1p = c1[0] / (c1[2] <= 3); // Infinity if Deathtoucher && P > 0
    const c2t = c2[1];
    return c1p >= c2t;
}
const f = (input) => {
    console.log("Match:", input);
    const [c1, c2] = input;
    const f1 = (c1[2] & 2);
    const f2 = (c2[2] & 2);
    if (f2 !== f1) {
        if (f1) {
            if (kills(c1, c2)) {
                console.log("c1 killed c2 in first round");
                return 2;
            }
        } else {
            if (kills(c2, c1)) {
                console.log("c2 killed c1 in first round");
                return 1;
            }
        }
    }
    return kills(c2, c1) + 2 * kills(c1, c2);
};

Lo que reduje a este intermedio:

const f = i => {
    const k = (a, b) => !(b[2] % 2) && a[0] / (a[2] <= 3) >= b[1];
    const [c, d] = i;
    const g = c[2] & 2;
    const h = k(c, d);
    const j = k(d, c);
    return d[2] & 2 - g &&
        (g  ? h && 2
            : j && 1
        ) || j + 2 * h
}
James
fuente
Bienvenido a PPCG! Y muy buena primera solución :) Puedo ver algún potencial para seguir jugando al golf, pero estoy en mi teléfono, después de algunas cervezas, así que no puedo probarlo correctamente.
Shaggy
Sin embargo, aquí hay un ahorro rápido de 7 bytes: tio.run/##bc/RbsIgFAbg@z0FuxgBd7RwNEu2SPcgjERKtak1ZVHjle/…
Shaggy
@Lanudo. ¡Buena esa! Por supuesto, el operador de coma, qué novato soy.
James
1
Todos fuimos nuevos una vez :)
Shaggy
3

JavaScript (ES6), 83 76 bytes

Toma la entrada como 6 argumentos distintos: 2 x (Poder, Resistencia, Habilidades). Se esperan habilidades como máscaras de bits con:

  • 1
  • 2
  • 4 4

0 0123

(p,t,a,P,T,A)=>(x=A<4&&p>=T|a&!!p)&(y=a<4&&P>=t|A&!!P)&&(a^A)&2?a+2>>1:x*2+y

Pruébalo en línea!

Comentado

(p, t, a, P, T, A) => // (p, t, a) = arguments for the first player (P1)
                      // (P, T, A) = arguments for the second player (P2)
  ( x =               // x is a flag which means 'P1 can kill P2',
                      // regardless of the 'First Strike' abilities
    A < 4 &&          // it is set to 1 if P2 is not Indestructible and:
    p >= T |          //   the power of P1 is greater than or equal to the toughness of P2
    a & !!p           //   or the power of P1 is not zero and P1 has the Death Touch
  ) &                 //
  ( y = a < 4 &&      // y is the counterpart of x and is computed the same way
    P >= t |          //
    A & !!P           //
  ) &&                // if both x and y are set
  (a ^ A) & 2 ?       // and exactly one player has the First Strike:
    a + 2 >> 1        //   return 2 if P1 has the First Strike, or 1 otherwise
  :                   // else:
    x * 2 + y         //   return the default outcome: x * 2 + y
Arnauld
fuente
3

C (gcc) , 114 113 95 bytes

Mucho golf gracias a ceilingcat y Logern.

g(Z{return F&1|F&4&&!(f&4||P<t)||!(f&2)&T>p;}
f(Z{return g(Z+2*g(p,t,f,P,T,F);}

Compilar con -DZ=P,T,F,p,t,f) .

Pruébalo en línea!

Verificamos (independientemente, debido a la simetría de la mecánica de combate) si cada una de las criaturas sobrevive al combate, lo que sucede si cualquiera de las dos es cierta:

  • la criatura es indestructible;
  • la criatura tiene el primer golpe Y la otra no Y su poder es mayor o igual a las dificultades de los demás (por lo tanto, podemos ignorar el toque de muerte de los demás);
  • otra criatura no tiene toque de muerte Y su poder es menor que nuestra resistencia.

(Las condiciones anteriores son más importantes).

Las entradas son poder y resistencia como números enteros, y habilidades como un campo de bits (1 = Indestructible, 2 = Toque de muerte, 4 = Primer golpe), la salida también es un campo de bits (1 = La primera criatura sobrevive, 2 = La segunda criatura sobrevive).

Max Yekhlakov
fuente
1
Usando una macro de -DZ=P,T,F,p,t,f) 96 bytes: ¡Pruébelo en línea!
Logern
Usar en P=…lugar de return …eliminar la nueva línea lo lleva a 85 bytes.
Además, -3 bytes reemplazando operadores lógicos &&, ||con bit a bit &,|
2

Retina 0.8.2 , 123 bytes

\d+
$*
(.*1)(.*;)(.*1)
$3$2$1
F(.*)F
$1
1+D
1
1*(,1+)I
$1
(1+)(F?;1*,)(1+)
$3$2$1
(1*)1*,\1(1+)?
$#2
0(F)?;0(F)?
$#1;$#2
F

Pruébalo en línea! Enlace incluye casos de prueba, aunque he sustituido 9por 99999la velocidad. La entrada usa las letras DFIaunque Ddebe preceder I. La salida está en el formato 1para sobrevivir y 0para morir. Explicación:

\d+
$*

Convierte las estadísticas a unario.

(.*1)(.*;)(.*1)
$3$2$1

Intercambia las estadísticas temporalmente.

F(.*)F
$1

Dos Fs se cancelan.

1+D
1

Toque de muerte reduce la resistencia del oponente a 1.

1*(,1+)I
$1

Indestructable reduce el poder del oponente a 0.

(1+)(;1*,)(1+)
$3$2$1

Cambie la Resistencia, así que ahora tiene P2, T1, F1; P1, T2, F2

(1*)1*,\1(1+)?
$#2

Si la resistencia es mayor que el poder del oponente, entonces sobrevive.

0(F)?;0(F)?
$#1;$#2

Si ambos mueren, el que tiene First Strike sobrevive.

F

De lo contrario, First Strike no hace ninguna diferencia.

Neil
fuente
1

C ++, 177 131 127 121 bytes

Aquí está mi solución no tan corta en C ++. Las habilidades son de 3 bits para cada criatura:

  1. D = 0x1 (0001)
  2. F = 0x2 (0010)
  3. I = 0x4 (0100)

Y simplemente devuelve 0 : si nadie muere, 1 : si las primeras criaturas mueren, 2 : si la segunda criatura muere y 3 : si ambas criaturas mueren.

[](int p,int t,int a,int r,int k,int b){return(a&2&&b^4)^(b&2&&a^4)?1+(a&2):((t<r||b&1&&r)&&a^4)+((k<p||a&1&&p)&&b^4)*2;}

Pruébalo en línea!

C ++, 85 81 bytes (Alternativa)

Al hacer un poco de trampa y capturar las variables en lambda y no pasarlas como argumentos, es posible llegar a 81 bytes. No sé si es una solución aceptable, así que la publico como alternativa.

[&]{s=(a&2&&b^4)^(b&2&&a^4)?1+(a&2):((t<r||b&1&&r)&&a^4)+((k<p||a&1&&p)&&b^4)*2;}

Pruébalo en línea!

DimChtz
fuente
Este es el código de golf , se espera que tales hacks, si no se requieren, compitan ... a menos que esté utilizando lenguajes de código de golf especialmente diseñados, lo que cambia un poco el juego.
3D1T0R
1

Perl 5, 245 bytes

$F[0]*=$F[4]if$F[2]=~/D/;$F[3]*=$F[1]if$F[5]=~/D/;$F[3]=0 if$F[2]=~/I/;$F[0]=0 if$F[5]=~/I/;$F[4]-=$F[0]if$F[2]=~/F/;$F[1]-=$F[3]if$F[5]=~/F/;if($F[1]>0&&$F[4]>0){$F[4]-=$F[0]if$F[2]!~/F/;$F[1]-=$F[3]if$F[5]!~/F/}$_=(0+($F[1]<=0)).(0+($F[4]<=0))

Corre con -lapE

Sin golf:

# Takes input in one lines, of the form:
# PPP TTT "<abilities>" PPP TTT "<abilities>"

$F[0] *= $F[4] if $F[2] =~ /D/;
$F[3] *= $F[1] if $F[5] =~ /D/;

$F[3] = 0 if $F[2] =~ /I/;
$F[0] = 0 if $F[5] =~ /I/;

$F[4] -= $F[0] if $F[2] =~ /F/;
$F[1] -= $F[3] if $F[5] =~ /F/;

if ($F[1] > 0 && $F[4] > 0) {
    $F[4] -= $F[0] if $F[2] !~ /F/;
    $F[1] -= $F[3] if $F[5] !~ /F/;
}

$_ = (0+ ($F[1] <= 0)) . (0+ ($F[4] <= 0));

"Toque mortal" se traduce como "tu poder ahora se multiplica por la dureza de tu enemigo", y "indestructible" se traduce como "el poder de tu enemigo ahora es cero", y este último tiene un precedente. El código ejecuta dos rondas, una donde solo los primeros huelguistas pueden atacar, y la otra donde solo los que no son los primeros huelguistas pueden atacar. Si la primera ronda resulta en una muerte, la segunda ronda no sucede. Como ya tratamos con el toque mortal e indestructible al principio, "muerte" es tan simple como verificar si la resistencia es mayor que cero o no.

Silvio Mayolo
fuente