Questa stringa è valida FEN?


12

La sfida

Scrivi un programma o una funzione che accetta un input di stringa come parametro di funzione o da stdin e determina se si tratta di una stringa FEN valida .

Ingresso

Si può presumere che l'input includerà sempre e solo i seguenti caratteri (case sensitive)
pkqrbnPKQRBN12345678/
La lunghezza dell'input sarà sempre di almeno 1 carattere e un massimo di 100 caratteri

Produzione

L'output dovrebbe essere un valore di verità / falsità. Questi possono essere i valori desiderati purché siano coerenti (tutti i risultati di verità hanno lo stesso output, tutti i risultati di falsi hanno lo stesso output). Dovresti avere esattamente due distinti possibili output.

Ciò che conta come valido

Le lettere minuscole rappresentano pezzi neri, le lettere maiuscole rappresentano pezzi bianchi.
Dovresti assicurarti che in una partita a scacchi sia possibile che esistano i pezzi nella posizione attuale.
Ogni giocatore avrà sempre esattamente 1 re (k / K)
Ogni giocatore non può avere più di 8 pedine (p / P)
Ogni giocatore di solito non avrà più di 1 * regina (q / Q)
Ogni giocatore di solito non avrà più di 2 * cornacchie (R / R)
Ogni giocatore avrà solitamente non più di 2 * cavalieri (n / n)
Ogni giocatore avrà solitamente non più di 2 * vescovi (B / B)
* E 'legale per un giocatore' promuovere 'una pedina per uno di questi quattro pezzi.
Il totale di pedine, regine, corvi, cavalieri e vescovi per ogni giocatore non sarà mai superiore a 15

Il numero totale di pezzi più i quadrati vuoti (indicati da numeri) dovrebbe sempre aggiungere esattamente 8 per ogni rango. E ci dovrebbero sempre essere esattamente 8 ranghi, separati da una barra.

Cose che puoi ignorare

Non devi preoccuparti se è possibile giocare nella posizione indicata o se la posizione è legale, solo che i pezzi possono esistere nelle quantità indicate.
Puoi ignorare ulteriori complessità delle stringhe FEN come il turno del giocatore, i diritti di castling e il passante.

Questo è il codice golf. Vince il programma più breve in byte. Si applicano solite scappatoie e regole.

Casi test

Input rnbqkbnr / pppppppp / 8/8/8/8 / PPPPPPPP / RNBQKBNR
Output True

Ingresso 2br2k1 / 1p2n1q1 / p2p2p1 / P1bP1pNp / 1BP2PnP / 1Q1B2P1 / 8 / 3NR2K
Uscita True

Ingresso r2r2k1 / p3q2p / ppR3pr / rP4bp / 3p4 / 5B1P / P4PP1 / 3Q1RK1
Uscita falso
(il nero ha 7 pedine e 4 torri - impossibile)

Ingresso 6k1 / pp3ppp / 4p3 / 2P3b1 / bPP3P1 / 3K4 / P3Q1q1
Uscita falso (solo 7 gradi)

Ingresso 3r1rk1 / 1pp1bpp1 / 6p1 / pP1npqPn / 8 / 4N2P / P2PP3 / 1B2BP2 / R2QK2R
Uscita falso (9 gradi)

Ingresso 5n1k / 1p3r1qp / p3p3 / 2p1N2Q / 2P1R3 / 2P5 / P2r1PP1 / 4R1K1
Uscita falso (il 2 ° grado ha 9 quadrati / pezzi)

Input rnbqkbnr / pppppppp / 8/35/8/8 / PPPPPPPPP / RNBQKBNR
Output True
Grazie a Feersum e Arnauld per aver chiarito questo caso (3 + 5 = 8)

Cos'è la FEN?

FEN è una notazione standard per la registrazione della posizione dei pezzi su una scacchiera. Credito di immagine http://www.chessgames.cominserisci qui la descrizione dell'immagine


"Ogni giocatore di solito non avrà più di 1 * regina": chiarisci cosa conta come valido, dato che presumo che non abbia importanza come "normale". È valido per il bianco avere nove regine? Dieci regine? Otto pedine e due regine? Zero re? Una pedina non promossa nel primo o nell'ultimo rango?
Anders Kaseorg,

@AndersKaseorg * It is legal for a player to 'promote' a pawn to any of these four pieces.Il giocatore può avere fino a 9 regine a condizione che il numero di pedine sia ridotto per compensare. Non devi preoccuparti che la posizione dei pezzi sia legale o illegale, ma solo il numero di pezzi.
Darren H,

1
Nel tuo terzo caso di prova, il nero ha 6 pedine, non 7, rendendolo un 'Vero' (?)
pizzapants184

1
@DarrenH La posizione FEN proposta da feersum è valida secondo le tue attuali regole. 35è solo un modo insolito per descrivere 8 quadrati vuoti.
Arnauld,

1
Le pedine @PatrickRoberts in primo o ultimo grado sono valide ai fini di questa sfida. Non è necessario tenere conto della legalità di una posizione, ma solo della quantità di pezzi. La contabilità per la legalità di una posizione (come il fatto che entrambi i giocatori siano sotto controllo) aggiunge molta complessità, quindi ho pensato che una coperta di "posizione non importa" sia più chiara di un dibattito su dove tracciare la linea di ciò che deve essere considerato e cosa no.
Darren H,

Risposte:


5

Retina , 105 byte

[1-8]
$*
^
/
iG`^(/[1KQRBNP]{8}){8}$
G`K
G`k
A`K.*K|k.*k
{2`N

2`B

2`R

1`Q

K

T`L`P
8`P

A`P
}T`l`L
^.

Provalo online! Il link include casi di test. Spiegazione:

[1-8]
$*

Espandi le cifre in quadrati vuoti, che denotiamo usando 1s.

^
/
iG`^(/[1KQRBNP]{8}){8}$

Elimina l'input se non corrisponde a 8 serie di 8 quadrati validi uniti a /s. (Un ulteriore /è prefissato per semplificare il controllo.)

G`K
G`k
A`K.*K|k.*k

Elimina l'input se non ha un re bianco o nero o se ne ha due.

{2`N

2`B

2`R

1`Q

K

Elimina i pezzi di partenza del bianco, se sono ancora lì.

T`L`P

Riduci i pezzi bianchi rimanenti ai pedoni.

8`P

Elimina i pedoni bianchi validi.

A`P

Elimina l'input se ci sono pedine bianche rimaste.

}T`l`L

Ricontrolla ma con i pezzi neri.

^.

Emette un valore veritiero a meno che la riga non sia stata eliminata.


6

JavaScript (ES6), 168 174 ... 155

Questa risposta è stata modificata un numero imbarazzante di volte. Speriamo che la versione attuale sia affidabile e decentemente giocata a golf.


Restituisce un valore booleano.

s=>[...s].map(c=>++n%9?+c?n+=--c:a[i='pP/KkQqRrBbNn'.search(c),i&=i>4&a[i]>(i>6)||i]=-~a[i]:x+=c=='/',a=[x=n=0])&&!([p,P,s,k,K]=a,n-71|x-7|s|k*K-1|p>8|P>8)

Formattato e commentato

s => [...s].map(c =>                  // for each character 'c' in the FEN string 's':
  ++n % 9 ?                           //   if we haven't reached the end of a rank:
    +c ?                              //     if the character is a digit:
      n += --c                        //       advance the board pointer by c - 1 squares
    :                                 //     else:
      a[                              //       update the piece counter array:
        i =                           //         i = piece identifier (0 to 12)
          'pP/KkQqRrBbNn'.search(c),  //             with special case: '/' --> 2
        i &=                          //         we count it as a promoted pawn instead if:
          i > 4 &                     //           it's a Q, R, B or N and we already have
          a[i] > (i > 6) ||           //           2 of them for R, B, N or just 1 for Q
          i                           //           else, we keep the identifier unchanged
      ] = -~a[i]                      //         '-~' allows to increment 'undefined'
  :                                   //   else:
    x += c == '/',                    //     check that the expected '/' is there
  a = [                               //   initialize the piece counter array 'a'
    x =                               //   initialize the '/' counter 'x',
    n = 0 ]                           //   initialize the board pointer 'n'
) &&                                  // end of map()
!(                                    // now it's time to perform all sanity checks:
  [p, P, s, K, k] = a,                //   copy the 5 first entries of 'a' to new variables
  n - 71 |                            //   have we reached exactly the end of the board?
  x - 7 |                             //   have we identified exactly 7 ends of rank?
  s |                                 //   have we encountered any unexpected '/' character?
  k * K - 1 |                         //   do we have exactly one king on each side?
  p > 8 |                             //   no more than 8 black pawns, including promotions?
  P > 8)                              //   no more than 8 white pawns, including promotions?

Casi test


3

Python 3, 284 259 236 225 247 234 byte

import re
s=input()
t,c=s.split("/"),s.count;P=p=9;o=0
for x in"pqrnb":p-=max(0,c(x)-o);P-=max(0,c(x.upper())-o);o+=o<2
v=8==len(t)and all(8==sum(int(x)for x in re.sub("[A-z]","1",p))for p in t)and p>0<P and c('k')==c('K')==1
print(v)

Provalo online!

Provalo online con tutti i casi di test!

-11 byte grazie a Mr. Xcoder

-13 byte grazie a Jonathan Allen

+22 Ho dimenticato che esistevano i re.

Semi-non golfato con qualche spiegazione:

import re
string = input()
split = string.split("/")
count = string.count # find # of occurences of char in string
pawns = 9 # represents the # of pawns a player has out of the game... plus one, e.g. 1 is all in game, 2 is one out, 0 is invalid
PAWNS = 9 # would be 8, but then I would need >= instead of >
offset = 0 # default for pawns
for char in "pqrnb": # for each pawn, each queen over 1, and each rook/knight/bishop over 2 for each player
    # subtract one from the players 'pawns' var, which must end up 1 or greater to be valid
    # otherwise too many pawns/queens/etc of that player are on the board
    pawns -= max(0,count(char)-offset)
    PAWNS -= max(0,count(char.upper())-offset)
    offset += (offset 0 and PAWNS>0 and \ # make sure each player does not have an invalid number of pawns/q/n/b/r
    count('k')==count('K')==1 # correct # of kings
print(valid)

1
234 byte . Ho sostituito ,p,P=9,9con ;P=p=9.
Mr. Xcoder,

1
230 byte . Perché avevi spazi non necessari in for-loop: /
Mr. Xcoder

1
225 byte : è possibile utilizzare p>0<Pinvece di p>0and P>0salvare anche 5 byte. In alternativa, avresti potuto usare p and P(per -3 byte), non hai bisogno di >0, perché i valori diversi da zero sono veritieri in Python
Mr. Xcoder

1
Le pedine possono essere aggiornate, la specifica dice che ci sono 7 pedine minuscole e 4 torri, mentre i miei occhi vedono solo 6 "minuscole".
pizzapants184

1
È possibile salvare 13 byte inizializzando con o=0prima del ciclo e incrementando con o+=o<2alla fine del corpo del ciclo.
Jonathan Allan,

2

PHP , 269 byte

$t=($o=count_chars($a="$argn/"))[47]==8&$o[107]==1&$o[75]==1&9>($w=$u=$o[80])&9>$b=$l=$o[112];foreach([81,82,78,66]as$k=>$v){$z=$k?11:10;$b+=$x=$o[32+$v];$t&=$l+$x<$z;$w+=$x=$o[$v];$t&=$u+$x<$z;}$t&=$b<16&$w<16;for(;$c=$a[$n++];)$c<A?$c>0?$s+=$c:$t&=!$s-=8:++$s;echo$t;

Provalo online!


2

JavaScript (ES6), 181 172 174 byte

f=([c,...s],n=1,o={p:0,P:0})=>c?c=='/'&&n%9?0:f(s,n+(+c||1),(o[c]=(o[c]||0)+(/[qrbn]/i.test(c)&&o[c]>1-/q/i.test(c)?!o[c>'a'?'p':'P']++:1),o)):o.p<9&o.P<9&n==72&o.k==1&o.K==1

Ungolfed:

f=
  ([c,...s],                 //c is current character
   n=1,                      //n is current square, range [1-72] (board is 9x8 due to slashes)
   o={p:0,P:0}               //o holds piece counts
  )=>
  c?
    c=='/'&&n%9?0:           //ensure 8 squares per row
    f(s,
      n+(+c||1),             //increment n by the correct number of squares
      (o[c]=(o[c]||0)+(/[qrbn]/i.test(c)&&o[c]>1-/q/i.test(c)?!o[c>'a'?'p':'P']++:1),o)
                             //"depromote" extra queens, rooks, bishops, or knights
     ):
  o.p<9&o.P<9&               //no more than 8 pawns per side (accounting for promotions)
  o.k==1&o.K==1&             //each side has one and only one king  
  n==72                      //correct number of squares


1

Python 3 , 263 byte

s=input()
n=0
for a in s.split('/'):n+=sum([int(c)if c in"123456789"else 1for c in a])
m=lambda k:{c:s.count(c)for c in s}.get(k,0)
p=[m("p"),m("P")]
for c in"rnbqRNGQ":b=c in"qQ";p[c<"Z"]+=m(c)+b-2if m(c)>2-b else 0
print((n==64)&(p[0]<9>p[1])&(m("K")>0<m("k")))

Provalo online!

Non è la più piccola presentazione di Python, ma penso che abbia ancora qualche promessa.

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.