Gioca una mossa di scacchi valida, data una tavola su stdin


11

Il programma gioca in bianco.

Esempio stdin:

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

Esempio stdout:

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

Qualsiasi mossa valida è ok. "En passant" e castling vengono ignorati. È possibile mostrare messaggi di errore o stampare nulla se non è presente uno spostamento valido.

Vince la risposta con il maggior numero di voti.


Intendo un messaggio di errore standard causato dal fallimento di alcune funzioni integrate della lingua. Quindi va bene? - È obbligatorio che il programma possa fare qualsiasi mossa legale? Forse le mosse speciali di castling e pedone dovrebbero essere rese opzionali con qualche bonus?
cessò di girare in senso antiorario il

2
@leftaroundabout: ogni volta che riesci a castellare, puoi semplicemente spostare la torre, quindi puoi saltare la logica almeno per quello.
Hammar

2
... e pensandoci un po 'di più, la mossa "en passant" richiede informazioni su quali mosse precedenti sono state fatte, che non possono essere dedotte solo dalle posizioni dei pezzi, quindi immagino che potrebbe essere sicuro lasciar perdere. Tuttavia, se la doppia prima mossa è disponibile può essere dedotta dal rango della pedina, quindi potresti voler includerla.
Hammar,

@hammar: hai ragione, non ci avevo pensato. Anche la doppia mossa non è importante, tranne che per un caso: quando puoi fare due passi puoi anche fare una, quindi diventa importante solo quando sei sotto controllo e la doppia mossa è l'unica mossa che copre il re. Inoltre, anche quando si non c'è bisogno di essere in grado di utilizzare ogni mossa, è ancora necessario considerare che può rispondere a nero con ogni possibilità.
cessò di girare in senso antiorario il

9
Le dimissioni sono considerate mosse legali? :)
Gnibbler

Risposte:


16

Non mi lamento dei voti positivi, ma per essere onesti ... la mia soluzione qui non è poi così eccezionale. Ugoren è migliore, a parte la mancanza di supporto Unicode. Assicurati di guardare tutte le risposte prima di votare, se hai incontrato questa domanda solo ora!
Comunque.

Haskell, 893 888 904 952 (senza arroccamento)

862 (senza doppie mosse del pedone)

(Non hai specificato se questo dovrebbe essere un codice golf, ma mi sembra che dovrebbe)

χ=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

Quando hai installato GHC (ad esempio come parte della piattaforma Haskell ) puoi fare semplicemente

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

Ora questo è pazzo :) Lo controllerò :)
Hristo Hristov il

Qualche idea su come testare questa meraviglia? Ideone.com non può gestirlo ...
Hristo Hristov,

@HristoHristov: strano che non funzioni su Ideone. Probabilmente ha a che fare con i caratteri non ASCII.
cessò di girare in senso antiorario il

sì, questo è il problema con ideone
Hristo Hristov,

14
Congratulazioni, sei riuscito a far sembrare Haskell APL. :-)
Ilmari Karonen il

11

C, 734 672 640 caratteri

Personaggi contati senza spazi bianchi rimovibili.
Il formato del file che ho usato non è come richiesto, ma ASCII semplificato.
Ho bisogno di aggiungere il supporto per i caratteri Unicode, costerebbe alcuni caratteri.

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 file di input / output:
deve essere esattamente 8 righe di esattamente 8 caratteri. pnbrqksono usati per pezzi bianchi, PNBRQKper pezzi neri, spazi per spazi:

RNBQKBNR
PPPP PPP

 n  P


pppppppp
r bqkbnr

La logica è abbastanza semplice:
per ogni possibile mossa di ogni pezzo bianco, prova ogni possibile mossa di ogni pezzo nero.
Se nessuna mossa nera cattura il re bianco, la mossa bianca è valida.

La scheda viene mantenuta come char[256], trattata come una matrice 16x16, dove viene utilizzato solo l'8x8 in alto a sinistra. Posizioni e vettori di movimento sono mantenuti in numeri interi a 8 bit ( x:4,y:4). Il bit extra consente di utilizzare l'aritmetica semplice ( new_pos = old_pos + steps*direction), con un facile rilevamento del bordo della scheda ( &0x88fa la magia). r[]codifica tre cose:

  1. I primi 15 byte associano i codici pezzo interni (K = 1, P = 2, N = 3, B = 4, R = 5, Q = 6) alle lettere.
  2. I successivi 6 byte associano i codici pezzo interni agli offset nell'ultima parte (K e Q sono uguali, B è la loro coda).
  3. Gli ultimi 16 byte codificano il movimento di tutti i pezzi, come '('+vector.

funzioni:

  1. mainlegge la lavagna, converte le lettere in codice interno, chiama aper trovare mosse bianche, stampa la lavagna.
  2. aricicla ricorsivamente sui 64 quadrati. Per ogni pezzo del colore giusto (parametro c), trova la regola di movimento per il pezzo e chiama d.
  3. dricicla ricorsivamente sulla regola del movimento codificata, che è un elenco di vettori, che richiede eciascuno di essi. Fornisce ela posizione originale, il vettore e il limite del raggio (7 per i pezzi sopra B, 2 per i pedoni di secondo rango, 1 altrimenti).
  4. everifica tutti i movimenti lungo un vettore. Se la mossa è possibile (ovvero i pedoni si muovono in avanti, all'interno della tavola, non bloccati, il pedone viene catturato in diagonale), controlla una delle due cose. Per le mosse bianche, corre vper convalidare la mossa. Per le mosse nere, controlla se il re bianco viene catturato. Se vero, la mossa viene giocata sul tabellone.
  5. vconvalida una mossa bianca. Copia il tabellone da parte, esegue la mossa per testare e chiama di anuovo per cercare mosse nere.

Finalmente una soluzione con codifica compressa corretta delle possibili mosse! Ed è molto veloce. Non pensi di poter aggiungere un wrapper Unicode ed essere ancora più corto del mio codice?
cessò di girare in senso antiorario l'

@leftaroundabout, credo di si. Il problema principale è che sto lavorando in una riga di comando di Linux, dove non puoi vedere Unicode, quindi il debug sarebbe fastidioso. Ho anche una versione che salva circa 40 byte in più (aggiornerò presto), quindi ho molti caratteri con cui lavorare.
ugoren,

@ugoren: Sicuramente qualsiasi distribuzione Linux moderna a metà strada supporta UTF-8 out of the box?
han

@han, sto lavorando su Windows e mi collego a Linux tramite SSH e Unicode non funziona. Posso scrivere su un file e aprirlo in Windows, ma non è più interessante.
ugoren,

Sarà compilato con gcc? Sto usando Geany per Windows con MinGW e verrà compilato con una serie di errori e avvisi ma non genererà / run.eg: C: \ Users \ xxx \ AppData \ Local \ Temp \ ccpBG9zy.o: codegolfchess.c :( .testo + 0x2d8): riferimento indefinito a `bcopy 'collect2: ld ha restituito 1 stato di uscita
rpd

5

Python 2.6, 886-1425 caratteri

La mia versione iniziale (nelle revisioni) arrivava a 886 caratteri ma non soddisfaceva completamente le specifiche (non controllava per evitare scacco matto, non prendeva nemmeno in considerazione le possibili mosse dei pezzi neri).

Ora funziona (e ho corretto diversi bug nell'originale). Purtroppo questo ha un costo in caratteri: 1425 per ora, ma dovrebbe esserci ancora poco spazio per il miglioramento. Questa versione dovrebbe essere molto più solida nella gestione dei casi limite rispetto alla precedente.

#-*-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"

Esempio di input e output:

# INPUT

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

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

Sono 886 byte, ma solo 854 caratteri. (Il mio programma ha oltre 1kB, grazie a molti operatori non ASCII!) - Hai intenzione di aggiungere il controllo per prendere ancora il re?
cessò di girare in senso antiorario l'

@leftaroundabout: ho aggiunto i controlli del re (che mi costringe a tenere conto anche delle possibili mosse di nero e aggiunge molti personaggi ...). Vabbè, questa versione dovrebbe essere più solida attorno ai casi limite (per quanto ho testato).
ChristopheD,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.