Final do jogo de xadrez: branco para companheiro em um

19

Dada uma grade de letras 8x8 que representa o estado atual de um jogo de xadrez, a tarefa do seu programa é encontrar um próximo movimento para o branco que resulte em xeque-mate (a resposta sempre será conjunta em um movimento).

Entrada

A entrada será em STDIN - 8 linhas de 8 caracteres cada. Os significados de cada caractere são os seguintes:

K/k - king
Q/q - queen
B/b - bishop
N/n - knight
R/r - rook
P/p - pawn
- - empty square

Letras maiúsculas representam peças brancas e letras minúsculas representam preto. O tabuleiro será orientado para que o branco seja reproduzido por baixo e o preto seja reproduzido por cima.

Resultado

Uma mudança para o branco que resulta em xeque-mate, em notação algébrica . Você não precisa anotar quando uma peça foi tirada, nem precisa se preocupar em desambiguar entre duas peças idênticas que podem fazer o mesmo movimento.

Entrada de amostra

Exemplo 1

Entrada:

------R-
--p-kp-p
-----n--
--PPK---
p----P-r
B-------
--------
--------

Resultado:

c6

Exemplo 2

Entrada:

--b-r--r
ppq-kp-p
-np-pn-B
--------
---N----
--P----P
PP---PP-
R--QRBK-

Resultado:

Nf5

Exemplo 3

Entrada:

---r-nr-
-pqb-p-k
pn--p-p-
R-------
--------
-P-B-N-P
-BP--PP-
---QR-K-

Resultado:

Rh5

Você pode presumir que a solução não envolverá roque ou en-passant.

Este é o código-golfe - a solução mais curta vence.

(Exemplos retirados de mateinone.com - quebra-cabeças 81, 82 e 83)

Gareth
fonte
Não. Penso que, para os fins desta pergunta, você pode assumir que a resposta não envolverá castiçal ou en-passant. Vou atualizar a pergunta.
Gareth
Como devemos lidar com posições com mais de um companheiro em um?
23711 Rob
@Rob Apenas uma solução é necessária; portanto, imprima a solução que encontrar primeiro.
Gareth
Também é seguro assumir que a solução não envolve promoção?
Peter Taylor
@ Peter Sim, não quero complicar demais o problema.
Gareth

Respostas:

7

Ruby, 589 512 510 499 493 caracteres

R=0..7
a=->b{o=[];R.map{|r|R.map{|c|v=Hash[?K,[6,7,8,11,13,16,17,18],?R,s=[157,161,163,167],?B,t=[156,158,166,168],?Q,s+t,?N,[1,3,5,9,15,19,21,23],?P,[32,181,183]][z=b[r][c]];v&&v.map{|s|k=2!=l=s/25+1;u=r;v=c;l.times{u+=s/5%5-2;v+=s%5-2;R===u&&R===v||break;t=b[u][v];j=t<?.&&l<8;(j||t=~/[a-z]/&&k)&&o<<=(h=b.map &:swapcase;h[u][v]=h[r][c];h[r][c]=?-;[z+"%c%d"%[97+v,8-u],h.reverse]);j&&(k||r==6)||break}}}};o}
a[$<.map{|l|l}].map{|m,b|a[b].any?{|f,x|a[x].all?{|g,y|y*""=~/K/}}||$><<m[/[^P]+/]}

A entrada é fornecida via stdin, por exemplo:

> ruby mateinone.rb
--------
--------
--------
-k------
b-------
-N-P----
--------
-----K-Q
^Z
Qb7

O resultado não é apenas um movimento que força um parceiro em um, mas todos os movimentos que o fazem.

Edit 1: A função efoi usada apenas uma vez, então eu a inline. Segundo, a codificação agora é baseada no número 5 em vez de 10. E refatorar a clonagem do quadro salvou alguns caracteres.

Edit 2: Ainda não há tantas melhorias quanto eu queria. Alterando o hash de {a=>b,c=>d}para Hash[a,b,c,d]. Isso custa 4 caracteres, mas salva um por par de valor-chave.

Edit 3: Apenas pequenas reduções: inline M (4 caracteres), t==?--> t<?.(2), removendo Pawn em notação algébrica no final (2), substituídos put (3). O programa agora tem menos de 500 caracteres.

Edit 4: É interessante o quanto ainda podemos encontrar em um programa como esse. Moveu uma invariante fora do loop e encontrou outro cálculo duplicado.

Howard
fonte
Por "não um, mas nenhum", você quer dizer "não necessariamente um, mas todos"?
Mateus Leia
@ Matthew Você está certo. Eu quis dizer "todos".
25411 Howard
Você pode usar em [*$<]vez de $<.map{|l|l}.
Lowjacker 7/08