É xeque-mate?

13

Totalmente surpreso que isso ainda não tenha sido publicado, dado o grande número de quebra-cabeças de xadrez no site. Enquanto eu pensava nisso, agradeço a Anush por publicá-lo na caixa de areia em março . Mas imaginei que já fazia tempo o suficiente para poder fazer isso sozinho.

Um xeque-mate no xadrez é uma posição em que o rei é atacado e não há movimento que possa defendê-lo. Se você não está familiarizado com o movimento das peças de xadrez, pode se familiarizar na Wikipedia .

O desafio

Para esse desafio, sua opinião será a posição de um tabuleiro de xadrez em qualquer notação que você desejar. Para esclarecer, o seu contributo irá descrever as peças em um tabuleiro de xadrez, com suas cores e posições, juntamente com a possível en passant quadrado captura, se houver. (A capacidade de fazer castelo é irrelevante, pois você não pode fazer castelo fora de controle.) Você pode achar a notação FEN útil , mas qualquer formato conveniente é adequado. Para simplificar, você pode assumir que é preto para jogar - isso significa que o preto sempre será o jogador com xadrez. Uma posição em que as brancas estejam em xeque, xeque-mate ou impasse será considerada inválida para este desafio.

Você deve emitir um valor verdadeiro se a posição for xeque-mate e um valor falsey se não for. Observe que o impasse não é xeque-mate - - o rei deve ser atacado!

Casos de teste de verdade

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 / 4T1R1 / R7 / 5k2 / 3pP3 / 5K2 / 8/8 b - -

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

Casos de teste 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 / 2T5 / 3k4 / 3T5 / 8/8 / 7K b - -

8 / 4Q1R1 / R7 / 5k2 / 3pP3 / 5K2 / 8/8 b - e3 (Veja isso em passante!)

Código golf - o código mais curto em bytes vence. Boa sorte!

dispersar
fonte
2
Isto parece uma grande questão :)
Anush
1
No interesse de ser independente - quais devem ser todos os desafios aqui - isso precisa ser muito mais desenvolvido do que depender de vínculos externos e / ou assumir um conhecimento existente das regras e da notação do xadrez. Eu sugiro levá-lo de volta ao Sandbox enquanto ele está sendo trabalhado.
Shaggy
3
@ Shaggy Os links externos neste desafio servem apenas por conveniência. Não vou listar todas as regras do xadrez aqui, pois a maioria dos outros desafios do xadrez pressupõe o conhecimento prévio deles. E os links de lichess servem apenas como uma representação visual útil dos casos de teste; a notação é bem definida fora da líquen. Eu poderia adicionar imagens, mas decidi não fazê-lo, pois parecia muita confusão.
scatter
1
Podemos supor que o tabuleiro foi alcançado através de um jogo válido?
Post Rock Garf Hunter
1
Reabri isso porque, embora a tarefa principal seja a mesma, esse desafio tem um esquema de IO muito mais relaxado (e honestamente melhor) e um critério de pontuação um pouco diferente (e honestamente melhor). Penso que talvez o antigo deva ser fechado como um tolo do novo, mas não vou martelá-lo.
Post Rock Garf Hunter

Respostas:

10

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

(b)(X)bX-1

Abaixo estão os valores esperados para cada quadrado:

 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 0

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

Experimente online!

Quão?

Representação do Conselho

Usamos a representação clássica da placa 0x88 , para que os quadrados de destino fora dos limites possam ser facilmente detectados.

   |  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

Mover codificação

Cada conjunto de movimentos é codificado com 5 parâmetros:

  • o tipo de peça
  • o número máximo de quadrados que podem ser visitados em cada direção
  • uma bandeira informando se as capturas são permitidas
  • uma bandeira informando se não são permitidas capturas
  • uma lista de direções

Todos esses parâmetros são compactados em uma única sequência. Por exemplo, os movimentos dos cavaleiros são codificados da seguinte maneira:

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

que dá:

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

Todos os conjuntos de movimentos estão resumidos na tabela a seguir, exceto as capturas passantes que são processadas separadamente.

  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

Comentado

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
fonte
8/1ppp4/1pkp4/8/2Q5/8/8/7K b - -
tsh
@tsh Um bug muito mais sério. Corrigido ao custo de 6 bytes por enquanto.
Arnauld
Como funciona sem uma representação informando se é possível passá-lo?
Anush 28/08/19
X
Aha. Muito obrigado.
Anush 28/08/19
6

Haskell , 1165 1065 1053 bytes

Bytes economizados graças 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)

Experimente online!

Isso não está exatamente bem no momento, mas é um começo. Com alguma ajuda ao longo do caminho, agora joguei isso de forma bastante agressiva (e corrigi um erro ao longo do caminho).

A única coisa questionável que isso faz é que ele pressupõe que, exceto por um rei ou um peão de passagem, você nunca poderá sair do controle capturando uma de suas próprias peças. No xadrez, você não tem permissão para fazer essa jogada, mas meu programa considera essas jogadas para economizar bytes, pressupondo que, se você estiver checado, isso nunca poderá tirar você disso.

Essa suposição é válida porque tais movimentos

  1. Não é possível capturar a peça que está atacando o rei, pois a peça que eles capturam é preta.

  2. Não é possível bloquear o caminho da peça que está atacando o rei, pois a peça preta capturada já estaria fazendo isso.

Também acrescentamos a estipulação adicional de que, se você não tem rei, está em xeque.

Esse programa também pressupõe que, se houver um peão que possa ser capturado passant, então o peão foi a última peça a ser movida e essa foi uma jogada legal. Isso ocorre porque o programa não verifica se o quadrado para o qual move o peão preto está vazio; portanto, se houver uma peça, as coisas podem ficar um pouco esquisitas. No entanto, isso não pode ser obtido se a última jogada foi uma jogada legal e, além disso, não pode ser representada na FEN . Portanto, essa suposição parece bastante sólida.

Aqui está a minha versão "ungolfed" para referência:

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)

Experimente online!

Post Rock Garf Hunter
fonte
1252 bytes com um pouco de golfe (no link TIO foi muito longo para caber neste comentário ...)
Leo Tenenbaum
@LeoTenenbaum Muito obrigado. Incorporarei isso em breve. Infelizmente, houve dois erros acidentais na versão em que você estava jogando golfe, dos quais agora corrigi. Certamente há espaço para melhorar de várias maneiras com um programa por tanto tempo.
Post Rock Garf Hunter
@tsh sim, eu esqueci de adicionar a localização dos reis para onde estava indo. corrigido agora
post rock Garf Hunter
Para listas,, guard x = [0|x]e você também pode usar x?y=Just(x,y)para salvar mais alguns bytes: 1129 bytes
Leo Tenenbaum
1

Python 3 (PyPy) , 729 bytes

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

Experimente online!

RootTwo
fonte
Isso atualmente falha para 8/2p5/Q7/Q2k4/Q7/8/8/7K b - -(não para xeque-mate).
Arnauld