Magic: The Gathering Combat with Abilities

16

en relation

Objectif:

Étant donné deux créatures avec des capacités de combat facultatives, renvoyez des valeurs uniques mais cohérentes qui représentent les créatures mortes, le cas échéant.

Contribution:

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

Chaque créature sera donnée sous forme de [P,T,"<abilities>"]. Ce sera dans le formulaire [P,T], [P,T,""]ou [P,T,0]s'il n'a pas de capacités, votre choix sur le formulaire. P est un entier> = 0, T est un entier> = 1. <abilities>est un sous-ensemble de "DFI", ou peut être représenté via un seul numéro / chaîne de bits si vous le souhaitez. L'ordre des drapeaux dépend également de vous.

Mécanique de combat:

Chaque créature a deux statistiques, Puissance et Robustesse dans cet ordre, et des capacités optionnelles. La puissance d'une créature est> = 0. La ténacité d'une créature est> = 1.

Chaque créature inflige simultanément des blessures égales à sa puissance à la créature adverse (à moins que l'une n'ait une première frappe). Si la valeur est supérieure ou égale à l'endurance de l'adversaire, il mourra (sauf s'il est indestructible).

Exemple: Alice est un 2/2, Bob est un 3/4, les deux sans capacités. Alice fera 2 dégâts à Bob et en prendra 3 en retour. La ténacité d'Alice est de 2 donc elle mourra, la ténacité de Bob est de 4 donc elle vivra.

Il n'y a que 3 capacités optionnelles que nous considérerons pour cela (bien qu'il y en ait plus dans le jeu). Ce seront des drapeaux à un caractère:

  • [D] eathtouch: Toute quantité de dégâts (X> 0) est considérée comme mortelle.
  • [F] première frappe: Inflige d'abord ses dégâts, capable de tuer l'autre créature avant qu'elle ne puisse attaquer. Si les deux créatures ont la première frappe, résolvez le combat normalement.
  • [I] indestructible: aucun montant de dégâts n'est considéré comme mortel, y compris Deathtouch.

Production:

Toute valeur cohérente pour chacun des quatre cas suivants. Veuillez indiquer les quatre valeurs dans votre réponse. Exemple de valeur de retour en parens:

  • Aucune créature n'est morte (0)
  • 1ère créature morte (1)
  • 2ème créature morte (2)
  • Les deux créatures sont mortes (3)

Règles:

  • L'entrée est garantie d'avoir deux créatures correctement formatées.
  • Si vous utilisez des personnages pour des capacités, vous pouvez supposer qu'ils sont ordonnés comme vous le souhaitez, mais publier l'ordre utilisé le cas échéant.
  • Si vous utilisez un nombre / chaîne de bits pour les capacités, postez l'encodage que vous utilisez. par exemple: 111est D/F/I, 7est D/F/I, etc.
  • Si une créature n'a pas de capacités, elle peut aussi être prise comme [P,T, ""]ou équivalent en nombre
  • Failles standard interdites
  • C'est le donc le code le plus court gagne.

Exemples:

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
la source
1
@ user71546 Ouais. Il y a un peu plus de règles impliquées, mais dans MtG, "Can'ts" l'emporte sur "Cans". Donc, fonctionnellement, Indestructible ignore Deathstrike. Modifié pour être plus explicite
Veskah
1
@ fəˈnɛtɪk, il subit encore des dégâts, il n'en meurt tout simplement pas. Attention, la question déforme également la règle. Ce devrait être "Les permanents [indestructibles] ne sont pas détruits par des dégâts mortels, et ils ignorent l'action basée sur l'état qui vérifie les dégâts mortels ".
Peter Taylor
4
" Si une créature n'a pas de capacité, elle doit être analysée comme [P, T]. [P, T," "] n'est pas valide " est une mauvaise règle. Il discrimine les langues à forte frappe sans aucun avantage.
Peter Taylor
2
@PeterTaylor Je veux garder les tableaux irréguliers mais vous avez raison, cela ne fait pas mieux. Ainsi, la règle a été supprimée
Veskah
1
@Veskah Puis-je prendre "D", "F", "I" comme nombres? D => 0, F => 1, I => 2
Luis felipe De jesus Munoz

Réponses:

6

Perl 5 , 248 octets

... sans espaces ni nouvelles lignes:

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 }

Essayez-le en ligne!

Ma version non golfée avec les dix tests de @Veskah (OP), les tests réussissent:

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.
la source
4

JavaScript, 137 125 120 111 octets

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)

J'utilise des nombres bitmap pour les capacités D = 4 F = 2 I = 1 ne le "DFI"serait 7. Ma sortie est Ni Mort 0, 1ère Mort 1, 2ème Died 2, deux sont morts 3.

Tests avec:

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)

Ce fut mon premier code de travail

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);
};

Ce que j'ai réduit à cet intermédiaire:

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
la source
Bienvenue chez PPCG! Et très belle première solution :) Je peux voir un certain potentiel pour le golf, mais je suis sur mon téléphone, après quelques bières, je ne peux donc pas tester correctement.
Shaggy
Voici une économie rapide de 7 octets: tio.run/##bc/RbsIgFAbg@z0FuxgBd7RwNEu2SPcgjERKtak1ZVHjle/…
Shaggy
@Hirsute. Joli! Bien sûr, l'opérateur virgule - quel noob je suis.
James
1
Nous étions tous nouveaux une fois :)
Shaggy
3

JavaScript (ES6), 83 76 octets

Prend l'entrée comme 6 arguments distincts: 2 x (Puissance, Robustesse, Capacités). Les capacités sont attendues sous forme de masques de bits avec:

  • 1
  • 2
  • 4

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

Essayez-le en ligne!

Commenté

(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
la source
3

C (gcc) , 114 113 95 bytes

Beaucoup de golf grâce au plafond et à 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);}

Compilez avec -DZ=P,T,F,p,t,f).

Essayez-le en ligne!

Nous vérifions (indépendamment, en raison de la symétrie des mécanismes de combat) si chacune des créatures survit au combat, ce qui se produit si l'une ou l'autre est vraie:

  • la créature est indestructible;
  • la créature a d'abord frappé ET l'autre non ET sa puissance est supérieure ou égale aux toughnes des autres (donc nous pouvons ignorer le contact mortel des autres);
  • l'autre créature n'a pas de contact mortel ET sa puissance est inférieure à notre endurance.

(Les anciennes conditions sont plus importantes).

Les entrées sont la puissance et l'endurance en tant qu'entiers, et les capacités en tant que champ de bits (1 = indestructible, 2 = contact avec la mort, 4 = première frappe), la sortie est également un champ de bits (1 = la première créature survit, 2 = la deuxième créature survit).

Max Yekhlakov
la source
1
Utilisation d'une macro -DZ=P,T,F,p,t,f) 96 octets - Essayez-le en ligne!
Logern
Utiliser P=…au lieu de return …et supprimer la nouvelle ligne vous amène à 85 octets.
De plus, -3 octets en remplaçant les opérateurs logiques &&, ||par bits &,|
2

Retina 0.8.2 , 123 octets

\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

Essayez-le en ligne! Lien inclut les cas de test, même si je l' ai substitué 9à 99999la vitesse. L'entrée utilise les lettres DFIbien que Ddoit précéder I. La sortie est au format 1pour survit et 0pour matrices. Explication:

\d+
$*

Convertissez les statistiques en unaire.

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

Échangez temporairement les statistiques.

F(.*)F
$1

Deux Fs annulent.

1+D
1

Le toucher mortel réduit la résistance de l'adversaire à 1.

1*(,1+)I
$1

Indestructible abaisse la puissance de l'adversaire à 0.

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

Redéfinissez la ténacité, vous avez donc maintenant P2, T1, F1; P1, T2, F2

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

Si la force est supérieure à la puissance de l'adversaire, elle survit.

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

Si les deux mouraient, celui avec First Strike survit.

F

Sinon, First Strike ne fait aucune différence.

Neil
la source
1

C ++, 177 131 127 121 121 octets

Voici ma solution pas si courte en C ++. Les capacités sont de 3 bits pour chaque créature:

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

Et il renvoie simplement 0 : si personne ne meurt, 1 : si les premières créatures meurent , 2 : si la deuxième créature meurt et 3 : si les deux créatures meurent.

[](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;}

Essayez-le en ligne!

C ++, 85 81 octets (Alternative)

En trichant légèrement et en capturant les variables dans lambda et en ne les passant pas comme arguments, il est possible de descendre à 81 octets. Je ne sais pas si c'est une solution acceptable, donc je la poste comme alternative.

[&]{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;}

Essayez-le en ligne!

DimChtz
la source
C'est du golf de code , de tels hacks sont attendus, si ce n'est nécessaire, afin de rivaliser ... à moins que vous n'utilisiez des langages de golf de code spécialement conçus, ce qui change un peu le jeu.
3D1T0R
1

Perl 5, 245 octets

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

Courir avec -lapE

Non 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));

"Deathtouch" se traduit par "votre puissance est maintenant multipliée par la ténacité de votre ennemi", et "indestructible" se traduit par "la puissance de votre ennemi est désormais nulle", ce dernier ayant préséance. Le code exécute deux tours, l'un où seuls les premiers attaquants peuvent attaquer et l'autre où seuls les non-premiers attaquants peuvent attaquer. Si le premier round entraîne un décès, le second round ne se produit pas. Puisque nous avons déjà traité du contact mortel et indestructible au début, la "mort" est aussi simple que de vérifier si la ténacité est supérieure à zéro ou non.

Silvio Mayolo
la source