Policjanci i złodzieje

11

Każdy zawsze chce wdrożyć grę życia Conwaya. To jest nudne! Zamiast tego zróbmy gliniarzy i złodziei!

Będziesz miał dwie drużyny: gliny i złodziei. Każda drużyna ma 5 członków o 50 zdrowiu. Program będzie się powtarzał w sposób ciągły. Po każdej iteracji wystąpią:

  • Dla każdej drużyny wydrukuj pierwszą literę ( Cdla gliniarzy, Rdla złodziei), spację, rozdzieloną spacjami listę HP członków i nową linię. To jest status zespołów. Po zakończeniu obu wydrukuj kolejny nowy wiersz. Na przykład, oto jak może to wyglądać w pierwszej rundzie:

    C 50 50 50 50 50
    R 50 50 50 50 50
    
  • Wybierz losową liczbę od 1 do 10 (w tym zarówno 1, jak i 10). Zadzwonimy pod ten numer N. Jeśli Njest parzysty, złodzieje przegrywają tę rundę; jeśli dziwne, gliny przegrywają.

  • Wybierz losowego członka przegranej drużyny, którego HP jest większe niż 0 i odejmij NHP. Punkty życia członków nigdy nie powinny pojawiać się poniżej statusu 0.

  • Uruchom ponownie pętlę.

Gra kończy się, gdy wszyscy członkowie jednej drużyny stracą całe swoje HP. Następnie, jeśli policjanci wygrają, zostaną wydrukowane następujące informacje:

C+
R-

a jeśli złodzieje wygrają:

R+
C-

To jest golf golfowy, więc wygrywa najmniejsza liczba znaków.

Oto przykładowa implementacja w Python 2:

import random

cops = [50]*5
robbers = [50]*5

while any(cops) and any(robbers):
    # print the status
    print 'C', ' '.join(map(str, cops))
    print 'R', ' '.join(map(str, robbers))
    print
    # pick N
    N = random.randint(1, 10)
    # pick the losing team (robbers if N is even, else cops)
    losers = robbers if N % 2 == 0 else cops
    # pick a member whose HP is greater than 0
    losing_member = random.choice([i for i in range(len(losers)) if losers[i]])
    losers[losing_member] -= N
    # make sure the HP doesn't visibly drop below 0
    if losers[losing_member] < 0: losers[losing_member] = 0

if any(cops):
    # robbers lost
    print 'C+'
    print 'R-'
elif any(robbers):
    # cops lost
    print 'C-'
    print 'R+'
kirbyfan64sos
źródło
Drobna ironia: spośród 3176+ pytań na tej stronie nie więcej niż 11 jest otagowanych game-of-life.
Sanchises
3
@sanchises Rozszerzona ironia: i 14 są oznaczone cops-and-robbers!
Runer112
@sanchises W dużej mierze miałem na myśli programowanie w ogóle (np. „Pomóż mi! Próbuję wdrożyć grę Conway's Game of Life!”) ... ale to wciąż dość ironiczne.
kirbyfan64sos
@ kirbyfan64sos Wiem (byłem tam, zrobiłem to), ale jest to dokładnie ten rodzaj strony, na którą odwiedzają ludzie po wdrożeniu GoL i chcą więcej ... W każdym razie, może spróbuję to zrobić w> <> , zobaczmy, czy mogę to zrobić.
Sanchises
Znów usunąłem tag CnR. W tym miejscu ten znacznik ma bardzo konkretne znaczenie i opisuje wyzwania, w których faktycznie istnieją dwie (niekoniecznie rozłączne) strony konkurujące ze sobą w niektórych zadaniach (rozejrzyj się po innych wyzwaniach z tym znacznikiem).
Martin Ender,

Odpowiedzi:

3

CJam, 86 bajtów

Jestem trochę spóźniony na imprezę, ale przynoszę prezent CJam! ... Hej czekaj, gdzie idziesz?

50aA*{"CR"1$+2/zSf*Nf+oNoAmr{_AmrE&+:P2$=:H!}gPH@)-Ue>t_2/z::+0#:L)!}g;'CL'+'-?N'R2$6^

Wypróbuj online.

Wyjaśnienie

Ponieważ pytania wymagają naśladowania prostego procesu, jest to stosunkowo prosta odpowiedź. Być może jednym z interesujących wyborów było utrzymanie zdrowia obu drużyn na tej samej liście. To kosztuje 3 bajty do konwersji na dwie osobne listy, co jest potrzebne zarówno do wyświetlania stanu zdrowia, jak i sprawdzania, czy zespół przegrał. Ale (tak sądzę) nadrabiają to 2 bajty zapisane podczas inicjalizacji i znacznie prostsza logika zadawania obrażeń.

50aA*           "Initialize the health list to 10 copies of 50. Even indices
                 hold the health of cops and odd indices hold the health of
                 robbers.";
{               "Do:";
  "CR"1$+2/z      "Split the health list into the two teams for output, adding
                   the corresponding team letter to the start of each.
                       [a b c d e f g h i j]
                    -> [['C a c e g i] ['R b d f h j]]";
  Sf*Nf+          "Insert a space between each element in each team health list
                   and append a newline to the end of each team health list.";
  oNo             "Print the health status for each team and an extra newline.";
  Amr             "Generate the damage amount minus one. If the damage amount is
                   even (robbers lose), then this is odd and aligns with robbers
                   being at odd indices in the health list, and vice versa.";
  {               "Do:";
    _AmrE&+:P       "Add a random even number from [0, 10) to the damage amount
                     minus one. This value modulo the size of the health list
                     (10) selects a person on the losing team to be damaged.";
    2$=:H!
  }g              "... While the selected person's health is zero.";
  PH@)-Ue>t       "Set the damaged person's new health to the maximum of their
                   current health minus the damage amount and zero.";
  _2/z::+0#:L     "Split the health list into the two teams, sum each team's
                   health, and search for a team's health equal to zero.";
  )!
}g              "... While no team's health was found equal to zero.";
;               "Discard the health list.";
'C              "Produce a 'C'.";
L'+'-?          "Produce a '+' if team 1 (robbers) lost, or '-' otherwise.";
N               "Produce a newline.";
'R              "Produce an 'R'.";
2$6^            "Produce the opposite of the sign produced before.";
                "Implicitly print these final results.";
Runer112
źródło
3

R - 201

S=sum
Z=sample
C=R=rep(50,5)
while(S(R)*S(C)){cat("C",C,"\nR",R,"\n\n")
N=Z(10,1)
F=function(x,i=Z(rep(which(x>0),2),1)){x[i]=max(0,x[i]-N);x}
if(N%%2)R=F(R)else C=F(C)}
cat(c("R+\nC-\n","C+\nR-\n")[1+!S(R)])
flodel
źródło
Również dlaczego w rep(which(x>0),2)przeciwieństwie do sprawiedliwego which(x>0)?
MickyT,
1) Liczę znaki EOL, ale nie ostatni. 2) sum(R*C)i sum(R)*sum(C)nie są tym samym. Na przykład nie chcesz wychodzić, jeśli C = c (0,0,0,10,10) i R = c (10, 10, 10, 0, 0). W takim przypadku oszczędzam, przypisując S=sum. 3) Problem samplepolega na tym, że jeśli pierwszy argument jest pojedynczą liczbą, np sample(5, 1). Będzie to to samo, co działanie sample(1:5, 1): zamiast zawsze zwracać 5, zwróci dowolną liczbę od 1do 5. Taka sample(rep(x, 2), 1)jest moja sztuczka polegająca na tym, że zawsze wybieram liczbę, xnawet w przypadku, gdy length(x)jest 1.
flodel
Przepraszam, moja zła ... Oczywiście za mało kawy. Dziękujemy za wyjaśnienie dotyczące sztuczki rep (). Myślałem, że musi być jakiś powód, po prostu go nie widziałem
MickyT
2

APL (Dyalog) (101)

∇K
S←2 5⍴50
→6/⍨~∧/J←∨/S>0
⎕←3↑'CR',0⌈S
S[L;M[?⍴M←(0<S[L←1+~2⊤N;])/⍳5]]-←N←?10
→2
⎕←'CR',⍪'+-'⌽⍨J⍳0
∇

Wyjaśnienie:

  • S←2 5⍴50: na początku ustaw Sna matrycę 5 na 2, gdzie każda wartość wynosi 50. Górny rząd matrycy reprezentuje gliniarzy, drugi rząd reprezentuje złodziei.
  • J←∨/S>0: dla każdego wiersza macierzy zapisz, Jczy którykolwiek z HP jest większy od zera.
  • →6/⍨~∧/J: jeśli nie obie drużyny mają żywych członków, przeskocz do linii 6. (koniec)
  • ⎕←3↑'CR',0⌈S: dla każdej wartości w macierzy, wypisz jej maksimum i 0, wstaw „C” do pierwszego wiersza i „R” do drugiego i dodaj trzeci (pusty) wiersz.
  • N←?10: uzyskaj losową liczbę w przedziale [1,10] i zapisz ją N.
  • L←1+~2⊤N: ustaw L(drużyna przegrywająca), 1czy liczba była nieparzysta i 2czy była parzysta.
  • M←(0<S[L... ;])/⍳5: pobierz indeksy żywych członków tego zespołu i zapisz jeM
  • M[?⍴M... ]: wybierz losową wartość zM
  • S[L;M... ]-←N: odejmij Nod wartości wybranego członka zespołu
  • →2: przeskocz do linii 2 (test dla żywych członków)
  • ⎕←'CR',⍪'+-'⌽⍨J⍳0: generuje końcowy status, stawiając +przed drużyną zwycięską i -przed drużyną przegrywającą.

Próbka wyjściowa

marinus
źródło
1

Ruby, 184

c,r=[p,p].map{('50 '*5).split}
puts([?C,*c]*' ',[?R,*r]*' ')while (u,v=[r,c].map{|a|a.shuffle.find{|x|x>?0}}).all?&&[u,v][rand(1..10)%2].sub!(/.+/){eval"#$&-1"}
puts u ?'R+
C-':'C+
R-'
histocrat
źródło
1

Mathematica, 246 241 bajtów

Prawdopodobnie można by dalej grać w golfa ...

a=ConstantArray[50,{2,5}];b=Or@@(#<1&)/@#&;c=Print;d=StringJoin@Riffle[IntegerString/@#," "]&;e=RandomInteger;Label@f;Which[b@a[[1]],c@"R+\nC-",b@a[[2]],c@"C+\nR-",True,c["C "<>d@a[[1]]<>"\nR "<>d@a[[2]]];a[[Mod[g=e@9+1,2]+1,e@4+1]]-=g;Goto@f]
LegionMammal978
źródło
1

PHP - 416 bajtów

Jestem nowym golfistą i choć to wyzwanie byłoby wystarczająco łatwe, aby je wypróbować. Oto co wymyśliłem.

<?$c=[50,50,50,50,50];$r=[50,50,50,50,50];while((array_sum($c)!=0)&&(array_sum($r)!=0)){$a="C ".join(" ",$c)."\n";$b="R ".join(" ",$r)."\n";echo$a,$b;$n=rand(1,10);$m=rand(0,4);if($n %2==0){while($r[$m]==0){$m=rand(0,4);}$r[$m]=$r[$m]-$n;if($r[$m]<0){$r[$m]=0;}}else{while($c[$m]==0){$m=rand(0,4);}$c[$m]=$c[$m]-$n;if($c[$m]<0){$c[$m]=0;}}if(array_sum($r)==0){echo"C+\nR-\n";}if(array_sum($c)==0){echo"R+\nC-\n";}}?>

Z wyjaśnieniem:

<? 
$c=[50,50,50,50,50];$r=[50,50,50,50,50];                       populate Arrays
while((array_sum($c) != 0) && (array_sum($r) != 0)){           loop until on array sums up to 0
    $a="C ".join(" ",$c)."\n";                                 set cops health to a
    $b="R ".join(" ",$r)."\n";                                 set robbers health to b
    echo$a,$b;                                                 print cop and robber health
    $n=rand(1,10);                                             chose random n
    $m=rand(0,4);                                              chose random member
    if($n % 2 == 0){                                           check if n is even
        while($r[$m] == 0){ $m=rand(0,4); }                    loop until value m of array r is not 0
        $r[$m]=$r[$m]-$n;                                      lower health of member m
        if($r[$m] < 0){ $r[$m]=0; }                            if health goes below 0 set it to 0
    }else{
        while($c[$m] == 0){ $m=rand(0,4); }                    same as above
        $c[$m]=$c[$m] - $n;
        if($c[$m] < 0){$c[$m]=0;}
    }
    if(array_sum($r) == 0){ echo"C+\nR-\n"; }                  check if r array sums up to 0 and print that cops won
    if(array_sum($c) == 0){ echo"R+\nC-\n"; }                  check if c array sums up to 0 and print that robbers won
}
?>
Timo
źródło
Nie jestem użytkownikiem PHP, ale zgaduję, że może skróciłbyś kilka znaków, usuwając != 0i zastępując czek równy zeru operatorem not ( !array_sum($r)).
kirbyfan64sos
@ kirbyfan64sos że nie działa
Timo
O. W większości języków tak by było.
kirbyfan64sos
1

C, 390 384 371 bajtów

Mój pierwszy golf, jeśli są jakieś możliwe ulepszenia, po prostu powiedz mi :)

wersja golfowa:

#include <time.h>
#include <stdio.h>
int p[10],j,r,c,w,N,x;int s(){r=c=0;for(j=5;j--;){c+=p[5+j];r+=p[j];}return !!r-!!c;}void t(){for(j=10;j--;)printf("%s %d",j-4?j-9?"":"\n\nC":"\nR",p[j]*=p[j]>0);}main(){srand(time(0));for(j=10;j--;)p[j]=50;t();while(!(w=s())){N=rand()%10+1;while(!p[x=N%2*5+rand()%5]);p[x]-=N;t();}N=(x=w<1?'C':'R')-w*15;printf("\n\n%c+\n%c-",x,N);}

nieco nie golfowa wersja:

#include <time.h>
#include <stdio.h>
int p[10],j,r,c,w,N,x;

int s(){
    r=c=0;
    for(j=5;j--;){
        c+=p[5+j];
        r+=p[j];
    }
    return !!r-!!c;
}

void t(){
    for(j=10;j--;)printf("%s %d",j-4?j-9?"":"\n\nC":"\nR",p[j]*=p[j]>0);
}

main(){
    srand(time(0));
    for(j=10;j--;)p[j]=50;
    t();
    while(!(w=s())){
        N=rand()%10+1;
        while(!p[x=N%2*5+rand()%5]);
        p[x]-=N;
        t();
    }
    //w=-1 if cops won, w=1 if robbers won
    N=(x=w<1?'C':'R')-w*15;
    printf("\n\n%c+\n%c-",x,N);
}

edytuj: Znalazłem sposób na jego skrócenie i naprawiłem mały błąd

Metaforce
źródło
Mała poprawka: możesz zastąpić pętle (np. for(j=0;j<10;j++)) Krótszą wersją ( for(j=10;--j;)).
kirbyfan64sos
Masz całkowitą rację, „naprawiłeś” to i kilka innych drobiazgów, dzięki.
Metaforce
0

Partia - 396 bajtów

Nie wiem, czy to się liczy technicznie - ponieważ tak naprawdę nie wybiera losowego członka zespołu, którego zdrowie jest większe niż 0 . Po prostu wybiera losowego członka, a jeśli odejmowanie zdrowia generuje liczbę mniejszą niż 0, wówczas liczba staje się 0.

@echo off&setLocal enableDelayedExpansion&for %%a in (C R)do for %%b in (1 2 3 4 5)do set %%a%%b=50
:a
set/aN=%RANDOM%*10/32768+1
set/ac=%N%/2*2
if %c%==%N% (set T=C&set L=R)else set T=R&set L=C
set/aG=%RANDOM%*5/32768+1
set/a%T%%G%-=%N%
for %%a in (C R)do set %%a=0&for %%b in (1 2 3 4 5)do (if !%%a%%b! LEQ 0 set %%a%%b=0
set/a%%a+=!%%a%%b!)
if %C% NEQ 0 if %R% NEQ 0 goto :a
echo !T!+&echo !L!-
nieszczęście
źródło
Wymagane jest, aby wartość nigdy nie wyświetlała się poniżej zera na statusie wydruku. Zrobiłem to samo w pokazanym przykładzie.
kirbyfan64sos
0

JavaScript: 410

function x(l){var t=this,o=t.p={n:l||"C",h:[50,50,50,50,50],s:function(){return o.h.reduce(function(a,b){return a+b})},r:function(){console.log(o.n+' '+o.h.join(' '))},d:function(m){while(o.h[z=~~(Math.random()*5)]<1){}o.h[z]=m>o.h[z]?0:o.h[z]-m}};o.r()}q=[new x(),new x('R')];while((c=q[0].p.s()>0)&&q[1].p.s()>0){q[(z=~~(Math.random()*10))%2].p.d(z);q[0].p.r();q[1].p.r()}console.log(c?'C+\r\nR-':'R+\n\rC-')
logika 8
źródło
0

Oktawa, 182 177 158 145 bajtów

145:

t=repmat(50,5);while prod(any(t))d=ceil(rand*10);c=2-mod(d,2);r=ceil(rand*5);t(r,c)-=d;t.*=t>0;end;p=2*any(t,1);['C-';'R+';'C+';'R-'](1+p:2+p,:)

Zrezygnowałem z sprawdzania, czy strzelanie do postaci jest powyżej zera - byłoby to znaczące tylko, gdybyśmy byli zmuszeni wyświetlać stan w każdej turze - tutaj po prostu losowo pomijamy jedną liczbę losową z RNG, co czyni ją bardziej losową.

Również zastąpiony

t=max(0,t)

z krótszym

t.*=t>0


[uwaga - drukuje „C + R-” bez nowej linii - jest naprawiony w wersji 145-bajtowej]

158:

t=repmat(50,5);while prod(any(t))d=ceil(rand*10);c=2-mod(d,2);do r=ceil(rand*5);until t(r,c);t(r,c)-=d;t=max(0,t);end;p=4*any(t,1);disp('C-R+C+R-'(1+p:4+p))

Degolfed:

t=repmat(50,5);               #only first two columns (cops, robbers) relevant
while prod(any(t))
    d=ceil(rand*10);
    c=2-mod(d,2);
    do r=ceil(rand*5);until t(r,c);
    t(r,c)-=d;
    t=max(0,t);
end;
p=4*any(t,1);
disp('C-R+C+R-'(1+p:4+p))

Zmieniłem repmat(50,5,2)na repmat(5)- więc mamy teraz macierz 5x5 zamiast 5x2 (dodatkowe 3 kolumny nie wpływają na algorytm). Znalazłem również sposób na skompresowanie wyjścia.

177:

t=repmat(50,5,2);while prod(sum(t))d=ceil(rand*10);c=2-mod(d,2);do r=ceil(rand*5);until t(r,c);t(r,c)-=d;t=max(0,t);end;if sum(t)(1)printf "C+\nR-\n";else printf "C-\nR+\n";end

Degolfed:

t=repmat(50,5,2);
while prod(sum(t))
    d=ceil(rand*10);
    c=2-mod(d,2);                  #cops or robbers affected?
    do r=ceil(rand*5);until t(r,c);
    t(r,c)-=d;
    t=max(0,t);
end
if sum(t)(1)
    printf "C+\nR-\n"
else
    printf "C-\nR+\n"
end

Zasadniczo tworzymy macierz 5x2, w której pierwsza kolumna to gliniarze, a druga kolumna to rabusie:

t =
50     50
50     50
50     50
50     50
50     50
[cops] [robbers]

sumFunkcja gdy zastosowano jeden argument sprawia sumę kolumnami, dlatego początkowo:

250    250

Gdy jeden z nich osiągnie zero, prod(sum(t))wartość do zera przerywa pętlę. Następnie możemy sprawdzić, kto wygrał, sprawdzając, którego kolumna sumuje się do zera.

pawel.boczarski
źródło