Spielen Sie einen gültigen Schachzug, wenn Sie ein Brett auf stdin haben

11

Das Programm spielt weiß.

Beispiel stdin:

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

Beispiel stdout:

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

Jeder gültige Zug ist in Ordnung. "En passant" und Rochade werden ignoriert. Es ist in Ordnung, Fehlermeldungen anzuzeigen oder nichts zu drucken, wenn keine gültige Verschiebung vorliegt.

Die Antwort mit den meisten Stimmen gewinnt.

Hristo Hristov
quelle
Ich meine eine Standardfehlermeldung, die durch den Ausfall einer eingebauten Funktion der Sprache verursacht wird. Also ist das ok? - Ist es obligatorisch, dass das Programm einen legalen Schritt machen kann? Vielleicht sollten Rochade- und Bauern-Spezialbewegungen mit einem Bonus optional gemacht werden?
hörte auf, gegen den Uhrzeigersinn am
2
@leftaroundabout: Wann immer du eine Burg bauen kannst, kannst du stattdessen einfach den Turm bewegen, damit du zumindest die Logik dafür überspringen kannst.
Hammar
2
... und wenn man noch etwas darüber nachdenkt, erfordert der "en passant" -Zug Informationen darüber, welche vorherigen Züge gemacht wurden, die nicht nur aus den Positionen der Teile abgeleitet werden können, also denke ich, dass es sicher sein könnte, das fallen zu lassen. Ob der doppelte erste Zug verfügbar ist, kann jedoch aus dem Rang des Bauern abgeleitet werden. Vielleicht möchten Sie dies einbeziehen.
Hammar
@ Hammar: Du hast Recht, darüber hatte ich nicht nachgedacht. Der doppelte Zug ist auch nicht wichtig, außer in einem Fall: Wenn Sie zwei Schritte machen können, können Sie auch einen machen. Daher wird er nur wichtig, wenn Sie in Schach sind und der doppelte Zug der einzige Zug ist, der den König abdeckt. Auch wenn Sie nicht in der Lage sein müssen, jede Bewegung auszuführen, müssen Sie dennoch berücksichtigen, dass Schwarz mit jeder Möglichkeit antworten kann.
hörte auf, gegen den Uhrzeigersinn am
9
Wird der Rücktritt als rechtlicher Schritt gewertet? :)
Gnibbler

Antworten:

16

Ich beschwere mich nicht über Upvotes, aber um fair zu sein ... meine Lösung hier ist eigentlich gar nicht so toll. Ugoren ist besser, abgesehen von mangelnder Unicode-Unterstützung. Sehen Sie sich vor der Abstimmung unbedingt alle Antworten an, wenn Sie erst jetzt auf diese Frage gestoßen sind!
Wie auch immer.

Haskell, 893 888 904 952 (ohne Rochade)

862 (ohne Bauern-Doppelzüge)

(Sie haben nicht angegeben, ob dies Code-Golf sein soll, aber es scheint mir, dass es sollte)

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

Wenn Sie GHC installiert haben (zum Beispiel als Teil der Haskell-Plattform ), können Sie dies einfach tun

$ runhaskell def0.hs < examplechessboard.txt
8 ║♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… ♘ … … ♟ … … …
4 ║… … … … … … … …
3 ║… … … … … … … …
2 ║♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
1 ║♖ … ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h
hörte auf, gegen den Uhrzeigersinn zu drehen
quelle
Nun, das ist verrückt :) Ich werde es überprüfen :)
Hristo Hristov
Irgendeine Idee, wie man diese Großartigkeit testet? Ideone.com kann nicht damit umgehen ...
Hristo Hristov
@HristoHristov: Seltsam, dass es auf Ideone nicht funktioniert. Hat wahrscheinlich mit den Nicht-ASCII-Zeichen zu tun.
hörte auf, gegen den Uhrzeigersinn am
Ja, das ist das Problem mit Ideone
Hristo Hristov
14
Herzlichen Glückwunsch, Sie haben es geschafft, Haskell wie APL aussehen zu lassen. :-)
Ilmari Karonen
11

C, 734 672 640 Zeichen

Zeichen werden ohne entfernbares Leerzeichen gezählt.
Das von mir verwendete Dateiformat entspricht nicht den Anforderungen, sondern vereinfachtem ASCII.
Ich muss Unicode-Zeichenunterstützung hinzufügen, es würde einige Zeichen kosten.

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]]);
}

Eingabe- / Ausgabedateiformat:
Muss genau 8 Zeilen mit genau 8 Zeichen enthalten. pnbrqkwerden für weiße Stücke, PNBRQKfür schwarze Stücke, Leerzeichen für Leerzeichen verwendet:

RNBQKBNR
PPPP PPP

 n  P


pppppppp
r bqkbnr

Die Logik ist ganz einfach:
Versuchen Sie für jede mögliche Bewegung jedes weißen Stücks jede mögliche Bewegung jedes schwarzen Stücks.
Wenn kein schwarzer Zug den weißen König erfasst, ist der weiße Zug gültig.

Die Platine wird als char[256]16x16-Matrix behandelt, wobei nur die 8x8-Matrix oben links verwendet wird. Positionen und Bewegungsvektoren werden in 8-Bit-Ganzzahlen ( x:4,y:4) gehalten. Das zusätzliche Bit ermöglicht die Verwendung einer einfachen Arithmetik ( new_pos = old_pos + steps*direction) mit einer einfachen Erkennung der Platinenkante ( &0x88macht die Magie). r[]codiert drei Dinge:

  1. Die ersten 15 Bytes ordnen interne Stückcodes (K = 1, P = 2, N = 3, B = 4, R = 5, Q = 6) Buchstaben zu.
  2. Die nächsten 6 Bytes ordnen interne Stückcodes Offsets im letzten Teil zu (K und Q sind gleich, B ist ihr Schwanz).
  3. Die letzten 16 Bytes codieren die Bewegung aller Teile als '('+vector.

Funktionen:

  1. mainliest die Tafel, wandelt Buchstaben in internen Code um, ruft aauf, um weiße Züge zu finden, druckt die Tafel.
  2. arekursiv Schleifen über die 64 Quadrate. Für jedes Stück der richtigen Farbe (Parameter c) wird die Bewegungsregel für das Stück gefunden und aufgerufen d.
  3. drekursiv durchläuft die codierte Bewegungsregel, bei der es sich um eine Liste von Vektoren handelt, die ejeweils aufgerufen werden. Es gibt edie ursprüngliche Position, den Vektor und die Bereichsgrenze an (7 für Steine ​​über B, 2 für Bauern zweiten Ranges, 1 ansonsten).
  4. etestet alle Bewegungen entlang eines Vektors. Wenn der Zug möglich ist (dh Bauern bewegen sich vorwärts, innerhalb des Bretts, nicht blockiert, Bauern diagonal gefangen), überprüft eines von zwei Dingen. Läuft bei weißen Zügen, vum den Zug zu validieren. Überprüft bei schwarzen Zügen, ob der weiße König gefangen ist. Wenn dies zutrifft, wird der Zug auf dem Brett gespielt.
  5. vvalidiert einen weißen Zug. Es kopiert das Board beiseite, führt den zu testenden Zug aus und ruft aerneut auf, um nach schwarzen Zügen zu suchen.
ugoren
quelle
Endlich eine Lösung mit korrekter komprimierter Codierung der möglichen Bewegungen! Und es ist schön schnell. Denken Sie nicht, Sie könnten einen Unicode-Wrapper hinzufügen und trotzdem kürzer als mein Code sein?
hörte auf, gegen den Uhrzeigersinn
@leftaroundabout, ich denke ich kann. Das Hauptproblem ist, dass ich in einer Linux-Befehlszeile arbeite, in der Sie Unicode nicht sehen können. Das Debuggen wäre also ärgerlich. Ich habe auch eine Version, die ungefähr 40 weitere Bytes spart (ich werde bald aktualisieren), also habe ich viele Zeichen, mit denen ich arbeiten kann.
Ugoren
@ugoren: Sicherlich unterstützt jede halbwegs moderne Linux-Distribution UTF-8 sofort?
Han
@han, ich arbeite unter Windows und verbinde mich über SSH mit Linux, und Unicode funktioniert nicht. Ich kann in eine Datei schreiben und in Windows öffnen, aber es ist einfach nicht mehr interessant.
Ugoren
Wird dies mit gcc kompiliert? Ich verwende Geany für Windows mit MinGW und es wird mit einer Reihe von Fehlern und Warnungen kompiliert, aber es wird nicht erstellt / ausgeführt :(. text + 0x2d8): undefinierter Verweis auf `bcopy 'collect2: ld hat 1 Exit-Status zurückgegeben
rpd
5

Python 2.6, 886 - 1425 Zeichen

Meine ursprüngliche Version (in den Revisionen) hatte 886 Zeichen, erfüllte die Spezifikation jedoch nicht vollständig (sie überprüfte nicht, ob Schachmatt vermieden wurde; sie berücksichtigte nicht einmal die möglichen Bewegungen der schwarzen Teile).

Jetzt ist es so (und ich habe mehrere Fehler im Original behoben). Leider ist dies mit Kosten in Zeichen verbunden: 1425 für den Moment, aber es sollte noch wenig Raum für Verbesserungen geben. Diese Version sollte im Umgang mit Randfällen viel solider sein als die vorherige.

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

Beispiel für Ein- und Ausgabe:

# EINGABE

8 ║♜ ♞ ♝… ♚ ♝ ♞ ♜
7 ♟ ♟ ♟ ♟… ♟ ♟ ♟
6 ║ ……………………
5 ║ ………… ♟ ………
4 ║ …… ………… ♙ ♛
3 ║ …………… ……
2 ║♙ ♙ ♙ ♙ ♙… ♙…
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♘
——╚═══════════════
-- A B C D E F G H
# AUSGABE

8 ║♜ ♞ ♝… ♚ ♝ ♞ ♜
7 ♟ ♟ ♟ ♟… ♟ ♟ ♟
6 ║ ……………………
5 ║ ………… ♟ ………
4 ║ …… ………… ♙ ♛
3 ║ ………… ♙ ♙…
2 ║♙ ♙ ♙ ♙ ♙ ………
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♘
——╚════════════════
-- A B C D E F G H
ChristopheD
quelle
Es sind 886 Bytes, aber nur 854 Zeichen. (Mein Programm hat dank der vielen Nicht-ASCII-Operatoren über 1 KB!) - Werden Sie noch prüfen, ob Sie den König nehmen?
hörte auf, gegen den Uhrzeigersinn
@leftaroundabout: Ich habe die King Checks hinzugefügt (was mich zwingt, auch mögliche Bewegungen von Schwarz zu berücksichtigen und viele Charaktere hinzufügt ...). Na ja, diese Version sollte in Randfällen solider sein (soweit ich getestet habe).
ChristopheD