Zagraj prawidłowy ruch szachowy, biorąc pod uwagę planszę na standardowym wejściu

11

Program jest biały.

Przykład stdin:

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

Przykładowy stdout:

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

Każdy prawidłowy ruch jest w porządku. „En passant” i castling są ignorowane. Można wyświetlać komunikaty o błędach lub nic nie drukować, jeśli nie ma prawidłowego przeniesienia.

Odpowiedź z największą liczbą głosów wygrywa.

Hristo Hristov
źródło
Mam na myśli standardowy komunikat o błędzie spowodowany awarią niektórych wbudowanych funkcji języka. Więc w porządku? - Czy jest to obowiązkowe, że program może wykonać żadnego ruchu prawnej? Być może specjalne ruchy roszące i pionkami powinny być opcjonalne z pewnymi bonusami?
przestał obracać przeciwnie do zegara
2
@leftaroundabout: Ilekroć możesz zamek, możesz po prostu przesunąć wieżę, aby przynajmniej pominąć logikę.
hammar
2
... i myśląc o tym trochę więcej, ruch „en passant” wymaga informacji o tym, jakie poprzednie ruchy zostały wykonane, czego nie można wywnioskować z samych pozycji elementów, więc myślę, że można to bezpiecznie porzucić. Jednak to, czy podwójny pierwszy ruch jest dostępny, można wywnioskować z rangi pionka, więc warto to uwzględnić.
hammar
@hammar: masz rację, nie myślałem o tym. Podwójny ruch również nie jest ważny, z wyjątkiem jednego przypadku: kiedy możesz przejść dwa kroki, możesz także przejść jeden, więc staje się to ważne, gdy jesteś w szachu, a podwójny ruch jest jedynym ruchem, który obejmuje króla. Ponadto, nawet jeśli ty nie musisz być w stanie wykorzystać każdy ruch, trzeba jeszcze wziąć pod uwagę, że czarne może odpowiedzieć z jakiejkolwiek możliwości.
przestał obracać przeciwnie do
9
Czy rezygnacja jest uważana za legalny ruch? :)
gnibbler

Odpowiedzi:

16

Nie narzekam na pozytywne opinie, ale szczerze mówiąc ... moje rozwiązanie tutaj nie jest wcale takie świetne. Ugoren jest lepszy, oprócz braku obsługi Unicode. Przed głosowaniem zapoznaj się z wszystkimi odpowiedziami, jeśli trafiłeś na to pytanie dopiero teraz!
Tak czy inaczej.

Haskell, 893 888 904 952 (bez roszady)

862 (bez podwójnych ruchów pionka)

(Nie określiłeś, czy to ma być kod golfowy, ale wydaje mi się, że powinien)

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

Po zainstalowaniu GHC (na przykład w ramach platformy Haskell ) możesz to zrobić

$ runhaskell def0.hs < examplechessboard.txt
8 ║♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… ♘ … … ♟ … … …
4 ║… … … … … … … …
3 ║… … … … … … … …
2 ║♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
1 ║♖ … ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h
przestał się obracać w lewo
źródło
Teraz to szaleństwo :) Sprawdzę to :)
Hristo Hristov
Masz pomysł, jak przetestować tę wspaniałość? Ideone.com nie może sobie z tym poradzić ...
Hristo Hristov
@HristoHristov: dziwne, że to nie działa na Ideone. Prawdopodobnie ma to związek ze znakami spoza ASCII.
przestał obracać przeciwnie do zegara
tak, to jest problem z ideonem
Hristo Hristov
14
Gratulacje, udało ci się sprawić, że Haskell wygląda jak APL. :-)
Ilmari Karonen
11

C, 734 672 640 znaków

Znaki liczone bez usuwalnej białej spacji.
Format pliku, którego użyłem, nie jest zgodny z żądaniem, ale uproszczony ASCII.
Muszę dodać obsługę znaków Unicode, kosztowałoby to trochę znaków.

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

Format pliku wejściowego / wyjściowego:
Musi mieć dokładnie 8 wierszy dokładnie 8 znaków. pnbrqksą używane do białych elementów, PNBRQKdo czarnych elementów, spacji dla przestrzeni:

RNBQKBNR
PPPP PPP

 n  P


pppppppp
r bqkbnr

Logika jest dość prosta:
dla każdego możliwego ruchu każdego białego elementu wypróbuj każdy możliwy ruch każdego czarnego elementu.
Jeśli żaden czarny ruch nie schwyta białego króla, biały ruch jest ważny.

Płytka jest utrzymywana jako char[256]traktowana jako matryca 16 x 16, w której używany jest tylko lewy górny 8 x 8. Pozycje i wektory ruchu są przechowywane w 8-bitowych liczbach całkowitych ( x:4,y:4). Dodatkowy bit pozwala na użycie prostej arytmetyki ( new_pos = old_pos + steps*direction), z łatwym wykryciem krawędzi deski ( &0x88robi magię). r[]koduje trzy rzeczy:

  1. Pierwsze 15 bajtów mapuje kody elementów wewnętrznych (K = 1, P = 2, N = 3, B = 4, R = 5, Q = 6) na litery.
  2. Kolejne 6 bajtów mapuje wewnętrzne kody sztuk na przesunięcia w ostatniej części (K i Q są takie same, B jest ich ogonem).
  3. Ostatnie 16 bajtów koduje ruch wszystkich elementów, jak '('+vector.

Funkcje:

  1. mainczyta tablicę, konwertuje litery na wewnętrzny kod, wzywa ado znalezienia białych ruchów, drukuje tablicę.
  2. arekurencyjnie zapętla się nad 64 kwadratami. Dla każdego elementu odpowiedniego koloru (parametru c) znajduje regułę ruchu dla elementu i wywołuje d.
  3. drekurencyjnie zapętla się nad zakodowaną regułą ruchu, która jest listą wektorów wywołujących ekażdy z nich. Daje eoryginalną pozycję, wektor i limit zasięgu (7 dla sztuk powyżej B, 2 dla pionków drugiej rangi, 1 w przeciwnym razie).
  4. etestuje wszystkie ruchy wzdłuż wektora. Jeśli ruch jest możliwy (tj. Pionki poruszają się do przodu, w obrębie planszy, nie są blokowane, pionek chwyta po przekątnej), sprawdza jedną z dwóch rzeczy. W przypadku białych ruchów biegnie, vaby potwierdzić ruch. W przypadku czarnych ruchów sprawdza, czy biały król został schwytany. Jeśli to prawda, ruch jest odtwarzany na planszy.
  5. vzatwierdza biały ruch. Kopiuje planszę na bok, wykonuje ruch, aby przetestować, i aponownie wzywa , aby poszukać czarnych ruchów.
ugoren
źródło
Wreszcie rozwiązanie z odpowiednim skompresowanym kodowaniem możliwych ruchów! I jest ładnie szybki. Nie sądzisz, że możesz dodać opakowanie Unicode i nadal być krótsze niż mój kod?
przestał się obracać przeciwnie do zegara
@leftaroundabout, chyba mogę. Główny problem polega na tym, że pracuję w wierszu poleceń Linuksa, w którym nie widać Unicode, więc debugowanie go byłoby denerwujące. Mam również wersję, która oszczędza około 40 bajtów więcej (wkrótce zaktualizuję), więc mam wiele znaków do pracy.
ugoren
@ugoren: Z pewnością jakakolwiek nowoczesna dystrybucja Linuksa w połowie drogi obsługuje UTF-8 po wyjęciu z pudełka?
han
@han, pracuję w systemie Windows i łączę się z Linuksem przez SSH, a Unicode nie działa. Mogę pisać do pliku i otwierać w systemie Windows, ale to już nie jest interesujące.
ugoren
Czy to się skompiluje z gcc? Używam Geany dla Windows z MinGW i będzie się kompilował z wieloma błędami i ostrzeżeniami, ale nie zbuduje / nie uruchomi się. Np: C: \ Users \ xxx \ AppData \ Local \ Temp \ ccpBG9zy.o: codegolfchess.c :(. tekst + 0x2d8): niezdefiniowane odniesienie do `bcopy 'collect2: ld zwrócił 1 status wyjścia
rpd
5

Python 2.6, 886 - 1425 znaków

Moja początkowa wersja (w wersjach) pojawiła się przy 886 znakach, ale nie była w pełni zgodna ze specyfikacją (nie sprawdzała, czy można uniknąć matowania; nawet nie brała pod uwagę możliwych ruchów czarnych elementów).

Teraz tak jest (i poprawiłem kilka błędów w oryginale). Niestety wiąże się to z kosztem postaci: na razie 1425, ale wciąż powinno być niewiele miejsca na ulepszenia. Ta wersja powinna być o wiele bardziej solidna w obsłudze przypadków krawędzi niż poprzednia.

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

Przykładowe dane wejściowe i wyjściowe:

# WEJŚCIE

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

8 ║♜ ♞ ♝… ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟… ♟ ♟ ♟
6 ║……………………
5 ║………… ♟………
4 ║………………… ♙ ♛
3 ║…………… ♙ ♙…
2 ║♙ ♙ ♙ ♙ ♙………
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
——╚════════════════
—— abcdefgh
ChristopheD
źródło
Ma 886 bajtów, ale tylko 854 znaki. (Mój program ma ponad 1kB, dzięki wielu operatorom spoza ASCII!) - Czy zamierzasz dodać sprawdzanie, czy wziąć króla?
przestał się obracać przeciwnie do zegara
@leftaroundabout: Dodałem czeki królewskie (co zmusza mnie do uwzględnienia możliwych ruchów czerni i dodaje wiele postaci ...). No cóż, ta wersja powinna być bardziej solidna wokół obudów krawędzi (o ile testowałem).
ChristopheD