Apakah string ini FEN valid?

12

Tantangan

Tulis program atau fungsi yang menggunakan input string sebagai parameter fungsi atau dari stdin dan tentukan apakah itu string FEN yang valid .

Memasukkan

Anda dapat mengasumsikan input hanya akan menyertakan karakter berikut (peka huruf besar-kecil)
pkqrbnPKQRBN12345678/
Panjang input akan selalu minimum 1 karakter dan maksimal 100 karakter

Keluaran

Output harus berupa nilai truey / falsey. Ini bisa berupa nilai apa pun yang Anda inginkan asalkan konsisten (semua hasil yang benar memiliki hasil yang sama, semua hasil yang palsu memiliki hasil yang sama). Anda harus memiliki dua kemungkinan output yang berbeda.

Apa yang dianggap valid

Huruf kecil mewakili potongan hitam, huruf besar mewakili potongan putih.
Anda harus memastikan ada kemungkinan dalam permainan catur untuk potongan-potongan di posisi saat ini ada.
Setiap pemain akan selalu memiliki tepat 1 raja (k / K).
Setiap pemain mungkin tidak memiliki lebih dari 8 pion (p / P).
Setiap pemain biasanya tidak memiliki lebih dari 1 * ratu (q / Q).
Setiap pemain biasanya tidak memiliki lagi dari 2 * rooks (r / R)
Setiap pemain biasanya memiliki tidak lebih dari 2 * ksatria (n / N)
Setiap pemain biasanya tidak memiliki lebih dari 2 * uskup (b / B)
* Adalah sah bagi seorang pemain untuk ' mempromosikan 'pion ke salah satu dari keempat bagian ini.
Total pion, ratu, benteng, ksatria, dan uskup untuk setiap pemain tidak akan pernah lebih dari 15

Jumlah total potongan ditambah kotak kosong (dilambangkan dengan angka) harus selalu menambahkan hingga tepat 8 untuk setiap peringkat. Dan harus selalu ada persis 8 peringkat, dipisahkan oleh garis miring ke depan.

Hal yang bisa Anda abaikan

Anda tidak perlu mengkhawatirkan diri Anda dengan apakah mungkin untuk bermain ke posisi yang dilambangkan, atau jika posisi itu legal, hanya potongan-potongan itu bisa ada dalam jumlah yang diberikan.
Anda dapat mengabaikan kompleksitas string FEN lebih lanjut seperti giliran pemain, hak castling dan en passant.

Ini golf kode. Program terpendek dalam byte menang. Celah dan aturan biasa berlaku.

Uji Kasus

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

Input 2br2k1 / 1p2n1q1 / p2p2p1 / P1bP1pNp / 1BP2PnP / 1Q1B2P1 / 8 / 3NR2K
Output Benar

Input r2r2k1 / p3q2p / ppR3pr / rP4bp / 3p4 / 5B1P / P4PP1 / 3Q1RK1
Output Salah
(hitam memiliki 7 pion dan 4 benteng - tidak mungkin)

Input 6k1 / pp3ppp / 4p3 / 2P3b1 / bPP3P1 / 3K4 / P3Q1q1
Output Salah (hanya 7 peringkat)

Input 3r1rk1 / 1pp1bpp1 / 6p1 / pP1npqPn / 8 / 4N2P / P2PP3 / 1B2BP2 / R2QK2R
Output Salah (9 peringkat)

Input 5n1k / 1p3r1qp / p3p3 / 2p1N2Q / 2P1R3 / 2P5 / P2r1PP1 / 4R1K1
Output Salah (peringkat ke-2 memiliki 9 kotak / potongan)

Masukan rnbqkbnr / pppppppp / 8/35/8/8 / PPPPPPPP / RNBQKBNR
Keluaran Benar
Terima kasih kepada Feersum dan Arnauld untuk mengklarifikasi kasus ini (3 + 5 = 8)

Apa itu FEN?

FEN adalah notasi standar untuk merekam posisi potongan-potongan di papan catur. Kredit gambar http://www.chessgames.commasukkan deskripsi gambar di sini

Darren H
sumber
“Setiap pemain biasanya memiliki tidak lebih dari 1 * ratu” - mohon klarifikasi apa yang dianggap valid, karena saya menganggap tidak masalah apa yang dianggap sebagai "biasa". Apakah valid untuk putih memiliki sembilan ratu? Sepuluh ratu? Delapan pion dan dua ratu? Nol raja? Pion tanpa promosi di peringkat pertama atau terakhir?
Anders Kaseorg
@AndersKaseorg * It is legal for a player to 'promote' a pawn to any of these four pieces.Pemain mungkin memiliki hingga 9 ratu asalkan jumlah pion dikurangi untuk mengimbangi. Anda tidak perlu khawatir tentang posisi potongan yang legal atau ilegal, hanya jumlah potongan.
Darren H
1
Dalam test-case ketiga Anda, hitam memiliki 6 pion, bukan 7, menjadikannya 'Benar' (?)
pizzapants184
1
@ DarrenH Posisi FEN yang diajukan oleh feersum valid sesuai dengan aturan Anda saat ini. 35hanyalah cara yang tidak biasa untuk menggambarkan 8 kotak kosong.
Arnauld
1
@PatrickRoberts bidak pada peringkat pertama atau terakhir yang berlaku untuk tujuan tantangan ini. Anda tidak perlu memperhitungkan legalitas suatu posisi, hanya jumlah potongan. Menghitung legalitas suatu posisi (seperti kedua pemain berada dalam kendali) menambah banyak kerumitan, jadi saya pikir selimut 'posisi tidak penting' lebih jelas daripada debat tentang di mana harus menentukan batas dari apa yang perlu dipertanggungjawabkan. dan apa yang tidak.
Darren H

Jawaban:

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

Cobalah online! Tautan termasuk kasus uji. Penjelasan:

[1-8]
$*

Perluas digit ke kotak kosong, yang kami tunjukkan menggunakan 1s.

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

Hapus input jika tidak cocok dengan 8 set dari 8 kotak yang valid yang bergabung dengan /s. (Ekstra /diawali untuk menyederhanakan pemeriksaan.)

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

Hapus input jika tidak ada putih atau tidak ada raja hitam, atau jika ada dua.

{2`N

2`B

2`R

1`Q

K

Hapus potongan awal putih, jika masih ada.

T`L`P

Demosikan potongan putih yang tersisa menjadi pion.

8`P

Hapus pion putih yang valid.

A`P

Hapus input jika ada pion putih yang tersisa.

}T`l`L

Periksa lagi tetapi dengan potongan hitam.

^.

Keluarkan nilai yang sebenarnya kecuali garis itu dihapus.

Neil
sumber
6

JavaScript (ES6), 168 174 ... 155

Jawaban ini telah diedit beberapa kali memalukan. Mudah-mudahan, versi saat ini dapat diandalkan dan layak golf.


Mengembalikan boolean.

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)

Diformat dan dikomentari

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?

Uji kasus

Arnauld
sumber
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)

Cobalah secara Online!

Cobalah Online dengan semua test case!

-11 byte terima kasih kepada Tn. Xcoder

-13 byte terima kasih kepada Jonathan Allen

+22 Saya lupa raja ada.

Semi-ungolfed dengan beberapa penjelasan:

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
sumber
1
234 byte . Saya diganti ,p,P=9,9dengan ;P=p=9.
Tn. Xcoder
1
230 byte . Mengapa Anda memiliki ruang yang tidak perlu di for-loop: /
Mr. Xcoder
1
225 byte : Anda dapat menggunakan p>0<Pbukannya p>0and P>0menyimpan 5 byte juga. Atau, Anda bisa menggunakan p and P(untuk -3 byte), Anda tidak memerlukannya >0, karena nilai-nilai bukan nol adalah benar dalam Python
Tn. Xcoder
1
Bidak dapat ditingkatkan, spek mengatakan bahwa ada 7 bidak huruf kecil dan 4 benteng, sedangkan mataku hanya melihat 6 huruf kecil.
pizzapants184
1
Anda dapat menyimpan 13 byte dengan menginisialisasi dengan o=0sebelum loop dan menambahkan dengan o+=o<2di akhir tubuh loop.
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;

Cobalah online!

Jörg Hülsermann
sumber
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

Tidak Disatukan:

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

Cobalah online!

Bukan pengajuan Python terkecil, tapi saya pikir itu masih memiliki beberapa janji.

MooseOnTheRocks
sumber