Cette chaîne est-elle valide FEN?

12

Le défi

Écrivez un programme ou une fonction qui prend une entrée de chaîne en tant que paramètre de fonction ou de stdin et détermine s'il s'agit d'une chaîne FEN valide .

Contribution

Vous pouvez supposer que l'entrée ne comprendra que les caractères suivants (sensible à la casse)
pkqrbnPKQRBN12345678/
La longueur de l'entrée sera toujours au minimum 1 caractère et au maximum 100 caractères

Production

La sortie doit être une valeur true / falsey. Il peut s'agir de toutes les valeurs souhaitées tant qu'elles sont cohérentes (tous les résultats véridiques ont la même sortie, tous les résultats falsey ont la même sortie). Vous devriez avoir exactement deux sorties distinctes possibles.

Ce qui compte comme valide

Les lettres minuscules représentent les pièces noires, les lettres majuscules représentent les pièces blanches.
Vous devez vous assurer qu'il est possible dans un jeu d'échecs que les pièces dans la position actuelle existent.
Chaque joueur aura toujours exactement 1 roi (k / K)
Chaque joueur ne peut pas avoir plus de 8 pions (p / P)
Chaque joueur n'aura généralement pas plus de 1 * reine (q / Q)
Chaque joueur n'en aura généralement pas plus de 2 * tours (r / R)
Chaque joueur n'aura généralement pas plus de 2 * chevaliers (n / N)
Chaque joueur n'aura généralement pas plus de 2 * évêques (b / B)
* Il est légal pour un joueur de ' promouvoir un pion à l'une de ces quatre pièces.
Le total des pions, reines, tours, chevaliers et évêques pour chaque joueur ne dépassera jamais 15

Le nombre total de pièces plus les cases vides (désignées par des nombres) doit toujours totaliser exactement 8 pour chaque rang. Et il devrait toujours y avoir exactement 8 rangs, séparés par une barre oblique.

Choses que vous pouvez ignorer

Vous n'avez pas à vous soucier de savoir s'il est possible ou non de jouer dans la position indiquée, ou si la position est légale, seulement que les pièces peuvent exister dans les quantités données.
Vous pouvez ignorer d'autres complexités des chaînes FEN telles que le tour du joueur, les droits de roque et en passant.

C'est le golf de code. Le programme le plus court en octets gagne. Les failles et les règles habituelles s'appliquent.

Cas de test

Entrée rnbqkbnr / pppppppp / 8/8/8/8 / PPPPPPPP / RNBQKBNR
Sortie True

Entrée 2br2k1 / 1p2n1q1 / p2p2p1 / P1bP1pNp / 1BP2PnP / 1Q1B2P1 / 8 / 3NR2K
Sortie True

Entrée r2r2k1 / p3q2p / ppR3pr / rP4bp / 3p4 / 5B1P / P4PP1 / 3Q1RK1
Sortie Faux
(le noir a 7 pions et 4 tours - impossible)

Entrée 6k1 / pp3ppp / 4p3 / 2P3b1 / bPP3P1 / 3K4 / P3Q1q1
Sortie Faux (seulement 7 rangs)

Entrée 3r1rk1 / 1pp1bpp1 / 6p1 / pP1npqPn / 8 / 4N2P / P2PP3 / 1B2BP2 / R2QK2R
Sortie Faux (9 rangées)

Entrée 5n1k / 1p3r1qp / p3p3 / 2p1N2Q / 2P1R3 / 2P5 / P2r1PP1 / 4R1K1
Sortie Faux (le 2e rang a 9 carrés / pièces)

Entrée rnbqkbnr / pppppppp / 8/35/8/8 / PPPPPPPP / RNBQKBNR
Sortie True
Merci à Feersum et Arnauld pour avoir clarifié ce cas (3 + 5 = 8)

Qu'est-ce que le FEN?

FEN est une notation standard pour enregistrer la position des pièces sur un échiquier. Crédit d'image http://www.chessgames.comentrez la description de l'image ici

Darren H
la source
"Chaque joueur n'aura généralement pas plus d'une * reine" - veuillez clarifier ce qui compte comme valide, car je suppose que peu importe ce qui compte comme "habituel". Est-il valable pour les blancs d'avoir neuf reines? Dix reines? Huit pions et deux reines? Zéro rois? Un pion non promu au premier ou au dernier rang?
Anders Kaseorg
@AndersKaseorg * It is legal for a player to 'promote' a pawn to any of these four pieces.Le joueur peut avoir jusqu'à 9 reines tant que le nombre de pions est réduit pour compenser. Vous n'avez pas à vous soucier que la position des pièces soit légale ou illégale, seulement le nombre de pièces.
Darren H
1
Dans votre troisième test, le noir a 6 pions, pas 7, ce qui en fait un `` vrai '' (?)
pizzapants184
1
@DarrenH La position FEN proposée par feersum est valide selon vos règles actuelles. 35est juste une façon inhabituelle de décrire 8 cases vides.
Arnauld
1
Les pions @PatrickRoberts au premier ou au dernier rang sont valides pour ce défi. Vous n'avez pas besoin de prendre en compte la légalité d'une position, seulement la quantité de pièces. La prise en compte de la légalité d'une position (comme le fait que les deux joueurs soient en échec) ajoute beaucoup de complexité, donc j'ai pensé qu'une couverture de `` la position n'a pas d'importance '' est plus claire qu'un débat sur où tracer la ligne de ce dont les besoins ont été pris en compte et ce qui ne fonctionne pas.
Darren H

Réponses:

5

Rétine , 105 octets

[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
^.

Essayez-le en ligne! Le lien inclut des cas de test. Explication:

[1-8]
$*

Développez les chiffres en carrés vides, ce que nous désignons par 1s.

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

Supprimez l'entrée si elle ne correspond pas à 8 ensembles de 8 carrés valides joints à l' /art. (Un extra /est préfixé pour simplifier la vérification.)

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

Supprimez l'entrée si elle n'a pas de roi blanc ou noir, ou si elle en a deux.

{2`N

2`B

2`R

1`Q

K

Supprimez les pièces de départ des blancs, s'ils sont toujours là.

T`L`P

Rétrogradez les morceaux blancs restants en pions.

8`P

Supprimez les pions blancs valides.

A`P

Supprimez l'entrée s'il reste des pions blancs.

}T`l`L

Vérifiez encore mais avec les pièces noires.

^.

Sortez une valeur véridique sauf si la ligne a été supprimée.

Neil
la source
6

JavaScript (ES6), 168 174 ... 155

Cette réponse a été modifiée un nombre embarrassant de fois. Espérons que la version actuelle soit à la fois fiable et décente.


Renvoie un booléen.

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)

Formaté et commenté

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?

Cas de test

Arnauld
la source
3

Python 3, 284 259 236 225 247 234 octets

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)

Essayez-le en ligne!

Essayez-le en ligne avec tous les cas de test!

-11 octets grâce à M. Xcoder

-13 octets grâce à Jonathan Allen

+22 J'ai oublié que les rois existaient.

Semi-non golfé avec quelques explications:

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)
pizzapants184
la source
1
234 octets . J'ai remplacé ,p,P=9,9par ;P=p=9.
M. Xcoder du
1
230 octets . Pourquoi avez-vous eu des espaces inutiles dans le for-loop: /
M. Xcoder
1
225 octets : vous pouvez également utiliser p>0<Pau lieu de p>0and P>0pour enregistrer 5 octets. Alternativement, vous auriez pu utiliser p and P(pour -3 octets), vous n'avez pas besoin de >0, car les valeurs non nulles sont véridiques en Python
M. Xcoder
1
Les pions peuvent être améliorés, la spécification dit qu'il y a 7 pions en minuscules et 4 tours, alors que mes yeux ne voient que 6 p en minuscules.
pizzapants184
1
Vous pouvez enregistrer 13 octets en initialisant avec o=0avant la boucle et en incrémentant avec o+=o<2à la fin du corps de la boucle.
Jonathan Allan
2

PHP , 269 octets

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

Essayez-le en ligne!

Jörg Hülsermann
la source
2

JavaScript (ES6), 181 172 174 octets

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

Non golfé:

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

Rick Hitchcock
la source
1

Python 3 , 263 octets

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

Essayez-le en ligne!

Pas la plus petite soumission Python, mais je pense qu'elle a encore des promesses.

MooseOnTheRocks
la source