Magic: The Gathering Combat with Abilities

16

Związane z

Cel:

Biorąc pod uwagę dwa stworzenia z opcjonalnymi zdolnościami bojowymi, zwracaj unikalne, ale spójne wartości, które reprezentują, które stworzenia zginęły, jeśli w ogóle.

Wejście:

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

Każde stworzenie otrzyma w formie [P,T,"<abilities>"]. Będzie w formie [P,T], [P,T,""]lub [P,T,0]jeśli nie ma zdolności, twój wybór w formie. P jest liczbą całkowitą> = 0, T jest liczbą całkowitą> = 1. <abilities>jest podzbiorem "DFI"lub może być reprezentowany przez jeden numer / ciąg bitów, jeśli chcesz. Kolejność flag zależy również od Ciebie.

Mechanika walki:

Każde stworzenie ma dwie statystyki, Moc i Wytrzymałość w tej kolejności oraz opcjonalne umiejętności. Moc stworzenia wynosi> = 0. Wytrzymałość stworzenia wynosi> = 1.

Każde stworzenie wyrządzi jednocześnie obrażenia równe swojej sile przeciwnemu stworzeniu (chyba, że ​​ktoś zadaje pierwsze ciosy). Jeśli wartość jest większa lub równa wytrzymałości przeciwnika, umrze (chyba że jest niezniszczalny).

Przykład: Alice jest a 2/2, Bob jest 3/4oboje bez umiejętności. Alice zada 2 obrażenia Bobowi i w zamian otrzyma 3 obrażenia. Wytrzymałość Alicji wynosi 2, więc umrze, wytrzymałość Boba wynosi 4, więc będzie żyć.

Istnieją tylko 3 opcjonalne zdolności, które rozważymy w tym celu (chociaż w grze jest ich więcej). Będą to flagi jednego znaku:

  • [D] eathtouch: Każda ilość obrażeń (X> 0) jest uważana za śmiertelną.
  • [F] pierwsze uderzenie: Najpierw zada obrażenia, zdolne zabić drugie stworzenie, zanim będzie mogło zaatakować. Jeśli oba stworzenia mają Pierwsze Uderzenie, rozstrzygnij walkę jak zwykle.
  • [I] niezniszczalny: Żadna ilość obrażeń nie jest uważana za śmiertelną, w tym Deathtouch.

Wynik:

Dowolna spójna wartość dla każdego z następujących czterech przypadków. Proszę podać cztery wartości w swojej odpowiedzi. Przykładowa wartość zwracana w parens:

  • Żadne stworzenie nie umarło (0)
  • 1. istota zmarła (1)
  • 2. istota zmarła (2)
  • Oba stworzenia umarły (3)

Zasady:

  • Wejście ma zagwarantowane dwa poprawnie sformatowane stworzenia.
  • Jeśli używasz postaci do umiejętności, możesz założyć, że są one uporządkowane tak, jak chcesz, ale w razie potrzeby opublikuj kolejność ich użycia.
  • Jeśli używasz liczby / ciągu bitowego dla umiejętności, opublikuj kodowanie, którego używasz. np .: 111jest D/F/I, 7jest D/F/Iitp.
  • Jeśli stwór nie ma umiejętności, można go również przyjąć jako [P,T, ""]ekwiwalent liczbowy lub ekwiwalent
  • Standardowe luki zabronione
  • To jest więc wygrywa najkrótszy kod.

Przykłady:

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
źródło
1
@ user71546 Tak. W grę wchodzi nieco więcej zasad, ale w MtG „Can'ts” przebija „Puszki”. Tak więc funkcjonalnie niezniszczalny ignoruje Deathstrike. Zredagowano to, aby być bardziej wyraźnym
Veskah
1
@ fəˈnɛtɪk, wciąż otrzymuje obrażenia, po prostu nie umiera z tego powodu. Pamiętaj, że pytanie to również zniekształca regułę. Powinno to być: „ [Niezniszczalne] permanenty nie są niszczone przez śmiertelne obrażenia i ignorują działanie oparte na stanie, które sprawdza śmiertelne obrażenia ”.
Peter Taylor,
4
Jeśli istota nie ma umiejętności, musi zostać sparsowana jako [P, T]. [P, T,„ ”] jest nieważny ” jest złą zasadą. Dyskryminuje języki przy silnym pisaniu bez żadnych korzyści.
Peter Taylor,
2
@PeterTaylor Chcę zachować postrzępione tablice, ale masz rację, że nie poprawi to. W ten sposób reguła została usunięta
Veskah
1
@Veskah Czy mogę traktować cyfry jako „D”, „F”, „I”? D => 0, F => 1, I => 2
Luis felipe De jesus Munoz

Odpowiedzi:

6

Perl 5 , 248 bajtów

... bez spacji i znaków nowej linii:

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 }

Wypróbuj online!

Moja nie golfowa wersja z dziesięcioma testami z @Veskah (OP), testy przechodzą:

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.
źródło
4

JavaScript, 137 125 120 111 bajtów

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)

Używam liczb bitmapowych dla zdolności D = 4 F = 2 I = 1 "DFI"byłoby 7. Mój dorobek to Ani umarł 0, 1. umarł 1, 2. umarł 2, oboje zmarli 3.

Testy z:

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)

To był mój pierwszy działający kod

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

Które zredukowałem do tego półproduktu:

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
źródło
Witamy w PPCG! I bardzo fajne pierwsze rozwiązanie :) Widzę potencjał do gry w golfa, ale jestem przy telefonie, po kilku piwach, więc nie mogę poprawnie przetestować.
Kudłaty
Oto szybkie oszczędzanie 7 bajtów: tio.run
Kudłaty
@Kudłaty. Niezłe! Oczywiście operator przecinka - jakim jestem noobem.
James
1
Wszyscy byliśmy kiedyś nowi :)
Kudłaty
3

JavaScript (ES6), 83 76 bajtów

Przyjmuje dane wejściowe jako 6 różnych argumentów: 2 x (Moc, Wytrzymałość, Zdolności). Zdolności są oczekiwane jako maski bitowe z:

  • 1
  • 2)
  • 4

012)3)

(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

Wypróbuj online!

Skomentował

(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
źródło
3

C (gcc) , 114 113 95 bajtów

Dużo gry w golfa dzięki CeCatcat i 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);}

Kompiluj z -DZ=P,T,F,p,t,f).

Wypróbuj online!

Sprawdzamy (niezależnie, z powodu symetrii mechaniki walki), czy każde ze stworzeń przetrwa walkę, co dzieje się, jeśli jedno z nich jest prawdziwe:

  • stworzenie jest niezniszczalne;
  • stwór ma pierwsze uderzenie ORAZ drugi nie ORAZ jego moc jest większa lub równa twardości innych (dlatego możemy zignorować dotyk śmierci drugiego człowieka);
  • inne stworzenie nie ma dotyku śmierci ORAZ jego moc jest mniejsza niż nasza wytrzymałość.

(Poprzednie warunki są ważniejsze).

Dane wejściowe to moc i wytrzymałość jako liczby całkowite oraz umiejętności jako pole bitowe (1 = Niezniszczalny, 2 = Śmierć, 4 = Pierwsze uderzenie), wyjście to także pole bitowe (1 = Pierwsze stworzenie przeżyje, 2 = Drugie stworzenie przeżyje).

Max Yekhlakov
źródło
1
Korzystanie z makra -DZ=P,T,F,p,t,f) 96 bajtów - wypróbuj online!
Logern
Używanie P=…zamiast return …i usuwanie nowej linii prowadzi do 85 bajtów.
Również -3 bajtów zastępując operatorów logicznych &&, ||z bitowe &,|
2

Retina 0.8.2 , 123 bajtów

\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

Wypróbuj online! Link obejmuje przypadków testowych, chociaż mam podstawione 9za 99999prędkość. Wejście używa liter, DFIchociaż Dmusi poprzedzać I. Wyjście ma format 1przetrwania i 0śmierci. Wyjaśnienie:

\d+
$*

Konwertuj statystyki na unary.

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

Tymczasowo wymień statystyki.

F(.*)F
$1

Dwa Fs anulowane.

1+D
1

Death Touch obniża Wytrzymałość przeciwnika do 1.

1*(,1+)I
$1

Niezniszczalny obniża Moc przeciwnika do 0.

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

Cofnij Wytrzymałość z powrotem, teraz masz P2, T1, F1; P1, T2, F2

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

Jeśli Wytrzymałość jest wyższa niż Moc przeciwnika, wówczas przetrwa.

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

Jeśli oboje zginą, przetrwa ten z Pierwszym Uderzeniem.

F

W przeciwnym razie First Strike nie ma znaczenia.

Neil
źródło
1

C ++, 177 131 127 121 bajtów

Oto moje nie tak krótkie rozwiązanie w C ++. Zdolności to 3 bity dla każdego stworzenia:

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

I po prostu zwraca 0 : jeśli nikt nie umiera, 1 : jeśli pierwsze stworzenia umierają, 2 : jeśli drugie stworzenie umiera, i 3 : jeśli oba stworzenia umierają.

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

Wypróbuj online!

C ++, 85 81 bajtów (alternatywnie)

Lekko oszukując i przechwytując zmienne w lambda i nie przekazując ich jako argumentów, można uzyskać do 81 bajtów. Nie wiem, czy jest to akceptowalne rozwiązanie, więc zamieszczam je jako alternatywę.

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

Wypróbuj online!

DimChtz
źródło
To jest gra w golfa , takie hacki są oczekiwane, jeśli nie są wymagane, aby konkurować ... chyba że używasz specjalnie zaprojektowanych języków gry w golfa, co nieco zmieni grę.
3D1T0R
1

Perl 5, 245 bajtów

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

Biegnij z -lapE

Nie golfowany:

# 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” przekłada się na „twoja moc jest teraz mnożona przez wytrzymałość twojego wroga”, a „niezniszczalny” przekłada się na „siła twojego wroga jest teraz zerowa”, przy czym ten ostatni ma pierwszeństwo. Kod uruchamia dwie rundy, jedną, w której atakują tylko pierwsi napastnicy, a drugą, w której atakują tylko nie-pierwsi. Jeśli pierwsza runda zakończy się śmiercią, druga runda nie nastąpi. Ponieważ już na początku zajmowaliśmy się dotykiem śmierci i niezniszczalnym, „śmierć” jest tak prosta, jak sprawdzenie, czy wytrzymałość jest większa od zera, czy nie.

Silvio Mayolo
źródło