Gerador de posição Chess960

11

Contexto

O Chess960 (ou Fischer Random Chess) é uma variante do xadrez inventada e defendida pelo ex-campeão mundial de xadrez Bobby Fischer, anunciada publicamente em 19 de junho de 1996 em Buenos Aires, Argentina. Emprega o mesmo tabuleiro e peças do xadrez padrão; no entanto, a posição inicial das peças nas fileiras dos jogadores é aleatória

Regras

  • Os peões brancos são colocados na segunda posição como no xadrez padrão
  • Todas as peças brancas restantes são colocadas aleatoriamente na primeira fila
  • Os bispos devem ser colocados em quadrados de cores opostas
  • O rei deve ser colocado em um quadrado entre as torres.
  • As peças de preto são colocadas iguais e opostas às peças de branco.

De: http://en.wikipedia.org/wiki/Chess960

Para todas as pessoas que gostariam de postar respostas ...

você precisa criar um gerador de posições Chess960, capaz de gerar aleatoriamente uma das 960 posições seguindo as regras descritas acima (ele deve ser capaz de gerar qualquer uma das 960, codificar uma posição não é aceita!) e você só precisa saída o branco classificar uma peça.

Exemplo de saída:

rkrbnnbq

Onde:

  • rei k
  • q rainha
  • b bispo
  • n cavaleiro
  • torre r

Este será o código de golfe, e o desempate será o voto positivo.

jsedano
fonte
Quando você diz que deve ser capaz de emitir qualquer uma das 960 posições, elas precisam ser equivalentes?
Peter Taylor
Interessante, eu realmente não pensei nisso ... quero dizer, idealmente, deveria ser, acho ... As respostas até agora oferecem essa qualidade ... certo?
Jsedano
Os dois que são escritos em idiomas que possuem componentes que embaralham uniformemente; os dois GolfScript são próximos, mas não muito uniformes.
Peter Taylor
Eu diria que perto é bom o suficiente
jsedano
Esta questão me inspirou a pedir codegolf.stackexchange.com/questions/12322/...
user123444555621

Respostas:

6

GolfScript ( 49 48 caracteres ou 47 para letras maiúsculas)

'bbnnrrkq'{{;9rand}$.'b'/1=,1$'r'/1='k'?)!|1&}do

Isso usa a técnica padrão de permutar aleatoriamente até atendermos aos critérios. Diferentemente da solução GolfScript da w0lf, isso faz as duas verificações na string, portanto é provável que ela percorra o loop mais vezes.

Usar maiúsculas permite salvar um caractere:

'BBNNRRKQ'{{;9rand}$.'B'/1=,1$'R'/1=75?)!|1&}do
Peter Taylor
fonte
8

Ruby 1.9, 67 65 caracteres

Ah, a velha técnica "continue randomizando até gerar algo válido" ...

$_=%w(r r n n b b q k).shuffle*''until/r.*k.*r/&&/b(..)*b/
$><<$_

(No Ruby 2.0, %w(r r n n b b q k)poderia ser 'rrnnbbqk'.chars)

Paul Prestidge
fonte
1
No 1.9.3, você pode poupar ~o custo de um aviso, quando disponível. pastebin.com/nuE9zWSw
manatwork
@ manatwork isso é ótimo, obrigado!
Paul Prestidge
2
a "manter a randomização até gerar algo válido" técnica ainda é muito mais rápido do que o "embaralhar a lista de possibilidades, filtrar e tomar a primeira" técnica que linguagens puramente funcionais como APL tendem a produzir :-)
John Dvorak
1
@ Daniero é definitivamente essa a $_variável. Funciona porque o ruby ​​possui alguns métodos interessantes, como o Kernel # chop, que funciona como o método String # chop equivalente, mas com $_seu receptor. Isso economiza muito tempo quando (por exemplo) você está gravando um loop de leitura / processo / gravação usando ruby -nou ruby -p.
Paul Prestidge
2
@GigaWatt no. O primeiro corresponde se houver um número par de caracteres entre dois B's. Este último corresponde apenas se os B's estiverem nos extremos.
John Dvorak
8

GolfScript 60 49

;'qbbnnxxx'{{9rand*}$.'b'/1=,2%}do'x'/'rkr'1/]zip

(reduzido para 49 caracteres graças às ótimas dicas de Peter Taylor)

Teste online aqui .

Uma explicação do código:

;'qbbnnxxx'         # push the string 'qbbnnxxx' on the clean stack
{

    {9rand*}$       # shuffle the string

    .'b'/1=,2%      # count the number of places between the 'b's
                    # (including the 'b's themselves)
                    # if this count is even, the bishops are on
                    # squares of different colors, so place a 0
                    # on the stack to make the do loop stop

}do                 # repeat the procedure above until a 
                    # good string is encountered

'x'/                # split the string where the 'x's are

'rkr'1/]zip         # and put 'r', 'k' and then 'r' again
                    # where the 'x's used to be
w0lf
fonte
1
Seu método para verificar se há um número par de letras entre os bs parece muito longo. Que tal .'b'/1=,2%?
Peter Taylor
E você pode evitar descartar tentativas fracassadas, retirando 'qbbnnxxx'o loop e reorganizando a mesma string.
Peter Taylor
@ PeterTaylor Obrigado pelas ótimas dicas. Para a questão da "contagem entre 'b's", senti que deveria haver um caminho mais curto, mas simplesmente não consegui encontrá-lo.
Cristian Lupascu
4

J, 56 caracteres

{.(#~'(?=.*b(..)*b).*r.*k.*r.*'&rxeq"1)'kqbbnnrr'A.~?~!8

leva alguns segundos na minha máquina devido ao algoritmo ineficiente. Alguma velocidade pode ser obtida adicionando ~.(remova duplicatas) antes 'kqbbnnrr'.

explicação:

  • ?~!8trata 8!elementos aleatórios de0 ... 8!
  • 'kqbbnnrr'A.~usa-os como índices de anagramas para a string kqbbnnrr.
  • (#~'...'&rxeq"1)' os filtra pela regex entre aspas.
  • {. significa "pegue o primeiro elemento"
John Dvorak
fonte
4

K, 69

(-8?)/[{~*(*/~~':{m=_m:x%2}@&x="b")&(&x="k")within&"r"=x};"rrbbnnkq"]
tmartin
fonte
3

Python, 105 caracteres

Basicamente, a técnica do cron, menos o material elegante do Ruby.

import re,random
a='rrbbnnkq'
while re.search('b.(..)*b|r[^k]*r',a):a=''.join(random.sample(a,8))
print a

Obrigado a Peter Taylor pelo encurtamento da regex.

daniero
fonte
not s('b(..)*b',a)parece ser uma maneira longa de dizer s('b.(..)*b',a). Além disso, samplepode ser um caractere menor que shuffle, mas requer um argumento extra.
Peter Taylor
Você está certo sobre o regex, Peter. Obrigado! Shuffleretorna None, portanto, não é bom :( #
daniero 22/06
1
Perdeu a floresta para as árvores. Você não precisa de duas regexes, porque está verificando a mesma sequência e oré equivalente à alternância de regex ( |). Economiza 13 caracteres.
Peter Taylor
@PeterTaylor Good catch! obrigado.
Daniero