Escreva o jogo mais curto de alak

10

Alak foi inventado pelo matemático AK Dewdney e descrito em seu livro de 1984, Planiverse. As regras do Alak são simples:

Alak é um jogo para dois jogadores jogado em um tabuleiro unidimensional com onze slots. Cada slot pode conter no máximo uma peça de cada vez. Existem dois tipos de peças, "x" e "o". x pertence a um jogador, o é ao outro. A configuração inicial da placa é:

      xxxx___oooo

Os jogadores se revezam em movimento. A cada turno, cada jogador pode mover apenas uma peça, uma vez. Um jogador não pode deixar passar o seu turno. Um jogador pode mover qualquer uma de suas peças para o próximo slot desocupado, à sua direita ou esquerda, o que pode envolver saltar sobre os slots ocupados. Um jogador não pode mover uma peça para o lado do tabuleiro.

Se um movimento cria um padrão em que as peças do oponente são cercadas, em ambos os lados, por duas peças da cor do movedor (sem nenhum espaço em branco desocupado), essas peças cercadas são removidas do tabuleiro.

O objetivo do jogo é remover todas as peças do seu oponente, quando o jogo termina. A remoção de tudo menos um termina o jogo também, já que o adversário não pode cercá-lo com uma peça e, portanto, sempre perde alguns movimentos.

Encontrei este jogo online e fiquei pensando: ele pode ser jogado de golfe?

Regras do golfe

  • Seu código deve seguir todas as regras do jogo, lidar com capturas, movimentação adequada etc. (a única exceção é que você não precisa adicionar um bot, mas você deve ter os dois jogadores controlados de alguma forma e um jogador deve ser humano).
  • A entrada deve ser movida na peça X para a peça Y ou sair. Por exemplo, você pode usar 1 4para dizer 'mover esta peça do ladrilho 1 para o ladrilho 4'. quitterminaria o programa, apesar de usar Control- Cseria aceitável. Você também deve verificar se uma movimentação é inválida (saindo do quadro ou movendo-se para algum lugar em que você precisaria atravessar espaços desocupados para chegar ou enviar uma mensagem que não seja um par de blocos ou quit).
  • Saídas para jogadores vencedores e inválida deve ser P1 WINS, P2 WINSe INVALID, respectivamente. (Todos esses são 7 caracteres.)
  • A saída deve mostrar a placa. É tudo o que é necessário.
  • Não importa se você usa algum auxílio, como peças numeradas ou outras peças.
  • O desafio termina se:

    • Uma resposta recebe 50 votos
    • Uma resposta continua sendo a mais votada por 3 semanas e nenhuma outra resposta foi publicada nesse período

e o desafio tem pelo menos três respostas (por isso há uma concorrência real).

Regras do jogo

  • O jogador à esquerda deve começar primeiro.
  • Apenas uma peça ocupa um quadrado de cada vez. Você move a peça para a esquerda ou direita até atingir um espaço desocupado. O quadro não quebra e você não pode se mover por áreas desocupadas. Por exemplo:
    • xoo__o. Aqui, o xmovimento à direita mudaria o quadro para _oox_o.
    • xxooo_. Aqui, a extrema esquerda xpode mover-se para render _xooox, que captura os os, saindo _x___x.
    • x__oox. Aqui, os os não são capturados (ainda há uma lacuna). A captura não é possível porque você não pode se mover por espaços desocupados. A xesquerda pode mover apenas um espaço, porque não há outras peças no meio (saindo _x_oox).
  • Várias peças adjacentes podem ser capturadas de uma só vez se o grupo estiver cercado pelas peças do oponente. Por exemplo, de x_ooxpara _xooxcapturará ambos se oresultará em _x__x.
  • Se após um movimento, você primeiro captura as peças do oponente , antes de verificar se sua própria peça deve ser removida. Veja dois exemplos:
    • o_oxxpara oxox_. Primeiro, o segundo oé capturado e ox_x_, portanto, o primeiro xpermanece no quadro.
    • o_ooxpara oxoo_. Desta vez, nenhum dos os é capturado, então o xé capturado.
    • Se você tiver apenas uma peça, o jogo termina, porque você não pode capturar com apenas uma peça.

Que os jogos comecem! Estou ansioso para ver o que você cria.

ASCIIThenANSI
fonte
Os comentários foram eliminados por serem obsoletos. Por favor, avise-me sobre quaisquer comentários que devam ser retirados.
Maçaneta

Respostas:

9

C, 617 592 bytes

#define O(x)(x-'x'?'x':'o')
q,f,t,k,i,x=4,o=4,*d;main(){char*A,Q[9],c='x',b[]="xxxx___oooo";printf(b);while(!q){scanf(" %8[^\n]%*[^\n]",Q);if(!strcmp(Q,"quit"))break;f=*Q>47&&*Q<58?atoi(Q):-1;A=f>9?Q+2:Q+1;t=*A==32&&A[1]>47&&A[1]<58?atoi(A+1):-1;i=t==f&&t<0&&f<0?1:0;for(k=f;k!=t;k+=(t-f)/abs(t-f))if(b[k]==95||b[t]-95||b[f]-c)i=1;if(i){printf("INVALID");continue;}b[t]=c;b[f]=95;for(t=0;t<2;t++){d=c-'x'?&o:&x;for(k=1;k<11;k++)if(b[k]==O(c)){for(i=k+1;b[i]==O(c)&&b[i];i++);if(b[i]==c&&b[k-1]==c)while(k<i)b[k++]=95,(*d)--;}c=t?c:O(c);}printf(b);if(o<2||x<2)printf("P%d WINS",(x>1)+1),q=1;}}

Desvendado:

#define O(x)(x-'x'?'x':'o')
q,f,t,k,i,x=4,o=4,*d;
main(){
    char*A,Q[9],c='x',b[]="xxxx___oooo";
    printf(b);
    while(!q){
        scanf(" %8[^\n]%*[^\n]",Q);
        if(!strcmp(Q,"quit"))break;
        f=*Q>47&&*Q<58?atoi(Q):-1;
        A=f>9?Q+2:Q+1;
        t=*A==32&&A[1]>47&&A[1]<58?atoi(A+1):-1;
        i=t==f&&t<0&&f<0?1:0;
        for(k=f;k!=t;k+=(t-f)/abs(t-f))
            if(b[k]==95||b[t]-95||b[f]-c)
                i=1;
        if(i){
            printf("INVALID");
            continue;
        }
        b[t]=c;
        b[f]=95;
        for(t=0;t<2;t++){
            d=c-'x'?&o:&x;
            for(k=1;k<11;k++)
                if(b[k]==O(c)){
                    for(i=k+1;b[i]==O(c)&&b[i];i++);
                    if(b[i]==c&&b[k-1]==c)
                        while(k<i)b[k++]=95,(*d)--;
                }
            c=t?c:O(c);
        }
        printf(b);
        if(o<2||x<2)printf("P%d WINS",(x>1)+1),q=1;
    }
}

Eu realmente queria obter este em ~ 400 bytes, mas existem muitas regras aqui e o processamento de entrada acabou sendo desagradável. Definitivamente ainda não acabei com isso. Aqui está um conjunto de execuções de amostra que cobrem quase tudo:

xxxx___oooo0 4
_xxxx__oooo7 6
_xxxx_o_ooo4 5
_xxx_xo_ooo8 6
INVALID8 7
_xxx_xoo_oo3 4
_xx_xxoo_oo7 3
_xxo__o__oo1 4
__x_x_o__oo10 9
INVALID10 8
__x_x_o_oo_2 3
___xx_o_oo_6 5
___xxo__oo_6 6
INVALID5 5
INVALID3 6
____x_x_oo_8 7
____x_xo_o_6 8
____x__o_o_P2 WINS

xxxx___oooo0 4
_xxxx__oooo10 6
_xxxx_oooo_1 5
__xxxxoooo_9 1
_o____ooo__P2 WINS

xxxx___oooo0 4
_xxxx__oooo7 6
_xxxx_o_ooo1 5
__xxxxo_ooo10 7
__xxxxoooo_2 10
___xxx____xP1 WINS

xxxx___oooo3 4
xxx_x__ooooquits
INVALIDtestme
INVALID3*4
INVALID3 four
INVALIDthree four
INVALIDthisstringislongerthanmybuffer
INVALID10 0
INVALID4 5
INVALID7 6
xxx_x_o_oooquit

Se eu interpretei algo errado, entre em contato!

BrainSteel
fonte
Eu testei, funciona bem e nada foi deixado de fora. Bom trabalho!
ASCIIThenANSI
Você pode economizar alguns bytes, substituindo printf("INVALID");com puts("INVALID");, o<2||x<2com o<2|x<2e printf(b);while(!q){comfor(printf(b);!q;){
es1024
3

PHP - 505

<?php
$s="xxxx___ooo".$y=o;$x=x;$c=function($m)use(&$x){return$x.str_repeat('_',strlen($m[1])).$x;};$e='$s=preg_replace_callback("~$x($y+)$x~",$c,$s);';$_=substr_count;while(true){echo$s;if($_($s,x)<2)die("P2 WINS");if($_($s,o)<2)die("P1 WINS");$i=trim(fgets(STDIN));if($i=='quit')die;if(!preg_match('!^(\d+) (\d+)$!',$i,$m)||$s[$f=$m[1]]!=$x||$s[$t=$m[2]]!="_"||(0&($a=min($f,$t))&$b=max($f,$t))||$_($s,"_",$a,($b-$a)+1)>1)echo"INVALID\n";else{$s[$f]='_';$s[$t]=$x;eval($e);$z=$x;$x=$y;$y=$z;eval($e);}}

Os avisos devem ser suprimidos redirecionando STDERRpara /dev/null.

Com espaço em branco são:

<?php
@$s = "xxxx___ooo".($y = o);
@$x = x;
$c = function($m)usea(&$x){
    return$x.str_repeat('_',strlen($m[1])).$x;
};
$e = '$s=preg_replace_callback("~$x($y+)$x~",$c,$s);';
@$_ = substr_count;
while (true){
    echo $s;

    if (@$_($s,x) < 2) die("P2 WINS");
    if (@$_($s,o) < 2) die("P1 WINS");

    $i = trim(fgets(STDIN));
    if($i == 'quit') die;

    if( !preg_match('!^(\d+) (\d+)$!',$i,$m)
    ||   $s[$f = $m[1]] != $x
    ||  @$s[$t = $m[2]] != "_"
    ||  (0 & ($a = min($f, $t)) & $b = max($f, $t))
    ||  $_($s, "_", $a, ($b - $a) + 1) > 1
    ) echo "INVALID\n";
    else {
        $s[$f] = '_';
        $s[$t] = $x;
        eval($e);
        $z = $x;
        $x = $y;
        $y = $z;
        eval($e);
    }
}

Com os casos de teste do BrainSteel:

xxxx___oooo0 4
_xxxx__oooo7 6
_xxxx_o_ooo4 5
_xxx_xo_ooo8 6
INVALID
_xxx_xo_ooo8 7
_xxx_xoo_oo3 4
_xx_xxoo_oo7 3
_xxo__o__oo1 4
__x_x_o__oo10 9
INVALID
__x_x_o__oo10 8
__x_x_o_oo_2 3
___xx_o_oo_6 5
___xxo__oo_6 6
INVALID
___xxo__oo_5 5
INVALID
___xxo__oo_3 6
____x_x_oo_8 7
____x_xo_o_6 8
____x__o_o_P2 WINS

xxxx___oooo0 4
_xxxx__oooo10 6
_xxxx_oooo_1 5
__xxxxoooo_9 1
_o____ooo__P2 WINS

xxxx___oooo0 4
_xxxx__oooo7 6
_xxxx_o_ooo1 5
__xxxxo_ooo10 7
__xxxxoooo_2 10
___xxx____xP1 WINS

xxxx___oooo3 4
xxx_x__ooooquits
INVALID
xxx_x__ooootestme
INVALID
xxx_x__oooo3*4
INVALID
xxx_x__oooo3 four
INVALID
xxx_x__oooothree four
INVALID
xxx_x__oooothisstringislongerthanmybuffer
INVALID
xxx_x__oooo10 0
INVALID
xxx_x__oooo4 5
INVALID
xxx_x__oooo7 6
xxx_x_o_oooquit
TimWolla
fonte
O que você quer dizer com 'avisos / avisos'?
ASCIIThenANSI
@ASCIIThenANSI Warnings por causa de literais de caracteres não citados: PHP Aviso: Uso da constante indefinida o - assumida 'o' em /tmp/pcg-48388.php na linha 2. Pode-se redirecioná-los para / dev / null.
TimWolla
Isso quebra o programa?
ASCIIThenANSI
@ASCIIThenANSI Não, ele funciona bem porque eles são redirecionados /dev/null.
TimWolla
Não há problema em mantê-lo enquanto o programa continuar funcionando corretamente e eles forem redirecionados para /dev/null.
ASCIIThenANSI
1

Python 2, 536 509 448 441 bytes

Ligar via a(); movimentos devem ser inseridos no formulário piece,destination(ou seja 1,4); saia com Ctrl-C. Se alguém pode ver mais potencial de golfe, sou todo ouvidos.

b,r,x='_',lambda p:''.join([p[i]for i in x]),range(11)
def a(m='xo'):
 t=w=0;p=dict(zip(x,'xxxx___oooo'))
 while w<1:
    print r(p);y=m[t%2]
    try:
     s,v=input();1/all([y==p[s],{v}<{r(p).rfind(b,0,s),r(p).find(b,s)},v-s]);p[s],p[v],h,c=b,y,0,{}  
     for _ in y,m[-~t%2]:
        for i in p:exec{_:"h=1;p.update(c)",b:"h,c=0,{}"}.get(p[i],h*"c[i]=b")
     w=min(map(r(p).count,m))<2;t+=1
    except:print"INVALID"
 print"P%d WINS"%-~(r(p).count('o')<2)
sirpercival
fonte
1

SpecBAS - 718 bytes

O SpecBAS é uma versão atualizada do Sinclair / ZX BASIC que pode ser executada fora de um emulador. (Ainda interpretado).

Usei alguns dos novos recursos para diminuir o tamanho o máximo que pude.

A linha 12 configura um regex para procurar peças "imprensadas" usando IF em linha e a linha 18 usa a natureza envolvente do INC (em vez de dizer INC p: IF p=3 THEN LET p=1)

1 LET b$="xxxx---oooo": LET p=1: LET c$="xo": DIM s=4,4
2 LET v=0: PRINT b$'"[";p;"] ";
3 INPUT m$: IF m$(1)="Q" THEN PRINT "QUIT": STOP 
4 LET f=VAL(ITEM$(m$,1," ")): LET t=VAL(ITEM$(m$,2," ")): PRINT f;" ";t
5 IF (f<1 OR f>11) OR (t<1 OR t>11) THEN LET v=1: GO TO 10
6 IF (b$(f)<>c$(p)) OR b$(t)<>"-" THEN LET v=1: GO TO 10
7 FOR i=f TO t STEP SGN(t-f)
8 IF b$(i)="-" THEN IF i<>t THEN LET v=1
9 NEXT i
10 IF v=1 THEN PRINT "INVALID": GO TO 2
11 LET b$(t)=b$(f): LET b$(f)="-"
12 LET r$=IIF$(p=1,"xo+x","ox+o")
13 LET m=MATCH(r$,b$): IF m=0 THEN GO TO 18
14 FOR i=m+1 TO POS(c$(p),b$,m+2)
15 IF b$(i)=c$(3-p) THEN LET b$(i)="-": DEC s(3-p): END IF
16 NEXT i
17 IF s(3-p)<2 THEN PRINT b$'"P";p;" WINS": STOP 
18 INC p,1 TO 2
19 GO TO 2

Saída (não é possível copiar da viúva de saída, portanto, captura de tela) insira a descrição da imagem aqui

insira a descrição da imagem aqui

Brian
fonte
0

C #, 730 bytes

using System;using System.Linq;class P{static void Main(string[]z){int p=1,d,e,g,x,y;var b=new[]{3,1,1,1,1,0,0,0,2,2,2,2};var o=new[]{"_","x","o"};Action<string>h=s=>{Console.Write(s,p);Environment.Exit(0);};Action i=()=>h("INVALID");Func<int,int,bool>j=(q,r)=>b.Select((v,w)=>w<=q||w>=r||v>0?0:w).Any(w=>w>0);Action<int>k=m=>{e=0;for(d=1;d<12;d++){if(b[d]==m){if(e>0&&!j(e,d))for(g=e+1;g<d;g++)b[g]=0;e=d;}}if(b.Count(w=>w>0&&w!=m)<3)h("P{0} WINS");};try{for(;;){for(g=1;g<12;g++)Console.Write(o[b[g]]);var n=Console.ReadLine();if(n=="quit")h("");var c=n.Split(' ');x=int.Parse(c[0]);y=int.Parse(c[1]);if(c.Length>2||b[x]!=p||b[y]!=0||(p>1?y:x)>=(p>1?x:y)||j(x<y?x:y,x<y?y:x))i();b[x]=0;b[y]=p;k(p);p=p>1?1:2;k(p);}}catch{i();}}}

Eu imagino que outras melhorias sejam possíveis. Por outro lado, interpretei a INVALIDsaída como finalizando a execução, portanto, talvez seja necessário corrigir esse problema para estar em paridade com outras respostas.

Andrew
fonte