Fischer-random position generation

A classic code-golf problem (especially for chess-lovers) concerning the generation of one of 960 possible starting positions in the Fischer-random chess variant.
May 15, 2018 - 23:23:36

The goal of this code-golf problem is to create a working Fischer-random chess starting position generator. What is Fischer-random chess exactly?

Chess960 (or Fischer Random Chess) is a variant of chess invented and advocated by former World Chess Champion Bobby Fischer, publicly announced on June 19, 1996 in Buenos Aires, Argentina. It employs the same board and pieces as standard chess; however, the starting position of the pieces on the players' home ranks is randomized.

Only very basic chess knowledge is required for this problem.

We will only be considering one side of the board, and only the first rank -- that is, the row that contains all of the important pieces rather than the pawns. In lowercase standard algebraic notation for a standard game of chess this would be represented as rnbkqbnr, where:

Notation Meaning
k King
q Queen
r Rook
b Bishop
n Knight

The only requirements of the problem are:

Example outputs:

rkrbnnbq
rbnqknbr
rbbkrnnq

There are 960 different possible arrangements for the starting position of one side.

Solution

I did this problem in Ruby and managed to get my solution down to 133 bytes, see if you can beat it:

def f;a='rrbbnnkq';loop{return a if/.*r.*k.*r/=~a&&(0...a.size).find_all{|i|a[i,1]==?b}.inject(:+).odd?;a=a.chars.shuffle*''};end;p f

# INSTRUCTIONS
# Run the program from command line with `ruby file_name.rb`

I tried an alternative solution based on representing the position as an array rather than a string but this added two more bytes, making it a 135 byte solution. Nevertheless, it was an interesting approach:

def f;a=%w(r r b b n n k q);loop{return a*''if a.size.times.select{|i|a[i]==?b}.inject(:+).odd?&&/.*r.*k.*r/=~a*'';a=a.shuffle};end;p f

# INSTRUCTIONS
# Run the program from command line with `ruby file_name.rb`

Testing

To test whether your solution actually gives correct results, you'll want to do something along the lines of:

def fischer
  # Your method
  return String.new
end

positions = []
100_000.times do
  positions << fischer
end

# INSTRUCTIONS
# This is how I've done it, but you can do it your own way:
# - Create an empty array
# - Use a loop to call the fischer-random generation method a large number of times (100,000+)
# - Add the result to the array
# - Find the number of unique elements in the array, it should be 960.

p positions.uniq.length
#=> 960