È scacco matto?


13

Completamente sorpreso, questo non è già stato pubblicato, dato il gran numero di puzzle di scacchi sul sito. Mentre ci ho pensato io, merito ad Anush per averlo pubblicato nella sandbox a marzo . Ma ho pensato che fosse abbastanza a lungo da poter andare avanti e farlo da solo.

Un scacco matto negli scacchi è una posizione in cui il re viene attaccato e non c'è mossa che possa difenderlo. Se non hai familiarità con il modo in cui si muovono i pezzi degli scacchi, puoi familiarizzare con Wikipedia .

La sfida

Per questa sfida, il tuo input sarà la posizione di una scacchiera in qualunque notazione ti piaccia. Per chiarire, il tuo input descriverà i pezzi su una scacchiera, con i loro colori e posizioni, insieme con l'eventuale quadrato di cattura en passant , se presente. (La possibilità di eseguire il casting è irrilevante in quanto non è possibile eseguire il casting senza controllo.) Potresti trovare utile la notazione FEN , ma qualsiasi formato conveniente va bene. Per semplicità, puoi presumere che sia Black a giocare - questo significa che Black sarà sempre il giocatore scacco matto. Una posizione in cui il Bianco è sotto controllo, scacco matto o stallo sarà considerata non valida per questa sfida.

È necessario generare un valore di verità se la posizione è scacco matto e un valore di falsa in caso contrario. Nota che lo stallo non è scacco matto : il re deve essere attaccato!

Casi di prova veritieri

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

Casi di prova Falsey

rnbqkbnr / pppppppp / 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 (Guarda che en passant!)

Codice golf: vince il codice più breve in byte. In bocca al lupo!


2
Sembra un'ottima domanda :)
Anush,

1
Nell'interesse di essere autonomi - che dovrebbero essere tutte le sfide qui - questo deve essere arricchito molto più che fare affidamento su collegamenti esterni e / o assumere una conoscenza esistente delle regole e della notazione degli scacchi. Suggerirei di riportarlo sulla Sandbox mentre è in fase di elaborazione.
Shaggy,

3
@Shaggy I link esterni in questa sfida servono solo per comodità. Non elencherò qui tutte le regole degli scacchi, poiché la maggior parte delle altre sfide di scacchi presuppone una loro conoscenza preliminare. E i collegamenti lichess servono solo come una pratica rappresentazione visiva dei casi di test; la notazione è ben definita al di fuori di lichess. Potrei aggiungere immagini ma ho deciso di non farlo perché mi sembrava un sacco di disordine.
disperde il

1
Possiamo presumere che il tabellone sia stato raggiunto tramite un gioco valido?
Post Rock Garf Hunter,

1
L'ho riaperto perché, sebbene il compito principale sia lo stesso, questa sfida ha uno schema di IO molto più rilassato (e onestamente migliore) e un criterio di punteggio leggermente diverso (e onestamente migliore). Penso che forse il vecchio dovrebbe essere chiuso come un duplicato di quello nuovo, ma non ho intenzione di martellarlo.
Post Rock Garf Hunter,

Risposte:


10

JavaScript (Node.js) ,  499 ... 374  370 byte

(b)(X)BX-1 se non ce ne sono.

Di seguito sono riportati i valori previsti per ciascun quadrato:

 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

Provalo online!

Come?

Rappresentanza del consiglio

Usiamo la classica rappresentazione della scheda 0x88 , in modo che i quadrati dei target fuori limite possano essere facilmente rilevati.

   |  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

Sposta la codifica

Ogni serie di mosse è codificata con 5 parametri:

  • il tipo di pezzo
  • il numero massimo di quadrati che possono essere visitati in ciascuna direzione
  • una bandiera che indica se sono consentite catture
  • una bandiera che indica se sono consentite non acquisizioni
  • un elenco di direzioni

Tutti questi parametri sono racchiusi in una singola stringa. Ad esempio, le mosse del cavaliere sono codificate come segue:

`&#!#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

che dà:

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

Tutti i set di mosse sono riepilogati nella tabella seguente, ad eccezione delle acquisizioni en-passant che vengono elaborate separatamente.

  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

Commentate

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

8/1ppp4/1pkp4/8/2Q5/8/8/7K b - -
TSH

@tsh Un bug molto più serio. Risolto al costo di 6 byte per ora.
Arnauld,

Come funziona senza una rappresentazione che ti dice se en passant è possibile?
Anush,

X

Aha. Grazie mille.
Anush,

6

Haskell , 1165 1065 1053 byte

Byte salvati grazie a Leo Tenenbaum

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)

Provalo online!

Questo non è esattamente ben golfato al momento, ma è un inizio. Con un po 'di aiuto lungo la strada, ora ho risolto il problema in modo piuttosto aggressivo (e ho corretto un errore lungo la strada).

L'unica cosa forse discutibile che fa è che si presume che, a parte un re o un pedone en passant, non si possa mai sfuggire al controllo catturando uno dei propri pezzi. Negli scacchi non ti è permesso fare questa mossa, ma il mio programma considera queste mosse per salvare byte supponendo che se sei sotto controllo questo non ti farà mai uscire.

Questa ipotesi è valida perché tali mosse

  1. Non è possibile catturare il pezzo che sta attaccando il re, poiché il pezzo che catturano è nero.

  2. Non è possibile bloccare il percorso del pezzo che sta attaccando il re, poiché il pezzo nero catturato lo avrebbe già fatto.

Aggiungiamo anche la clausola aggiuntiva che se non hai un re sei sotto controllo.

Questo programma presuppone anche che se c'è una pedina che può essere catturata in modo passivo, la pedina è stata l'ultima pedina da muovere e quella mossa è stata una mossa legale. Questo perché il programma non controlla se il quadrato in cui si sposta il pedone nero è vuoto, quindi se c'è un pezzo lì le cose possono diventare un po 'complicate. Tuttavia, ciò non può essere ottenuto se l'ultima mossa è stata una mossa legale e inoltre non può essere rappresentata nella FEN . Quindi questo assunto sembra piuttosto solido.

Ecco la mia versione "ungolfed" per riferimento:

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)

Provalo online!


1252 byte con un po 'di golf (il collegamento TIO era troppo lungo per adattarsi a questo commento ...)
Leo Tenenbaum,

@LeoTenenbaum Grazie mille lo incorporerò a breve purtroppo ci sono stati due errori accidentali nella versione che stavi giocando a golf da cui ora ho risolto. C'è sicuramente spazio per migliorare in molti modi con un programma così lungo.
Post Rock Garf Hunter,

@tsh sì, ho dimenticato di aggiungere la posizione dei re a dove stava andando. risolto ora
Post Rock Garf Hunter

Per gli elenchi guard x = [0|x]e puoi anche utilizzare x?y=Just(x,y)per salvare qualche altro byte: 1129 byte
Leo Tenenbaum,

1

Python 3 (PyPy) , 729 byte

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'))

Provalo online!


Questo al momento fallisce per 8/2p5/Q7/Q2k4/Q7/8/8/7K b - -(non scacco matto).
Arnauld,
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.