Копи та грабіжники


11

Кожен завжди хоче реалізувати «Гра життя» Конвей. Це нудно! Давайте замість цього робимо копів та грабіжників!

У вас буде дві команди: поліцейські та грабіжники. Кожна команда має 5 членів з 50 здоров'ям у кожному. Програма буде циклічно постійно. Кожна ітерація відбуватиметься наступним чином:

  • Для кожної команди надрукуйте перший лист ( Cдля поліцейських, Rдля грабіжників), пробіл, розділений пробілом список членів HP та новий рядок. Це статус команд. Після того як обидва зроблені, надрукуйте ще один новий рядок. Наприклад, ось як це може виглядати перший тур:

    C 50 50 50 50 50
    R 50 50 50 50 50
    
  • Виберіть випадкове число від 1 до 10 (включаючи як 1, так і 10). Ми зателефонуємо на номер N. Якщо Nце рівно, грабіжники програють цей раунд; якщо дивно, поліцейські програють.

  • Виберіть випадкового члена команди, яка програла, чий HP більший за 0, і відрахуйте NHP. HP членів ніколи не повинен з’являтися нижче 0 за статусом.

  • Перезапустіть цикл.

Гра закінчується, коли всі члени однієї команди втрачають весь свій HP. Потім, якщо поліцейські переможуть, буде надруковано наступне:

C+
R-

і якщо розбійники переможуть:

R+
C-

Це кодовий гольф, тому виграє найменша кількість символів.

Ось приклад реалізації в 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+'

Незначна іронія: з 3176 питань на цьому веб-сайті не більше 11 позначено тегами game-of-life.
Санчіз

3
@sanchises Розширена іронія: і 14 позначено тегами cops-and-robbers!
Runer112

@sanchises Я в основному мав на увазі програмування взагалі (наприклад, "Допоможи мені! Я намагаюся реалізувати Гра життя життя Конвея!") ... але це все ще досить іронічно.
kirbyfan64sos

@ kirbyfan64sos я знаю (був там, робив це), але це саме той сайт, куди люди заходять після впровадження GoL і хочуть більше ... У будь-якому випадку, можливо, я буду переглядати це в> <> , давайте подивимось, чи можу я це зробити.
Санчіз

Я знову видалив тег CnR. Навколо цей тег має дуже специфічне значення і описує виклики, коли насправді дві (не обов'язково розбіжні) сторони, які конкурують один з одним за певні завдання (огляньте інші виклики з цим тегом).
Мартін Ендер

Відповіді:


3

CJam, 86 байт

Я трохи запізнююся на вечірку, але приношу подарунок CJam! ... Гей, чекай, куди ти йдеш?

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

Спробуйте в Інтернеті.

Пояснення

Оскільки запитання задають простий процес, це відповідь досить простий. Можливо, одним із цікавих виборів, які я зробив, було збереження здоров’я обох команд, що переплуталися в одному списку. Це коштує 3 байти для перетворення у два окремі списки, що потрібно як для показу здоров’я, так і для перевірки, чи програла команда. Але (я думаю) це складено двома байтами, збереженими в ініціалізації, і набагато простішою логікою боротьби з пошкодженнями.

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.";

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

Також чому на rep(which(x>0),2)противагу справедливому which(x>0)?
MickyT

1) Я рахую символи EOL, але не останній. 2) sum(R*C)і sum(R)*sum(C)не одне і те ж. Наприклад, ви б не хотіли виходити, якщо C = c (0,0,0,10,10) і R = c (10, 10, 10, 0, 0). У цьому випадку я заощаджую, призначаючи S=sum. 3) Проблема sampleполягає в тому, що якщо перший аргумент - це єдине число, наприклад sample(5, 1), тоді це буде те саме, що робити sample(1:5, 1): замість того, щоб завжди повертатися 5, він повертає будь-яке число з 1до 5. Тож sample(rep(x, 2), 1)мій трюк у тому, щоб завжди вибирати номер xнавіть у тому випадку, коли length(x)є 1.
flodel

Вибачте мій поганий ... Очевидно, кави мало. Дякуємо за пояснення щодо хитрості rep (). Я подумав, що має бути причина, просто не міг її побачити
MickyT

2

APL (Діалог) (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
∇

Пояснення:

  • S←2 5⍴50: на початку встановіть Sматрицю 5 на 2, де кожне значення дорівнює 50. Верхній рядок матриці представляє копії, другий ряд представляє грабіжників.
  • J←∨/S>0: для кожного рядка матриці зберігайте в Jтому, чи будь-який з HP більший за нуль.
  • →6/⍨~∧/J: якщо в обох команд немає живих членів, перейдіть до рядка 6. (кінець)
  • ⎕←3↑'CR',0⌈S: для кожного значення в матриці виведіть максимум його та 0, додайте "C" до першого рядка та "R" до другого та додайте третій (порожній) рядок.
  • N←?10: отримайте випадкове число в інтервалі [1,10] і збережіть його N.
  • L←1+~2⊤N: встановіть L(команда, що програла), 1якщо число було непарним і 2якщо воно було парним.
  • M←(0<S[L... ;])/⍳5: отримати індекси живих членів команди та зберегти їхM
  • M[?⍴M... ]: виберіть випадкове значення зM
  • S[L;M... ]-←N: відняти Nзначення вибраного члена команди
  • →2: перейти до рядка 2 (тест для живих членів)
  • ⎕←'CR',⍪'+-'⌽⍨J⍳0: вивести остаточний статус, поставивши +перед командою-переможцем і -перед командою, яка програла.

Вибірка зразка


1

Рубі, 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-'

1

Математика, 246 241 байт

Можливо, можна було б пограти в гольф далі ...

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]

1

PHP - 416 байт

Я новачок у гольфі, і хоча ця проблема буде досить легкою, щоб спробувати це. Тож ось що я придумав.

<?$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";}}?>

З поясненням:

<? 
$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
}
?>

Я не користувач PHP, але я здогадуюсь, що, можливо, ви вирізали б кілька символів, видаливши != 0та замінивши чек рівним нулю на оператор not ( !array_sum($r)).
kirbyfan64sos

@ kirbyfan64sos, що не працює
Тимо

Ой. У більшості мов це було б.
kirbyfan64sos

1

C, 390 384 371 байт

Мій перший гольф, якщо можливі вдосконалення, просто скажіть мені :)

версія для гольфу:

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

дещо неозорений варіант:

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

редагувати: я знайшов спосіб трохи скоротити його та виправив невеличку помилку


Невелике вдосконалення: ви можете замінити петлі (наприклад for(j=0;j<10;j++)) коротшою версією ( for(j=10;--j;)).
kirbyfan64sos

Ви абсолютно праві, "виправили" це та ще кілька незначних речей, дякую.
Metaforce

0

Пакетна - 396 байт

Я не знаю, чи це технічно підраховується - оскільки він насправді не вибирає випадкового члена команди , стан здоров'я якого перевищує 0 . Він просто вибирає випадковий член, і якщо віднімання здоров'я генерує число менше 0, то число стає 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!-

Вимога полягає в тому, щоб значення надрукованого статусу ніколи не було нижче 0 Я робив те саме на прикладі, який я показав.
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-')

0

Октава, 182 177 158 145 байт

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,:)

Я відмовився перевіряти, чи є зйомка символів вище нуля - це було б суттєво, лише якщо ми змушені відображати стан у кожному кроці - тут ми просто випадковим чином пропускаємо одне випадкове число з RNG, роблячи це більш випадковим.

Також замінено

t=max(0,t)

з коротшими

t.*=t>0


[зверніть увагу - він друкує "C + R-" без нового рядка - він зафіксований у версії 145 байт]

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

Дегольф:

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

Я змінився repmat(50,5,2)на repmat(5)- тому в нас зараз матриця 5x5 замість 5x2 (додаткові 3 стовпці не впливають на алгоритм). Я також знайшов спосіб стиснути вихід.

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

Дегольф:

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

В основному ми створюємо матрицю 5х2, де перший стовпчик - копи, а другий - грабіжники:

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

sumФункція , коли один аргумент застосовується робить суму за стовпцями, так що спочатку:

250    250

Коли одна з них досягає нуля, prod(sum(t))обчислюється нуль, розбиваючи цикл. Тоді ми можемо перевірити, хто переміг, перевіряючи, чия колонка дорівнює нулю.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.