Czy ten ciąg jest prawidłowy FEN?

12

Wyzwanie

Napisz program lub funkcję, która pobiera ciąg znaków jako parametr funkcji lub ze standardowego wejścia i określa, czy jest to prawidłowy ciąg FEN .

Wejście

Możesz założyć, że dane wejściowe będą zawierały tylko następujące znaki (wielkość liter ma znaczenie)
pkqrbnPKQRBN12345678/
Długość danych wejściowych zawsze będzie wynosić co najmniej 1 znak i maksymalnie 100 znaków

Wynik

Dane wyjściowe powinny mieć wartość true / falsey. Mogą to być dowolne wartości, o ile są spójne (wszystkie prawdziwe wyniki mają tę samą moc wyjściową, wszystkie wyniki falsey mają tę samą moc wyjściową). Powinieneś mieć dokładnie dwa różne możliwe wyniki.

Co uznaje się za ważne

Małe litery reprezentują czarne elementy, wielkie litery oznaczają białe elementy.
Powinieneś upewnić się, że w grze w szachy możliwe jest istnienie pionków na aktualnej pozycji.
Każdy gracz zawsze będzie miał dokładnie 1 króla (k / K)
Każdy gracz może mieć nie więcej niż 8 pionków (p / P)
Każdy gracz zwykle ma nie więcej niż 1 * królową (q / Q)
Każdy gracz zwykle nie ma więcej niż 2 * wieże (r / r)
Każdy gracz zwykle będzie miał nie więcej niż 2 * rycerzy (n / N)
Każdy gracz zwykle będzie miał nie więcej niż 2 * biskupów (b / B)
* Gracz może legalnie „ wypromować pionka do dowolnego z tych czterech elementów.
Suma pionków, królowych, wież, rycerzy i biskupów dla każdego gracza nigdy nie przekroczy 15

Całkowita liczba sztuk plus puste kwadraty (oznaczone liczbami) zawsze powinny sumować się dokładnie do 8 dla każdej rangi. I zawsze powinno być dokładnie 8 stopni, oddzielonych ukośnikiem.

Rzeczy, które możesz zignorować

Nie musisz się martwić, czy możliwe jest zagranie na oznaczonej pozycji, czy też jeśli pozycja jest legalna, tylko że elementy mogą istnieć w podanych ilościach.
Możesz zignorować dalsze złożoności łańcuchów FEN, takie jak tura gracza, prawa roszowania i en passant.

To jest kod golfowy. Najkrótszy program w bajtach wygrywa. Obowiązują zwykłe luki i zasady.

Przypadki testowe

Wejście rnbqkbnr / pppppppp / 8/8/8/8 / PPPPPPPP / RNBQKBNR
Wyjście True

Wejście 2br2k1 / 1p2n1q1 / p2p2p1 / P1bP1pNp / 1BP2PnP / 1Q1B2P1 / 8 / 3NR2K
Wyjście Prawda

Input r2r2k1 / p3q2p / ppR3pr / rP4bp / 3p4 / 5B1P / P4PP1 / 3Q1RK1
Output False
(czarny ma 7 pionków i 4 wieże - niemożliwe)

Wejście 6k1 / pp3ppp / 4p3 / 2P3b1 / bPP3P1 / 3K4 / P3Q1q1
Wyjście Fałsz (tylko 7 stopni )

Wejście 3r1rk1 / 1pp1bpp1 / 6p1 / pP1npqPn / 8 / 4N2P / P2PP3 / 1B2BP2 / R2QK2R
Wyjście Fałsz (9 stopni )

Wejście 5n1k / 1p3r1qp / p3p3 / 2p1N2Q / 2P1R3 / 2P5 / P2r1PP1 / 4R1K1
Wyjście Fałsz (2. stopień ma 9 kwadratów / sztuk)

Wprowadź rnbqkbnr / pppppppp / 8/35/8/8 / PPPPPPPP / RNBQKBNR
Wyjście True
Dziękujemy Feersum i Arnauld za wyjaśnienie tej sprawy (3 + 5 = 8)

Co to jest FEN?

FEN jest standardowym zapisem do rejestrowania pozycji pionków na szachownicy. Kredyt na zdjęcia http://www.chessgames.comwprowadź opis zdjęcia tutaj

Darren H.
źródło
„Każdy gracz zwykle ma nie więcej niż 1 * królową” - proszę wyjaśnić, co liczy się jako ważne, ponieważ zakładam, że nie ma znaczenia, co liczy się jako „zwykłe”. Czy białe mają dziewięć królowych? Dziesięć królowych? Osiem pionków i dwie królowe? Zero królów? Bezproblemowy pionek na pierwszym czy ostatnim poziomie?
Anders Kaseorg
@AndersKaseorg * It is legal for a player to 'promote' a pawn to any of these four pieces.Gracz może mieć do 9 królowych, o ile liczba pionów zostanie zmniejszona, aby to zrekompensować. Nie musisz się martwić o to, czy pozycja jest legalna lub nielegalna, a tylko o liczbę sztuk.
Darren H
1
W trzecim przypadku czarny ma 6 pionków, a nie 7, co czyni go „Prawdą” (?)
pizzapants184
1
@DarrenH Stanowisko FEN zaproponowane przez feersum jest ważne zgodnie z obowiązującymi przepisami. 35to po prostu niezwykły sposób na opisanie 8 pustych kwadratów.
Arnauld
1
@PatrickRoberts pionki na pierwszym lub ostatnim poziomie ważne do celów tego wyzwania. Nie musisz brać pod uwagę legalności pozycji, tylko ilość sztuk. Rozliczenie legalności pozycji (np. Obaj gracze w szachach) dodaje dużo komplikacji, więc doszedłem do wniosku, że koc „pozycja nie ma znaczenia” jest jaśniejszy niż debata na temat tego, gdzie wytyczyć granicę potrzeb a co nie.
Darren H

Odpowiedzi:

5

Siatkówka , 105 bajtów

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

Wypróbuj online! Link zawiera przypadki testowe. Wyjaśnienie:

[1-8]
$*

Rozwiń cyfry do pustych kwadratów, które oznaczamy za pomocą 1s.

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

Usuń dane wejściowe, jeśli nie pasują one do 8 zestawów 8 prawidłowych kwadratów połączonych /s. ( /Prefiks jest dodawany w celu uproszczenia kontroli).

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

Usuń wejście, jeśli nie ma białego lub czarnego króla, lub jeśli ma dwa z nich.

{2`N

2`B

2`R

1`Q

K

Usuń początkowe elementy bieli, jeśli nadal tam są.

T`L`P

Obniż pozostałe pionki do pionków.

8`P

Usuń prawidłowe białe pionki.

A`P

Usuń wejście, jeśli pozostały białe pionki.

}T`l`L

Sprawdź jeszcze raz, ale z czarnymi kawałkami.

^.

Podaj prawdziwą wartość, chyba że wiersz został usunięty.

Neil
źródło
6

JavaScript (ES6), 168 174 ... 155

Ta odpowiedź była wielokrotnie krępująca. Mamy nadzieję, że obecna wersja jest zarówno niezawodna, jak i przyzwoita.


Zwraca wartość logiczną.

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)

Sformatowane i skomentowane

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?

Przypadki testowe

Arnauld
źródło
3

Python 3, 284 259 236 225 247 234 bajtów

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)

Wypróbuj online!

Wypróbuj online ze wszystkimi testami!

-11 bajtów dzięki Mr. Xcoder

-13 bajtów dzięki Jonathanowi Allenowi

+22 Zapomniałem, że królowie istnieją.

Na wpół nieprzygotowany z pewnym wyjaśnieniem:

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)
pizzapanty184
źródło
1
234 bajty . Wymieniłem ,p,P=9,9z ;P=p=9.
Pan Xcoder
1
230 bajtów . Dlaczego mieliście niepotrzebne spacje w for-loop: /
Mr. Xcoder
1
225 bajtów : Możesz użyć p>0<Pzamiast p>0and P>0zapisać 5 bajtów. Alternatywnie, mógłbyś użyć p and P(dla -3 bajtów), nie potrzebujesz >0, ponieważ niezerowe wartości są prawdziwe w Pythonie
Mr. Xcoder
1
Pionki można ulepszać, specyfikacja mówi, że jest 7 małych pionków i 4 wieże, podczas gdy moje oczy widzą tylko 6 małych liter.
pizzapants184
1
Możesz zapisać 13 bajtów, inicjując z o=0przed pętlą i zwiększając z o+=o<2na końcu ciała pętli.
Jonathan Allan
2

PHP , 269 bajtów

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

Wypróbuj online!

Jörg Hülsermann
źródło
2

JavaScript (ES6), 181 172 174 bajtów

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

Nie golfowany:

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
źródło
1

Python 3 , 263 bajty

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

Wypróbuj online!

Nie jest to najmniejsze zgłoszenie w języku Python, ale myślę, że wciąż ma pewne obietnice.

MooseOnTheRocks
źródło