Полицейские и грабители


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 и хотят большего ... В любом случае, возможно, я попробую это сделать в> <> Давайте посмотрим, смогу ли я это сделать.
Sanchises

Я снова удалил тег 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 байта, что необходимо как для отображения состояния здоровья, так и для проверки, проиграла ли команда. Но (я думаю) это компенсируется 2 байтами, сохраненными при инициализации, и гораздо более простой логикой нанесения ущерба.

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

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

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

Я изменил repmat(50,5,2)на repmat(5)- поэтому у нас теперь матрица 5х5 вместо 5х2 (дополнительные 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

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

По сути, мы создаем матрицу 5x2, где первый столбец - копы, а второй - грабители:

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.