Czy to mat?

14

Całkowicie zaskoczony, że nie został jeszcze opublikowany, biorąc pod uwagę dużą liczbę szachowych łamigłówek na stronie. Pomyślałem o tym osobiście, dziękuję Anushowi za opublikowanie go w piaskownicy w marcu . Uznałem jednak, że minęło już tyle czasu, że mogłem zrobić to sam.

Mat w szachach jest pozycja, w której król jest atakowany i nie ma ruch, który może go bronić. Jeśli nie wiesz, jak poruszają się szachy, możesz zapoznać się z Wikipedią .

Wyzwanie

W przypadku tego wyzwania Twoim wkładem będzie pozycja szachownicy w dowolnej notacji, którą lubisz. Aby wyjaśnić, Twój wkład opisze sztuk na szachownicy, z ich kolory i stanowisk, wraz z ewentualną en passant przechwytywania kwadratu, jeśli w ogóle. (Zdolność do zamków jest nieistotna, ponieważ nie można zamykać spod kontroli.) Notacja FEN może być przydatna , ale dowolny dogodny format jest w porządku. Dla uproszczenia możesz założyć, że gra w kolorze czarnym - oznacza to, że czarny zawsze będzie szachowym graczem. Pozycja, w której białe są w szachach, matach lub impasach, zostanie uznana za nieważną dla tego wyzwania.

Musisz podać prawdziwą wartość, jeśli pozycja jest matem, i wartość falsey, jeśli tak nie jest. Pamiętaj, że impas nie jest matą - król musi zostać zaatakowany!

Prawdziwe przypadki testowe

1k5R / 6R1 / 8/8/8/8/8 / 6K1 b - -

rn2r1k1 / pp1p1pQp / 3p4 / 1b1n4 / 1P2P3 / 2B5 / P5PP / R3K2R b - -

kr5R / rB6 / 8/8/8 / 5Q2 / 6K1 / R7 b - -

2K5 / 1B6 / 8/8/8 / 7N / R7 / R3r2k b - - 0 1

8 / 4Q1R1 / R7 / 5k2 / 3pP3 / 5K2 / 8/8 b - -

2K5 / 1B6 / 8/8/8 / 4b2N / R7 / 4r2k b - -

Przypadki testowe Falsey

rnbqkbnr / ppppppppp / 8/8 / 4P3 / 8 / PPPP1PPP / RNBQKBNR b KQkq -

8/8/8/8/8 / 1KQ5 / 4N3 / 1k6 b - -

2K5 / 1B6 / 8/8/8 / 7N / R7 / 4r2k b - -

8/8 / 2Q5 / 3k4 / 3Q5 / 8/8 / 7K b - -

8 / 4Q1R1 / R7 / 5k2 / 3pP3 / 5K2 / 8/8 b - e3 (Patrz, jak to pasywnie!)

Code golf - wygrywa najkrótszy kod w bajtach. Powodzenia!

rozpraszać
źródło
2
To wygląda na świetne pytanie :)
Anush,
1
Aby być samowystarczalnym - którym powinny tu być wszystkie wyzwania - należy to rozwinąć o wiele bardziej niż polegać na zewnętrznych linkach i / lub zakładać istniejącą znajomość zasad i notacji szachowej. Sugeruję zabranie go z powrotem do piaskownicy podczas pracy.
Kudłaty
3
@Shaggy Zewnętrzne linki w tym wyzwaniu służą wyłącznie wygodzie. Nie wymienię tutaj wszystkich reguł szachowych, ponieważ większość innych wyzwań szachowych zakłada ich wcześniejszą znajomość. Linki do lichess służą jedynie jako poręczna wizualna reprezentacja przypadków testowych; notacja jest dobrze zdefiniowana poza lichess. Mogłem dodawać obrazy, ale postanowiłem tego nie robić, ponieważ wydawało mi się, że to dużo bałaganu.
rozprasza
1
Czy możemy założyć, że do planszy dotarła ważna gra?
Ad Hoc Garf Hunter
1
Ponownie to otworzyłem, ponieważ chociaż podstawowe zadanie jest takie samo, to wyzwanie ma znacznie bardziej swobodny (i szczerze mówiąc lepszy) schemat IO i nieco inne (i szczerze mówiąc lepsze) kryterium punktacji. Myślę, że być może stary powinien zostać zamknięty jako duplikat nowego, ale nie zamierzam go wbijać.
Ad Hoc Garf Hunter

Odpowiedzi:

10

JavaScript (Node.js) ,  499 ... 374  370 bajtów

(b)(X)bX1

Poniżej znajdują się oczekiwane wartości dla każdego kwadratu:

 0: empty square

 5: white pawn      6: black pawn
 9: white king     10: black king
17: white bishop   18: black bishop
33: white rook     34: black rook
49: white queen    50: black queen
65: white knight   66: black knight

640

b=>e=>(g=(c,k)=>b.map((v,p,h,s=p+(p&~7),M=t=>v&-~c?c?(B=[...b],K&=g(b[t?b[T]=b[p]:b[b[e-8]=0,e]=6,p]=0),b=B):k|=V&8:0,m=([a],[x,t,...d]=Buffer(a))=>d.map(c=>(h=n=>(V=(a+=c-66)&136?3:b[T=a+a%8>>1])&v&3||t>>!V&v>>x&n>31&&h(n-4/!V,M``))(t,a=s)))=>(v=b[p],m`##123ACQRS`,m`$?13QS`,m`%?2ACR`,m`&#!#04PTac`,c?(p-e+8.5&~1||M(),m`"!QS`,p<16?m`"&R`:m`""R`):m`"!13`))|k)(1,K=g())*K

Wypróbuj online!

W jaki sposób?

Reprezentacja zarządu

Używamy klasycznej reprezentacji planszy 0x88 , aby łatwo było wykryć poza celami kwadraty docelowe.

   |  a    b    c    d    e    f    g    h
---+----------------------------------------
 8 | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 
 7 | 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 
 6 | 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 
 5 | 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 
 4 | 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 
 3 | 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 
 2 | 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67 
 1 | 0x70 0x71 0x72 0x73 0x74 0x75 0x76 0x77

Przenieś kodowanie

Każdy zestaw ruchów jest kodowany za pomocą 5 parametrów:

  • rodzaj kawałka
  • maksymalna liczba kwadratów, które można odwiedzić w każdym kierunku
  • flaga informująca, czy przechwytywanie jest dozwolone
  • flaga informująca, czy niedozwolone jest przechwytywanie
  • lista wskazówek

Wszystkie te parametry są spakowane w jeden ciąg. Na przykład ruchy rycerza są kodowane w następujący sposób:

`&#!#04PTac`
 ||\______/
 ||    |                            +------> 0 + 1 = 1 square in each direction
 ||    |                            | +----> standard moves allowed
 ||    +---> 8 directions           | |+---> captures allowed
 ||                                / \||
 |+--------> ASCII code = 35 = 0b0100011
 |
 +---------> 1 << (ASCII code MOD 32) = 1 << 6 = 64

66

 char. | ASCII code | -66
-------+------------+-----
  '!'  |     33     | -33
  '#'  |     35     | -31
  '0'  |     48     | -18
  '4'  |     52     | -14
  'P'  |     80     | +14
  'T'  |     84     | +18
  'a'  |     97     | +31
  'c'  |     99     | +33

co daje:

 [ - ] [-33] [ - ] [-31] [ - ]
 [-18] [ - ] [ - ] [ - ] [-14]
 [ - ] [ - ] [ N ] [ - ] [ - ]
 [+14] [ - ] [ - ] [ - ] [+18]
 [ - ] [+31] [ - ] [+33] [ - ]

Wszystkie zestawy ruchów są podsumowane w poniższej tabeli, z wyjątkiem przechwyceń en-passant, które są przetwarzane osobno.

  string    | description             | N | S | C | directions
------------+-------------------------+---+---+---+----------------------------------------
 &#!#04PTac | knight                  | 1 | Y | Y | -33, -31, -18, -14, +14, +18, +31, +33
 ##123ACQRS | king                    | 1 | Y | Y | -17, -16, -15, -1, +1, +15, +16, +17
 "!13       | white pawn / captures   | 1 | N | Y | -17, -15
 "!QS       | black pawn / captures   | 1 | N | Y | +15, +17
 "&R        | black pawn / advance x2 | 2 | Y | N | +16
 ""R        | black pawn / advance x1 | 1 | Y | N | +16
 $?13QS     | bishop or queen         | 8 | Y | Y | -17, -15, +15, +17
 %?2ACR     | rook or queen           | 8 | Y | Y | -16, -1, +1, +16

Skomentował

b => e => (
  // generate all moves for a given side
  g = (c, k) =>
    b.map((
      v, p, h,
      // s = square index in 0x88 format
      s = p + (p & ~7),
      // process a move
      M = t =>
        // make sure that the current piece is of the expected color
        v & -~c ?
          c ?
            // Black's turn: play the move
            ( // board backup
              B = [...b],
              // generate all White moves ...
              K &= g(
                // ... after the board has been updated
                b[
                  t ?
                    // standard move
                    b[T] = b[p]
                  :
                    // en-passant capture
                    b[b[e - 8] = 0, e] = 6,
                  p
                ] = 0
              ),
              // restore the board
              b = B
            )
          :
            // White's turn: just update the king's capture flag
            k |= V & 8
        :
          0,
      // generate all moves of a given type for a given piece
      m = ([a], [x, t, ...d] = Buffer(a)) =>
        d.map(c =>
          ( h = n =>
            ( // advance to the next target square
              V = (a += c - 66) & 136 ? 3 : b[T = a + a % 8 >> 1]
            )
            // abort if it's a border or a friendly piece
            & v & 3 ||
            // otherwise: if this kind of move is allowed
            t >> !V &
            // and the current piece is of the expected type
            v >> x &
            // and we haven't reached the maximum number of squares,
            n > 31 &&
            // process this move (if it's a capture, force n to
            // -Infinity so that the recursion stops)
            h(n - 4 / !V, M``)
          )(t, a = s)
        )
    ) =>
      (
        v = b[p],
        // king
        m`##123ACQRS`,
        // bishop or queen
        m`$?13QS`,
        // rook or queen
        m`%?2ACR`,
        // knight
        m`&#!#04PTac`,
        c ?
          // black pawn
          ( // en-passant capture
            p - e + 8.5 & ~1 || M(),
            // standard captures
            m`"!QS`,
            // standard moves
            p < 16 ? m`"&R` : m`""R`
          )
        :
          // white pawn (standard captures only)
          m`"!13`
      )
    ) | k
// is the black king in check if the Black don't move?
// is it still in check after each possible move?
)(1, K = g()) * K
Arnauld
źródło
8/1ppp4/1pkp4/8/2Q5/8/8/7K b - -
tsh
@tsh Znacznie poważniejszy błąd. Naprawiono na razie koszt 6 bajtów.
Arnauld
W jaki sposób działa bez przedstawienia, czy en passant jest możliwy?
Anush
X
Aha. Dziękuję bardzo.
Anush
6

Haskell , 1165 1065 1053 bajtów

Bajty uratowane dzięki Leo Tenenbaumowi

n=Nothing
x?y=Just(x,y)
o(x,y)=x<0||y<0||x>7||y>7
m#k@(x,y)|o k=n|1>0=m!!x!!y
z(x,y)m p(a,b)|o(x+a,y+b)=1<0|Just g<-m#(x+a,y+b)=elem g[(p,0),(5,0)]|1>0=z(x+a,y+b)m p(a,b)
t(x,y)p(a,b)m|o(x+a,y+b)=[]|g<-(x+a,y+b)=(g%p)m++do[0|m#g==n];t g p(a,b)m
c m|(x,y):_<-[(a,b)|a<-u,b<-u,m#(a,b)==6?1],k<-z(x,y)m=or$[m#(x+a,y+b)==6?0|a<-0:s,b<-0:s]++do a<-s;[k 3(a,b)|b<-s]++(k 2<$>[(a,0),(0,a)])++[m#l==4?0|b<-[2,-2],l<-[(x+a,y+b),(x+b,y+a)]]++[m#(x-1,y+a)==p?0|p<-[0,1]]
c m=1>0
(k%p)m=[[[([p|a==k]++[m#a])!!0|a<-(,)b<$>u]|b<-u]|not$o k]
w(Just(_,1))=1<0
w x=1>0
m!u@(x,y)|g<-m#u,Just(q,1)<-g,v<-((u%n)m>>=),r<-v.t u g,k<-(do[0|n==m#(x+1,y)];(u%n)m>>=(x+1,y)%g)++(do a<-s;[0|n<m#(x+1,y+a)];v$(x+1,y+a)%g)++(do[0|(x,n,n)==(1,m#(x+1,y),m#(x+2,y))];v$(x+2,y)%g)++(do a<-s;[0|1?0==m#(x,y+a)];v((x,y+a)%n)>>=(x+1,y+a)%g)=[k,k,do a<-s;[(a,0),(0,a)]>>=r,do a<-s;b<-s;r(a,b),do a<-s;b<-[2,-2];l<-[(x+a,y+b),(x+b,y+a)];v$l%g,do a<-0:s;b<-[0|a/=0]++s;r(a,b),do a<-[x-1..x+1];b<-[y-1..y+1];[0|w$m#(a,b)];v$(a,b)%g]!!q
m!u=[]
u=[0..7]
s=[1,-1]
q m=all c$m:do a<-u;b<-u;m!(a,b)

Wypróbuj online!

Na razie nie jest to do tej pory gra w golfa, ale to dopiero początek. Z pewną pomocą po drodze teraz grałem w golfa dość agresywnie (i naprawiłem błąd po drodze).

Jedną być może wątpliwą rzeczą jest to, że zakłada, że ​​inaczej niż przez króla lub pionka en passant, nigdy nie można wymknąć się spod kontroli, zdobywając jeden ze swoich pionków. W szachach nie możesz wykonać tego ruchu, ale mój program rozważa te ruchy, aby zaoszczędzić bajty przy założeniu, że jeśli jesteś w szachu, nigdy cię to nie wydostanie.

To założenie jest ważne, ponieważ takie ruchy

  1. Nie można schwytać elementu atakującego króla, ponieważ element, który schwytali, jest czarny.

  2. Nie można zablokować ścieżki elementu atakującego króla, ponieważ złapany czarny element już by to zrobił.

Dodajemy również dodatkowy warunek, że jeśli nie masz króla, jesteś pod kontrolą.

Program ten zakłada również, że jeśli istnieje pionek, który można schwytać en passant, wówczas pionek był ostatnim elementem do poruszenia, a ruch ten był legalnym ruchem. Wynika to z faktu, że program nie sprawdza, czy kwadrat, na który przesuwa czarny pionek, jest pusty, więc jeśli jest jakiś element, rzeczy mogą się trochę krzywić. Nie można tego jednak uzyskać, jeżeli ostatni ruch był legalny, a ponadto nie może być reprezentowany w FEN . To założenie wydaje się więc dość solidne.

Oto moja wersja „bez golfa” w celach informacyjnych:

import Control.Monad
out(x,y)=x<0||y<0||x>7||y>7
at b (x,y)
  |out(x,y)=Nothing
  |otherwise=(b!!x)!!y
inLine (x,y) ps m (a,b) 
  | out (x+a,y+b) = False
  | elem (m `at` (x+a,y+b)) $ Just <$> ps = True
  | m `at` (x+a,y+b) == Nothing = inLine (x+a,y+b) ps m (a,b) 
  | otherwise = False
goLine (x,y) p (a,b)m
  | out (x+a,y+b) = []
  | otherwise = case m `at` (x+a,y+b) of
--    Just (n,1) -> []
    Just (n,_) -> set(x+a,y+b)p m
    Nothing    -> set(x+a,y+b)p m ++ goLine(x+a,y+b)p(a,b)m
checkBishop (x,y) m=or[inLine(x,y)[(3,0),(5,0)]m(a,b)|a<-[1,-1],b<-[1,-1]]
checkRook   (x,y) m=or$do
  a<-[1,-1]
  inLine(x,y)[(2,0),(5,0)]m<$>[(a,0),(0,a)]
checkKnight (x,y) m=any((==Just(4,0)).(at m))$do
  a<-[1,-1]
  b<-[2,-2]
  [(x+a,y+b),(x+b,y+a)]
checkPawn (x,y) m=or[at m a==Just(p,0)|a<-[(x-1,y+1),(x-1,y-1)],p<-[0,1]]
checkKing (x,y) m=or[at m(a,b)==Just(6,0)|a<-[x-1..x+1],b<-[y-1..y+1]]
check m
  | u:_<-[(a,b)|a<-[0..7],b<-[0..7],(m!!a)!!b==Just(6,1)] =
    checkBishop u m ||
    checkRook   u m ||
    checkKnight u m ||
    checkPawn   u m ||
    checkKing   u m
  | otherwise = True
set (x,y) p m=[[[head$[p|(a,b)==(y,x)]++[(m!!b)!!a]|a<-[0..7]]|b<-[0..7]]|not$out(x,y)]
white(Just(n,0))=True
white x=False
moves m (x,y)
 |g<-m `at` (x,y)=case g of
  Just(2,1) -> do
    a<-[1,-1]
    b<-[(a,0),(0,a)]
    set(x,y)Nothing m>>=goLine (x,y) g b
  Just(3,1) -> do
    a<-[1,-1]
    b<-[1,-1]
    set(x,y)Nothing m>>=goLine (x,y) g(a,b)
  Just(4,1) -> do
    n<-set(x,y)Nothing m
    a<-[1,-1]
    b<-[2,-2]
    l<-[(x+a,y+b),(x+b,y+a)]
    -- guard$white$n `at` l
    set l g n
  Just(5,1) -> do
    a<-[1,-1]
    c<-[(a,0),(0,a),(a,1),(a,-1)]
    set(x,y)Nothing m>>=goLine (x,y) g c
  Just(6,1) -> do
    a<-[x-1..y+1]
    b<-[x-1..y+1]
    guard$white(m `at`(a,b))||Nothing==m`at`(a,b)
    set(x,y)Nothing m>>=set(a,b)g
  Just(n,1) -> (do
    guard$Nothing==m `at` (x+1,y)
    set(x,y)Nothing m>>=set(x+1,y)g) ++ (do
      a<-[1,-1]
      guard$white$m`at`(x+1,y+a)
      set(x,y)Nothing m>>=set(x+1,y+a)g) ++ (do
        guard$(x,Nothing,Nothing)==(1,m`at`(x+1,y),m`at`(x+1,y))
        set(x,y)Nothing m>>=set(x+2,y)g) ++ (do
          a<-[1,-1]
          guard$Just(1,0)==m`at`(x,y+a)
          set(x,y)Nothing m>>=set(x,y+a)Nothing>>=set(x+1,y+a)g)
  _ -> []
checkmate m=all check$m:do
  a<-[0..7]
  b<-[0..7]
  moves m(a,b)

Wypróbuj online!

Ad Hoc Garf Hunter
źródło
1252 bajty z odrobiną gry w golfa (łącze TIO było zbyt długie, aby zmieścić się w tym komentarzu ...)
Leo Tenenbaum
@LeoTenenbaum Dzięki wielkie dzięki, że wkrótce to uwzględnię, niestety były dwa przypadkowe błędy w wersji, w którą grałeś, z której teraz naprawiłem. Z pewnością istnieje wiele możliwości poprawy na wiele sposobów dzięki tak długiemu programowi.
Ad Hoc Garf Hunter
@ ich, tak, zapomniałem dodać lokalizację królów do miejsca, w którym zmierza. naprawiono teraz
Ad Hoc Garf Hunter
W przypadku list guard x = [0|x]możesz także x?y=Just(x,y)zapisać kilka dodatkowych bajtów: 1129 bajtów
Leo Tenenbaum
1

Python 3 (PyPy) , 729 bajtów

F=lambda a,b:a<'^'<=b or a>'^'>=b
def m(b,P,A=0):
 yield b
 for(r,f),p in b.items(): 
  if F(P,p):continue
  *d,n,k={'R':[(0,1),8,4],'N':[(1,2),(2,1),2,4],'B':[(1,1),8,4],'Q':[(0,1),(1,1),8,4],'K':[(0,1),(1,1),2,4],'P':[(2,0),(1,0),(1,1),(1,-1),2,1],'p':[(-2,0),(-1,0),(-1,1),(-1,-1),2,1]}[p if p=='p'else p.upper()]
  if p in'pP':d=d[d!=[2,7][p=='p']+A:]
  for u,v in d:
   for j in range(k):
    for i in range(1,n):
     U=r+u*i;V=f+v*i;t=b.get((U,V),'^')
     if U<1or U>8or V<1 or V>8:break
     if F(p,t):
      B=dict(b);B[(U,V)]=B.pop((r,f))
      if t in'eE':B.pop(([U+1,U-1][t=='e'],V))
      yield B
     if t not in'^eE':break
    u,v=v,-u
M=lambda b:all(any('k'not in C.values()for C in m(B,'W',1))for B in m(b,'b'))

Wypróbuj online!

RootTwo
źródło
To obecnie kończy się niepowodzeniem dla 8/2p5/Q7/Q2k4/Q7/8/8/7K b - -(nie mat).
Arnauld