Juega un movimiento de ajedrez válido, dado un tablero en stdin

11

El programa juega blanco.

Ejemplo stdin:

8 ║♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… … … … ♟ … … …
4 ║… … … … … … … …
3 ║… … ♘ … … … … …
2 ║♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
1 ║♖ … ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h

Ejemplo stdout:

8 ║♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… … … … ♟ … … …
4 ║… … … … ♙ … … …
3 ║… … ♘ … … … … …
2 ║♙ ♙ ♙ ♙ … ♙ ♙ ♙
1 ║♖ … ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h

Cualquier movimiento válido está bien. "En passant" y enroque son ignorados. Está bien mostrar mensajes de error o no imprimir nada si no hay un movimiento válido.

La respuesta con más votos gana.

Hristo Hristov
fuente
Me refiero a un mensaje de error estándar causado por el fallo de alguna función incorporada del idioma. ¿Entonces está bien? - ¿Es obligatorio que el programa pueda hacer algún movimiento legal? ¿Quizás los movimientos especiales de enroque y peón deberían hacerse opcionales con alguna bonificación?
dejó de girar en sentido contrario a las agujas del reloj el
2
@leftaroundabout: cada vez que puedes hacer un castillo, puedes mover la torre en su lugar, por lo que puedes saltarte la lógica al menos.
hammar
2
... y pensándolo un poco más, el movimiento "en passant" requiere información sobre los movimientos anteriores que se han realizado, lo que no puede deducirse solo de las posiciones de las piezas, por lo que supongo que sería seguro dejarlo caer. Sin embargo, si el primer movimiento doble está disponible puede deducirse del rango del peón, por lo que es posible que desee incluir eso.
hammar
@hammar: tienes razón, no había pensado en eso. El doble movimiento tampoco es importante, excepto en un caso: cuando puedes ir dos pasos también puedes ir uno, por lo que solo se vuelve importante cuando estás bajo control y el doble movimiento es el único movimiento que cubre al rey. Además, incluso cuando usted no tiene que ser capaz de utilizar todos sus movimientos, sigue siendo necesario tener en cuenta que la respuesta lata negro con cualquier posibilidad.
dejó de girar en sentido contrario a las agujas del reloj el
99
¿Renunciar se cuenta como un movimiento legal? :)
gnibbler

Respuestas:

16

No me estoy quejando de los votos, pero para ser justos ... mi solución aquí no es realmente tan buena. Ugoren es mejor, aparte de la falta de soporte Unicode. ¡Asegúrese de ver todas las respuestas antes de votar, si se ha encontrado con esta pregunta solo ahora!
De todas formas.

Haskell, 893 888 904 952 (sin enrocar)

862 (sin peones dobles movimientos)

(No especificó si se supone que esto es código golf, pero me parece que debería)

χ=w⋈b;w="♙♢♤♔♕♖♗♘";b="♟♦♠♚♛♜♝♞"
μ=t⤀ζ++((\(x,y)->(x,-y))⤀)⤀μ;q c|((_,m):_)<-((==c).fst)☂(χ⋎μ)=m
t(x:y:l)=(d x,d y):t l;t _=[];d c=fromEnum c-78
ζ=["NM","NL","MMOM","MMMNMONMNOOMONOO",σ⋈δ,σ,δ,"MLOLPMPOOPMPLOLM"]
σ=l>>=(\c->'N':c:c:"N");δ=[l⋎l,reverse l⋎l]>>=(>>=(\(l,r)->[l,r]))
l="GHIJKLMOPQRSTU"
α c|c∊"♢♤"='♙'|c∊"♦♠"='♟'|c∊χ=c;π('♙':_)=6;π _=1
(⋎)=zip;(⤀)=map;(∊)=elem;(✄)=splitAt;(☂)=filter;(⋈)=(++)
φ r@(x,y)p a
 |x>7=φ(0,y+1)p a
 |y>7=[]
 |c<-a✠r=(c⌥r)p a y⋈φ(x+1,y)p a
(c⌥r)p a y
 |c==p!!0=(a☈r)c χ++const(y==π p)☂(a☈r)(p!!1)χ++(a☈r)(p!!2)('…':w)
 |c∊p=(a☈r)c χ
 |True=[]
a✠(x,y)=a!!y!!(x*2);o(x,y)=x>=0&&x<8&&y>=0&&y<8
(n➴a)(x,y)|(u,m:d)<-y✄a,(l,_:r)<-(x*2)✄m=u⋈(l⋈(n:r):d)
(a☈r@(x,y))c b=(α c➴('…'➴a)r)⤀((\r->o r&&not((a✠r)∊b))☂((\(ξ,υ)->(x+ξ,y+υ))⤀q c))
main=interact$unlines.uncurry((⋈).zipWith((⋈).(:" ║"))['8','7'..]
 .head.((all(any('♔'∊)).φ(0,0)b)☂).φ(0,0)w.(drop 3⤀)).(8✄).lines

Cuando tiene instalado GHC (por ejemplo, como parte de la plataforma Haskell ) puede hacer solo

$ runhaskell def0.hs < examplechessboard.txt
8 ║♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… ♘ … … ♟ … … …
4 ║… … … … … … … …
3 ║… … … … … … … …
2 ║♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
1 ║♖ … ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h
dejó de girar en sentido antihorario
fuente
Ahora esto es una locura :) Lo comprobaré :)
Hristo Hristov
¿Alguna idea de cómo probar esta genialidad? Ideone.com no puede manejarlo ...
Hristo Hristov
@HristoHristov: extraño, no funciona en Ideone. Probablemente tiene que ver con los caracteres no ASCII.
dejó de girar en sentido contrario a las agujas del reloj el
sí, este es el problema con la ideona
Hristo Hristov
14
Felicitaciones, has logrado que Haskell se parezca a APL. :-)
Ilmari Karonen
11

C, 734 672 640 caracteres

Caracteres contados sin espacios en blanco extraíbles.
El formato de archivo que utilicé no es el solicitado, sino ASCII simplificado.
Necesito agregar soporte de caracteres Unicode, costaría algunos characets.

char*r=" kpnbrq  KPNBRQ $ ,&)$wxy()879()8(6:GI(",B[256],*b=B,i;
e(x,d,m,V,c,r,n,p){
    for(r=0,p=b[x];m/++r;){
        n=x+d*r;
        if(p==2+8*(d<0)||n&136||!(b[n]?r=8,8^p^b[n]^8&&c&65^64:c&65^65)
            ? r=m,0
            : V?v(n,x):b[n]==1)
            return b[x]=0,b[n]=p%8-2||n/16%7?p:p+4;
    }
    return d>0&&e(x,-d,m,V,c);
}
d(x,v,m,i)char*m;{
    return(i=*m-40)?e(x,i%64,b[x]%8-2?b[x]&4?7:1:(x/16-1)%5|i%2?1:2,v,i)||d(x,v,m+1):0;
}
v(t,f){
    bcopy(B,b+=128,128);
    b[t]=b[f];b[f]=0;
    i=a(1,63);
    b=B;
    return!i;
}
a(c,n){
    return b[i=n*2-n%8]&&b[i]/8==c&&d(i,!c,r+r[b[i]%8+15]-10)||n--&&a(c,n);
}
main(){
    for(;gets(b);b+=8)for(;*b;b++)*b=strchr(r,*b)-r;b=B;
    for(i=64*!a(0,63);i<64;i++%8-7||puts(""))putchar(r[b[i*2-i%8]]);
}

Formato de archivo de entrada / salida:
debe tener exactamente 8 líneas de exactamente 8 caracteres. pnbrqkse utilizan para piezas blancas, PNBRQKpara piezas negras, espacios para espacios:

RNBQKBNR
PPPP PPP

 n  P


pppppppp
r bqkbnr

La lógica es bastante simple:
para cada posible movimiento de cada pieza blanca, intente cada posible movimiento de cada pieza negra.
Si ningún movimiento negro captura al rey blanco, el movimiento blanco es válido.

El tablero se mantiene como char[256], tratado como una matriz de 16x16, donde solo se usa el 8x8 superior izquierdo. Las posiciones y los vectores de movimiento se mantienen en enteros de 8 bits ( x:4,y:4). El bit extra permite usar aritmética simple ( new_pos = old_pos + steps*direction), con detección fácil del borde del tablero ( &0x88hace la magia). r[]codifica tres cosas:

  1. Los primeros 15 bytes asignan códigos internos de piezas (K = 1, P = 2, N = 3, B = 4, R = 5, Q = 6) a letras.
  2. Los siguientes 6 bytes asignan códigos internos de piezas a compensaciones en la última parte (K y Q son lo mismo, B es su cola).
  3. Los últimos 16 bytes codifican el movimiento de todas las piezas, como '('+vector.

Funciones:

  1. mainlee el tablero, convierte letras en código interno, llama apara encontrar movimientos blancos, imprime el tablero.
  2. arecorre recursivamente los 64 cuadrados. Para cada pieza del color correcto (parámetro c), encuentra la regla de movimiento para la pieza y llama d.
  3. drecorre recursivamente la regla de movimiento codificada, que es una lista de vectores, que llama ea cada uno. Da ela posición original, el vector y el límite de rango (7 para piezas por encima de B, 2 para peones de segundo rango, 1 de lo contrario).
  4. eprueba todos los movimientos a lo largo de un vector. Si el movimiento es posible (es decir, los peones se mueven hacia adelante, dentro del tablero, no bloqueados, la captura de peones en diagonal), verifica una de dos cosas. Para movimientos blancos, corre vpara validar el movimiento. Para movimientos negros, verifica si el rey blanco es capturado. Si es cierto, el movimiento se juega en el tablero.
  5. vvalida un movimiento blanco. Copia el tablero a un lado, ejecuta el movimiento para probar y avuelve a llamar para buscar movimientos negros.
Ugoren
fuente
¡Por fin, una solución con la codificación comprimida adecuada de los posibles movimientos! Y es muy rápido. ¿No crees que podrías agregar un contenedor Unicode y aún así ser más corto que mi código?
dejó de girar en contra del reloj
@leftaroundabout, supongo que puedo. El principal problema es que estoy trabajando en una línea de comandos de Linux, donde no se puede ver Unicode, por lo que depurarlo sería molesto. También tengo una versión que ahorra unos 40 bytes más (actualizaré pronto), así que tengo muchos caracteres para trabajar.
ugoren
@ugoren: ¿Seguramente cualquier distribución de Linux moderna a mitad de camino es compatible con UTF-8?
Han
@han, estoy trabajando en Windows y me conecto a Linux por SSH, y Unicode no funciona. Puedo escribir en un archivo y abrirlo en Windows, pero ya no es interesante.
ugoren
¿Esto compilará con gcc? Estoy usando Geany para Windows con MinGW y compilará con un montón de errores y advertencias, pero no compilará / ejecutará.eg: C: \ Users \ xxx \ AppData \ Local \ Temp \ ccpBG9zy.o: codegolfchess.c :(. text + 0x2d8): referencia indefinida a 'bcopy' collect2: ld devolvió 1 estado de salida
rpd
5

Python 2.6, 886 - 1425 caracteres

Mi versión inicial (en las revisiones) llegó a 886 caracteres, pero no satisfizo completamente la especificación (no comprobó para evitar el jaque mate; ni siquiera consideró los posibles movimientos de las piezas negras).

Ahora sí (y he solucionado varios errores en el original). Por desgracia, esto tiene un costo en caracteres: 1425 por ahora, pero aún debería haber poco margen de mejora. Esta versión debería ser mucho más sólida en el manejo de casos extremos que la anterior.

#-*-coding:utf8-*-
import sys;e=enumerate
B,W=["♟","♜","♞","♝","♛","♚"],["♙","♖","♘","♗","♕","♔"]
R={"♙":[11,42],"♖":[28],"♘":[31],"♗":[8],"♕":[8,28],"♔":[1,21]}
def F(w):return sum([[(i,j)for j,p in e(o)if p==w]for i,o in e(Z)],[])
def G(x,y):
 P=Z[x][y];D=P in W;L=[]
 for o in R[P]if D else R[unichr(ord(P.decode('utf8'))-6).encode('utf8')]:
  r,k="%02d"%o        
  for g,h in[[(-1,-1),(1,1),(-1,1),(1,-1)],[[(1,-1),(1,1)],[(-1,-1),(-1,1)]][D],[(-1,0),(1,0),(0,-1),(0,1)],[(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)],[(-1,0)]][int(r)]:
   J=0
   for i in range(int(k)):
    T=x+(i+1)*g;U=y+(i+1)*h
    if T<0 or T>7 or U<0 or U>7:break
    M=Z[T][U]
    if not J:L.append((T,U,P,M))
    else:break
    if r in"02"and(M in W+B):
     J=1
     if not((D and M in B)or(not D and M in W)):L.pop()
    elif(r=="1"and not((D and M in B)or(not D and M in W)))or(r=="4"and((i==1 and x!=6)or M!="…")):L.pop()
 return L  
Z=[[y for y in l[5:].split()]for l in sys.stdin.readlines()[:-2]]
Q=[]
for p in R:
 for i,j in F(p):
  for M,L,c,_ in G(i,j):
   O=Z[M][L];Z[i][j]="…";Z[M][L]=c;E=[];map(E.extend,map(F,B))
   if not any(any(1 for _,_,_,I in G(v,h)if I==["♔","♚"][c in B])for v,h in E):Q.append((i,j,M,L,c))
   Z[i][j]=c;Z[M][L]=O
(x,y,X,Y,p)=Q[0];Z[x][y]="…";Z[X][Y]=p
for i,h in e(Z):print`8-i`+' ║'+' '.join(h)
print"——╚"+"═"*16+"\n—— a b c d e f g h"

Ejemplo de entrada y salida:

# ENTRADA

8 ║♜ ♞ ♝… ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟… ♟ ♟ ♟
6 ║ ... ... ... ... ... ... ... ...
5 ║ ... ... ... ... ♟ ... ... ...
4 ║ ... ... ... ... ... ... ♙ ♛
3 ║ ... ... ... ... ... ♙ ... ...
2 ║♙ ♙ ♙ ♙ ♙ ... ♙ ...
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— abcdefgh
# SALIDA

8 ║♜ ♞ ♝… ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟… ♟ ♟ ♟
6 ║ ... ... ... ... ... ... ... ...
5 ║ ... ... ... ... ♟ ... ... ...
4 ║ ... ... ... ... ... ... ♙ ♛
3 ║ ... ... ... ... ... ♙ ♙ ...
2 ║♙ ♙ ♙ ♙ ♙ ... ... ...
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
——╚════════════════
—— abcdefgh
ChristopheD
fuente
Tiene 886 bytes, pero solo 854 caracteres. (¡Mi programa tiene más de 1kB, gracias a los muchos operadores que no son ASCII!) - ¿Vas a agregar verificación para tomar el rey todavía?
dejó de girar en sentido contrario a las agujas del reloj
@leftaroundabout: agregué los cheques del rey (lo que me obliga a tener en cuenta también los posibles movimientos de negro, y agrega muchos personajes ...). Oh, bueno, esta versión debería ser más sólida en los casos extremos (hasta donde probé).
ChristopheD