13
\$\begingroup\$

Introduction

Fischer random chess, also known as Chess960 for the 960 valid starting boards, is a variant of chess where each player's pieces are randomly shuffled at the start. As a reminder, each player gets 8 pawns, two rooks, two knights, two bishops, one queen, and one king. For this challenge, you don't need to know anything about the rules of chess, as we are only concerned with the starting positions of the pieces on a 8x8 chessboard. In particular, white's non-pawn pieces are placed randomly on the first rank (row of the chessboard). The white pawns are placed on the second rank as usual. In addition, the following rules for white's non-pawn pieces must be adhered to:

  • The bishops must be placed on opposite color squares (since the chessboard has a checkerboard pattern, that means there is an odd distance between them)
  • The king must be placed on a square between the rooks

Black's pieces are placed mirroring white's horizontally on the board, so that black's pieces are on the same file (column) as the corresponding white's pieces.

The input board must be given as a FEN board string, which is standard for chess programs. From the FEN specification:

The board contents are specified starting with the eighth rank and ending with the first rank. For each rank, the squares are specified from file a to file h. White pieces are identified by uppercase SAN piece letters ("PNBRQK") and black pieces are identified by lowercase SAN piece letters ("pnbrqk"). Empty squares are represented by the digits one through eight; the digit used represents the count of contiguous empty squares along a rank. A solidus character "/" is used to separate data of adjacent ranks.

For reference, SAN piece letters are: pawn = "P", knight = "N", bishop = "B", rook = "R", queen = "Q", and king = "K". White's pieces are in uppercase while black's are in lowercase.

Task

Given a valid FEN board string, described above, output a boolean value for whether or not the input board is a Fischer random chess starting board.

Test cases

Valid boards

The first string is a standard board (fun fact: board 518 in the standard Fischer random chess numbering scheme).

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
rqkbbrnn/pppppppp/8/8/8/8/PPPPPPPP/RQKBBRNN
bqrnnkrb/pppppppp/8/8/8/8/PPPPPPPP/BQRNNKRB
nrbbqnkr/pppppppp/8/8/8/8/PPPPPPPP/NRBBQNKR
bqnrnkrb/pppppppp/8/8/8/8/PPPPPPPP/BQNRNKRB
nnqrkrbb/pppppppp/8/8/8/8/PPPPPPPP/NNQRKRBB
nnbrkqrb/pppppppp/8/8/8/8/PPPPPPPP/NNBRKQRB
nbbrnkqr/pppppppp/8/8/8/8/PPPPPPPP/NBBRNKQR
rknrnbbq/pppppppp/8/8/8/8/PPPPPPPP/RKNRNBBQ
qnbbrknr/pppppppp/8/8/8/8/PPPPPPPP/QNBBRKNR

Invalid boards

Everything after the board string starting with # is a comment for compactness and is not part of the input.

8/8/8/8/8/8/8/8                                # Empty board
8/8/8/8/8/8/PPPPPPPP/RNBQKBNR                  # Missing black's pieces
RNBQKBNR/PPPPPPPP/8/8/8/8/PPPPPPPP/RNBQKBNR    # Missing black's pieces and too many white pieces
rnbqkbnr/ppp1pppp/8/8/8/8/PPPPPPPP/RNBQKBNR    # Missing pawn
rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR    # Black's pieces don't mirror white's
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR  # Not a starting board
4q2k/2r1r3/4PR1p/p1p5/P1Bp1Q1P/1P6/6P1/6K1     # Definitely not a starting board
rkbqnnbr/pppppppp/8/8/8/8/PPPPPPPP/RKBQNNBR    # Bishops must be on opposite squares
qkrnbbrn/pppppppp/8/8/8/8/PPPPPPPP/QKRNBBRN    # King must be between rooks
rkrbbnnn/pppppppp/8/8/8/8/PPPPPPPP/RKRBBNNN    # Missing queens
\$\endgroup\$
9
  • 4
    \$\begingroup\$ Suggested testcase: rkrbbnnn/pppppppp/8/8/8/8/PPPPPPPP/RKRBBNNN (Missing queens) \$\endgroup\$
    – emanresu A
    Commented Jun 6, 2021 at 5:52
  • 2
    \$\begingroup\$ Tip for brute force solutions: if you are generating all valid boards, you should be getting exactly 960 unique possible starting positions. \$\endgroup\$
    – Razetime
    Commented Jun 6, 2021 at 9:36
  • \$\begingroup\$ Unknown about rotated board QNBBRKNR/PPPPPPPP/8/8/8/8/pppppppp/qnbbrknr \$\endgroup\$
    – l4m2
    Commented Jun 6, 2021 at 22:49
  • \$\begingroup\$ @l4m2 "In particular, white's non-pawn pieces are placed randomly on the first rank" and "The board contents are specified starting with the eighth rank", hence that is an invalid one. Probably worth being a test-case though. \$\endgroup\$ Commented Jun 7, 2021 at 11:51
  • \$\begingroup\$ So solutions can take it for granted that each side has two rooks, two knights, two bishops, one queen, and one king, without needing to check the piececount? e.g. RRNBQKRB is illegal but would pass most solutions here. \$\endgroup\$
    – smci
    Commented Jun 7, 2021 at 23:52

8 Answers 8

6
\$\begingroup\$

Jelly, 82 bytes

”pẋ8;⁶ẋ⁴¤“bbknnqrr”;s8;ṚŒu$$
ṣ”/8RṾ,⁶ẋ$Ɗ€Z¤yⱮµF€Ṣ€⁼¢ȧ1ịẹ”bƲSḂƊȧ8ịf⁾RKƲ⁼U$$ȧṪ⁼ḢŒu$Ɗ

Try it online!

”pẋ8;⁶ẋ⁴¤“bbknnqrr”;s8;ṚŒu$$    Helper Link (nilad)
”p                              "p"
  ẋ8                            repeated 8 times
    ;---¤                       then append
     ⁶                          " "
      ẋ⁴                        repeated 16 times
         “bbknnqrr”;            then prepend "bbknnqrr"
                    s8          slice into chunks of length 8
                      ;----$    append
                       ṚŒu$     the grid, reversed, uppercased

This helper link generates an 8x8 matrix representing any valid starting position if each row is sorted alphabetically.

ṣ”/8RṾ,⁶ẋ$Ɗ€Z¤yⱮ    Main Link - first part
ṣ”/                 split the input on "/"
   8 ---------¤      (inline niladic chain)
   8R               [1, 2, ..., 8]
     -----Ɗ€        for each of those
     Ṿ              uneval it (turn to string)
      ,             and pair with
       ⁶ẋ$          " " * (the number)
              yⱮ    apply this as a transformation to each

This part converts from FEN notation to an 8x8 matrix of characters, where blanks are spaces.

µF€Ṣ€⁼¢             Main Link - second part
µ                   start a new monadic chain (avoids chaining)
 F€                 flatten each row
   Ṣ€               sort each row
     ⁼¢             is it equal to (helper link)?

This part checks if the board's rows have the correct pieces.

ȧ1ịẹ”bƲSḂƊ          Main Link - third part
ȧ                   logical AND
 --------Ɗ
 -----Ʋ
 1ị                 1st element
   ẹ”b              find indices of bishops
       S            sum
        Ḃ           is it odd?

This part checks for the positioning of the bishops in the first row.

ȧ8ịf⁾RKƲ⁼U$$        Main Link - fourth part
ȧ                   logical AND
 ----------$
 ------Ʋ
 8ị                 8th element
   f⁾RK             filter to only keep R and K
        ⁼U$         is it equal to its reverse?

This part checks if the kings and rooks are in the order RKR; since we've already made sure each row's piece count is correct, the only way for it to be symmetric is to be RKR.

ȧṪ⁼ḢŒu$Ɗ            Main Link - fifth part
ȧ                   logical AND
 ------Ɗ
 Ṫ                  pop the last row
  ⁼                 is it equal to
   ḢŒu$             the first row uppercase?

This part makes sure the black and white pieces align.

\$\endgroup\$
5
\$\begingroup\$

Retina 0.8.2, 91 83 80 bytes

G`^[b-r]{8}/p{8}(/8){4}/P{8}/[B-R]{8}$
Gi`^(.{8}).*\1
G`b(..)*b.*R.*K.*R
q.*N.*N

Try it online! Link includes test cases. Edit: Saved 2 bytes thanks to @Jakque. Explanation:

G`^[b-r]{8}/p{8}(/8){4}/P{8}/[B-R]{8}$

Check that both sides have exactly 8 pieces and pawns. The following checks then require those pieces to include at least one each of king and queen and at least two each of the other three pieces, therefore those pieces are in fact exactly one and two each of the appropriate pieces.

Gi`^(.{8}).*\1

Now that we know that the first eight pieces are Black's and the last eight are White's, check that White's pieces mirror Black's.

G`b(..)*b.*R.*K.*R

Check that Black has at least two bishops on opposite coloured squares and White has at least one king between two rooks.

q.*N.*N

Check that Black has at least one queen and White has at least two knights.

\$\endgroup\$
7
  • \$\begingroup\$ Nice, I was waiting for a regex solution \$\endgroup\$
    – qwr
    Commented Jun 6, 2021 at 8:01
  • \$\begingroup\$ Sneaky, Beats jelly by one byte!! \$\endgroup\$
    – Wasif
    Commented Jun 6, 2021 at 8:12
  • \$\begingroup\$ @Wasif not anymore :) \$\endgroup\$
    – hyperneutrino
    Commented Jun 6, 2021 at 8:52
  • \$\begingroup\$ @Wasif Especially since the bugfix... \$\endgroup\$
    – Neil
    Commented Jun 6, 2021 at 10:54
  • \$\begingroup\$ -2: by making some verification on white's pieces (instead of black's) to make multiple verification on the same line: Try it online! \$\endgroup\$
    – Jakque
    Commented Jun 6, 2021 at 15:59
4
\$\begingroup\$

05AB1E, 43 bytes

Same length as a valid input ;). Very slow, generates all valid boards (8 times) and checks if the list contains the input.

.•5h+…Í•œʒæ…rkrå}ʒ'b¡1ègÈ}ε'p8×8D)Âu«'/ý}så

Try it online!

Commented:

.•5h+…Í•           # alphabet compressed string "bbknnqrr"
        œ          # all permutations of this string

                   # remove invalid configurations of black pieces:
ʒ      }           # keep a string
 æ    å            #   if its powerset contains ...
  …rkr             #   the string "rkr"
        ʒ       }  # filter on
         'b¡       #   split by the bishops
            1è     #   the substring between the bishops
              gÈ   #   has even length?

ε             }    # map over all valid configurations of blacks pieces
 'p8×              # create the row of 8 black pawns
     8D            # push two copies of 8
       )           # collect black's pieces, the pawns and both 8's into a list
        Â          # bifurcate: duplicate and reverse the copy
         u         # convert each string in the reversed to upper case
          «        # concatenate both lists
           '/ý     # join the rows by "/"

s                  # swap to the implicit input
 å                 # is it contained in the list of valid FENs?

05AB1E, 44 bytes

Fast version at the cost of byte, uses a lot of the same code, but only verifies the input without generating additional boards.

8£Ð{.•5h+…Í•Q×æ…rkrå×D'b¡1ègÈ×'p8×8D)Âu«'/ýQ

Try it online! or Try all cases!

8£               # take first 8 chars of the input (= black pieces)
  Ð              # push two copies of black pieces
   {        Q    # does the sorted string sort equal
    .•5h+…Í•     # the compressed string "bbknnqrr"?
             ×   # repeat black pieces this may times
æ…rkrå           # is the king between the rooks?
      ×D         # repeat black pieces that may times and push another copy
        'b¡1ègÈ  # are the bishops on opposite squares?
               × # repeat blacks pieces ...
'p8×8D)Âu«'/ý    # generate FEN from blacks pieces
             Q   # does this equal the input?
\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 95 bytes

Similar to my original version, but with a single regular expression.

Returns either a string (truthy) or null (falsy).

s=>s.match(s.slice(35).toLowerCase()+'.p{8}[/8]{9}P{8}(?=.*B(..)*B)(?=.*R.*K.*R)(?=.*N.*N).*Q')

Try it online!


JavaScript (ES6),  105 103  99 bytes

Returns a Boolean value.

s=>[/R.*K.*R/,/B(..)*B/,/N.*N/,/p{8}[/8]{9}P{8}.*Q/,s.slice(35).toLowerCase()].every(e=>s.match(e))

Try it online!

How?

As stated in the challenge, the input is guaranteed to be a valid FEN string. So once the pawn structure has been fully checked, we can safely assume that there are exactly two remaining rows that are properly formatted and just make sure that all other expected pieces are there.

We use 4 standard regular expressions:

/R.*K.*R/            ~> there's a white king surrounded by 2 white rooks
/B(..)*B/            ~> there are 2 white bishops with an even number of
                        squares in between
/N.*N/               ~> there are 2 white knights
/p{8}[/8]{9}P{8}.*Q/ ~> the pawn configuration is correct
                        and there's a white queen in the last row

Followed by this string:

s.slice(35).toLowerCase()

which is interpreted as another regex by match() and allows us to make sure that the first row is the last row in lower case.

\$\endgroup\$
1
  • \$\begingroup\$ This is nearing some of the other answers in length, nice job sticking it to esolangs! \$\endgroup\$ Commented Jun 7, 2021 at 14:16
3
\$\begingroup\$

Vyxal, 56 bytes

\//Dh⟨\p8*|\8|\8⟩JḂv⇧J≠⅛hDs«4cð↔Ṗ«≠⅛ƛ\b=;T∑₂⅛«ƈʁ«:„↔≠⅛¾a

Try it Online!

\//Dh⟨\p8*|\8|\8⟩JḂv⇧J≠⅛ # Part 1 - is the board a mirror?
\//                      # Split on slashes
   D                     # 3 copies
    h                    # the first (black pieces)
     ⟨\p8*|\8|\8⟩J       # Prepended to eight pawns and two empty ranks
                  Ḃ      # Duplicate and get reverse
                   v⇧    # Uppercase all pieces in the revers
                     J   # Joined
                      ≠  # Is not equal to original?  
                       ⅛ # Push to global array
hDs«4cð↔Ṗ«≠⅛ # Part 2 - are all the pieces here?
h            # First element
 D           # Tripled for future use
  s          # Sorted
          ≠  # Is not equal to
   «4cð↔Ṗ«   # Compressed string `bbknnqrr`?
           ⅛ # Push to global array
ƛ\b=;T∑₂⅛ # Part 3 - are the bishops on opposite color squares?
ƛ   ;     # Map to
 \b=      # Is a b?
     T∑   # Sum of truthy indices
       ₂  # Is even?
        ⅛ # Push to global array
«ƈʁ«:„↔≠⅛ # Part 4 - is the king between the rooks?
«ƈʁ«      # Compressed `rkr`
    :„    # Duplicate and put on bottom of stack
      ↔   # Remove characters that aren't `rkr`
       ≠  # Doesn't equal rkr?
        ⅛ # Push to global array
¾a # Part 5 - is everything in global array falsy?
¾  # Global array
 a # are any truthy?

What. A. Mess. Return 0 for valid and 1 for not.

-1 thanks to @cairdcoinheringaahing.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 190 bytes

lambda i:all([match('^[bknqr]{8}p{8}(8){4}P{8}[BKNQR]{8}$',''.join(i)),len({sub('[^rk]','',x.lower())for x in i[::7]})==1,len({sub('[^b]','.',x.lower())for x in i[::7]})==1])
from re import*

Try it online!

takes a list of each row in board

\$\endgroup\$
1
  • \$\begingroup\$ Can shorten it to lambda i:match(...)and len(...)==len(...)==1, or lambda i:(match(...)or 1)==len(...)==len(...)==1 if it must return an actual boolean (i.e. not None). \$\endgroup\$
    – Alex Hall
    Commented Jun 6, 2021 at 20:48
2
\$\begingroup\$

Jelly,  49 47 bytes

-2 thanks to Nick kennedy (form valid strings in reverse and use mould for the pawns.)

”Pṁṭ⁾88⁸ṭṚŒl;Ɗj”/
“RNBQK”ṁ8Œ!ẹ”BSḂƊƇf⁾RKŒḂ$ƇÇ€ċ

A monadic Link that accepts a valid FEN string as a list of characters and yields 8 (truthy) if the FEN string is a valid Fischer random chess starting position or 0 (falsey) if not.

Try it online!
Or see the test-suite (to make it quicker valid boards are only built once, thus ċ moved to the footer)

How?

”Pṁṭ⁾88⁸ṭṚŒl;Ɗj”/ - Link 1, get board: S, valid eighth rank
”Pṁ               - 'P' moulded like S      -> "PPPPPPPP"
   ṭ⁾88           - (that) tacked to ("88") -> ['8', '8', "PPPPPPPP"]
       ⁸ṭ         - (S) tacked to (that)    -> ['8', '8', "PPPPPPPP", S] = white's side
             Ɗ    - last three links as a monad - f(white's side):
         Ṛ        -   reverse
          Œl      -   to lower-case -> black's side
            ;     -   (black's side) concatenate (white's side)
              j”/ - join with '/'s

“RNBQK”ṁ8Œ!ẹ”BSḂƊƇf⁾RKŒḂ$ƇÇ€ċ - Main Link: FEN string
“RNBQK”ṁ8                     - "RNBQK" moulded like [1..8] -> "RNBQKRNB"
         Œ!                   - all permutations
                 Ƈ            - filter keep those for which:
                Ɗ             -   last three links as a monad:
           ẹ”B                -     indices of 'B'
              S               -     sum
               Ḃ              -     least significant bit (i.e. is odd?)
                         Ƈ    - filter keep those for which:
                        $     -   last two links as a monad:
                  f⁾RK        -     filter-keep if in "RK"
                      ŒḂ      -     is it a palindrome?
                          ǀ  - call Link 1 for each
                            ċ - count occurrences (of S)
\$\endgroup\$
2
  • 1
    \$\begingroup\$ @NickKennedy mould - very nice. I did consider building in reverse but I must've done something wrong with tack. Thanks for the saves :) \$\endgroup\$ Commented Jun 7, 2021 at 16:11
  • 1
    \$\begingroup\$ @NickKennedy Not at all - all improvements are welcome, however minor. \$\endgroup\$ Commented Jun 7, 2021 at 17:38
0
\$\begingroup\$

Charcoal, 54 bytes

¿⁼θ⪫⟦…θ⁸×p⁸8⁸8⁸×P⁸↥…θ⁸⟧/¿⁼rkrΦθ№krι¿⬤qbn›⊗№θι⊕κ﹪Σ⌕Aθb²

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for valid, nothing if not. Explanation:

¿⁼θ⪫⟦…θ⁸×p⁸8⁸8⁸×P⁸↥…θ⁸⟧/

Take the first 8 characters of the input, then a string of 8 ps, then 8 four times (mixing numeric and string to save bytes), then a string of 8 Ps, then the first 8 characters of the input in upper case, join the whole lot together with /s, and check that this results in the original input.

¿⁼rkrΦθ№krι

Check that removing all characters other than k and r from the input results in the string rkr.

¿⬤qbn›⊗№θι⊕κ

Check that the input contains q at least once and b and n at least twice. (Given the other checks, this actually limits them to once and twice anyway.)

﹪Σ⌕Aθb²

Check that the bs are an odd distance apart.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.