该字符串有效吗?


12

挑战

编写一个程序或函数,该程序或函数将字符串输入作为函数参数或从stdin输入并确定它是否为有效的FEN字符串。

输入值

您可以假定输入将仅包含以下字符(区分大小写)
pkqrbnPKQRBN12345678/
输入的长度将始终为最小1个字符和最大100个字符

输出量

输出应为真/假值。这些值可以是您希望的任何值,只要它们是一致的即可(所有真实结果具有相同的输出,所有虚假结果具有相同的输出)。您应该有两个截然不同的可能输出。

什么才算有效

小写字母代表黑色,大写字母代表白色。
您应该确保在象棋游戏中可能存在处于当前位置的棋子。
每个玩家将始终只有一个国王(k / K)
每个玩家最多只能有8个棋子(p / P)
每个玩家通常不会超过1 *王后(q / Q)
每个玩家通常都不会有更多少于2 *名新手(r / R)
每位球员通常不超过2 *名骑士(n / N)
每名球员通常不超过2 *名主教(b / B)
*合法的“将“兵”提升为这四个部分中的任何一个。
每位玩家的棋子,皇后,新手,骑士和主教的总数永远不会超过15

每个等级的总件数加上空方(以数字表示)应始终正好等于8。并且应该始终有8个等级,中间用正斜杠分隔。

您可以忽略的事情

您不必担心自己是否有可能发挥指定的位置,或者如果该位置是合法的,仅需保证所给定的数量即可存在。
您可以忽略FEN琴弦的进一步复杂性,例如演奏者回合,铸造权和传球权。

这是代码高尔夫。以字节为单位的最短程序获胜。通常存在漏洞和规则。

测试用例

输入 rnbqkbnr / pppppppp / 8/8/8/8 / PPPPPPPP / RNBQKBNR
输出 True

输入 2br2k1 / 1p2n1q1 / p2p2p1 / P1bP1pNp / 1BP2PnP / 1Q1B2P1 / 8 / 3NR2K
输出 True

输入 r2r2k1 / p3q2p / ppR3pr / rP4bp / 3p4 / 5B1P / P4PP1 / 3Q1RK1
输出 False
(黑色有7个棋子和4个白钩-不可能)

输入 6k1 / pp3ppp / 4p3 / 2P3b1 / bPP3P1 / 3K4 / P3Q1q1
输出 False(仅7级)

输入 3r1rk1 / 1pp1bpp1 / 6p1 / pP1npqPn / 8 / 4N2P / P2PP3 / 1B2BP2 / R2QK2R
输出 False(9级)

输入 5n1k / 1p3r1qp / p3p3 / 2p1N2Q / 2P1R3 / 2P5 / P2r1PP1 / 4R1K1
输出 False(第二等级有9个正方形/个)

输入 rnbqkbnr / pppppppp / 8/35/8/8 / PPPPPPPP / RNBQKBNR
输出 True
感谢Feersum和Arnauld澄清了这种情况(3 + 5 = 8)

什么是芬?

FEN是用于在棋盘上记录棋子位置的标准符号。 图片来源http://www.chessgames.com在此处输入图片说明


“每个玩家通常不会超过1个皇后” —请澄清什么才是有效的,因为我认为什么才是“正常”并不重要。白人拥有九个皇后是否有效?十个皇后?八个棋子和两个皇后?零国王?排名第一或最后一位的未经推广的棋子?
Anders Kaseorg '17

@AndersKaseorg * It is legal for a player to 'promote' a pawn to any of these four pieces.玩家可以减少9个皇后,只要减少棋子的数量即可。您无需担心棋子的合法或非法位置,而只需担心棋子的数量。
Darren H

1
在您的第三个测试用例中,黑色有6个棋子,而不是7个,使其成为“ True”(True)(?)
pizzapants184 '17

1
@DarrenH根据您当前的规定,feersum提出的FEN职位有效。35只是描述8个空方块的一种不寻常的方式。
Arnauld

1
在第一个或最后排名@PatrickRoberts走卒有效的这一挑战的目的。您无需考虑头寸的合法性,只需计件数即可。考虑到职位的合法性(例如双方都在检查中)会增加很多复杂性,因此我认为,“职位无关紧要”的笼罩要比关于在哪里划清需求的界限的辩论更为清楚。什么没有。
Darren H

Answers:


5

视网膜,105字节

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

在线尝试!链接包括测试用例。说明:

[1-8]
$*

将数字扩展为空的正方形,我们用1s 表示。

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

如果输入与/s 连接的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

再次检查,但黑色部分。

^.

除非删除该行,否则输出真实值。


6

JavaScript的(ES6),168 174 ... 155

这个答案被尴尬地编辑了很多次。希望当前的版本既可靠又不错。


返回一个布尔值。

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)

格式化和评论

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?

测试用例


3

Python 3中,284个259 236 225 247 234字节

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)

在线尝试!

在线尝试所有测试用例!

-11个字节,感谢Xcoder先生

-13字节感谢乔纳森·艾伦

+22我忘记了国王的存在。

半解开并有一些解释:

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个字节。我换成,p,P=9,9;P=p=9
Xcoder先生17年

1
230个字节。为什么在for-loop//
Xcoder先生17年

1
225个字节:您也可以使用p>0<P而不是p>0and P>0保存5个字节。或者,您可能已经使用过p and P(对于-3个字节),您不需要>0,因为非零值在Python中是正确的
Xcoder先生17年

1
典当可以升级,规范说有7个小写的pawn和4个白嘴鸦,而我的眼睛只看到6个小写的'p'。
pizzapant184 '17

1
通过o=0在循环之前进行初始化,并o+=o<2在循环主体的末尾进行递增, 可以节省13个字节。
乔纳森·艾伦

2

PHP,269字节

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

在线尝试!


2

的JavaScript(ES6),181个 172 174字节

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

取消高尔夫:

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字节

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

在线尝试!

不是最小的Python提交,但我认为它仍有希望。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.