Programming Chess960 for The 3Robot Chess Computer
Introduction
I recently started playing Chess960, and found it very enjoyable. I had long thought about adding the Chess960 variant to 3Robot's on-board chess engine. Finally, I bit the bullet and had a go.
For more about my 3Robot chess computer with robotic arm, check out these links.
• The 3Robot - An Update with Arduino Giga and Stockfish

What is Chess960?
Chess960 (also known as Fischer Random or Freestyle) is a chess variant where the pieces along the back ranks are randomly mixed up. It was proposed by Bobby Fischer in 1996, and is by far the most popular variant of "shuffle" chess, first mentioned some two or three hundred years ago. By randomizing the pieces, the player has to think right from the start, and can't rely on memory of openings. It's perfect for those who like the challenge of chess but without the theory or the study. Some even believe it's the future of chess.
The Chess960 rules for shuffling the back rank are that the king sits between the rooks, and the bishops are on opposite colour squares. Other than that, the pieces can be anywhere. As such, the kings cannot sit in the corners. Both back ranks must mirror each other, such that kings, queens, etc. all sit facing each other on the same files. The pawns remain on the second ranks. The rules of castling are very similar to standard chess but with a twist, namely, the king and castling rook are permitted to obstruct each other.
There are a total of 960 possible start positions, of which standard chess is one of them (position 518). Another familiar position is 534, where kings and queens are swapped. These two positions are excluded in tournaments. Here's start position 777.

Interestingly, there is a variant of Chess960 called Double Fischer Random (or asymmetrical Chess960), where the back ranks do not have to mirror each other.
As White can have a significant advantage in Chess960, it's often proposed that the same starting position be played twice, with players taking turns with White.
The terms short and long castling, and king-side and queen-side castling, lose their meaning in Chess960. Instead they are referred to as "a-side" or "h-side" castling, but keep the familiar "0-0-0" and "0-0" notation respectively.
The 3Robot chess engine
The on-board chess engine inside the 3Robot is one I downloaded from the web, and altered substantially to work alongside 3Robot's motorised arm and tactile chess board. While I certainly don't understand completely how the engine works, I have become familiar enough with it to make changes. So after some thought (always advisable before coding) I concluded that to make the engine play Chess960 would require these tasks.
• add a list of all 960 starting positions
• set up a game with one of those starting positions and see how the engine plays
• amend the user interface to accommodate the new variant
• implement castling.
The 3Robot Plays Freestyle
A list of all 960 randomised starting positions can be found on the internet. Here are the first few positions.
chess960Pos[0] = "BBQNNRKR";
chess960Pos[1] = "BQNBNRKR";
chess960Pos[2] = "BQNNRBKR";
chess960Pos[3] = "BQNNRKRB";
chess960Pos[4] = "QBBNNRKR";
If you're running your chess engine on a small microcontroller board with limited RAM, then giving up around 8,000 bytes to store the list may not be possible. Instead, starting positions can be determined by code, as in this Python example.
import random
def getRandomSquare() -> int:
r = random.randint(0,7)
while backRank[r] != '': r = random.randint(0,7)
return r
backRank = ['','','','','','','',''] # 0..7
# put K (but not in corners)
kingStartPos = random.randint(1,6)
backRank[kingStartPos] = 'k'
# put a-side R
rookStartPosASide = random.randint(0,kingStartPos-1)
backRank[rookStartPosASide] = 'r'
# put h-side R
rookStartPosHSide = random.randint(kingStartPos+1,7)
backRank[rookStartPosHSide] = 'r'
# put first B
r = getRandomSquare()
backRank[r] = 'b'
colourFirstB = r % 2; # 0 or 1 which signifies light or dark square B
# put second B (but on a different colour square)
r = random.randint(0,7)
while (backRank[r] != '') or ((r % 2) == colourFirstB): r = random.randint(0,7)
backRank[r] = 'b'
# put first N
backRank[getRandomSquare()] = 'n'
# put second N
backRank[getRandomSquare()] = 'n'
# put Q
backRank[getRandomSquare()] = 'q'
# all done
print(backRank)
Here, we don't know the actual position number. It's nice to know the position number, as it helps with importing the game into an online engine for analysis. But as long as you provide the FEN of the starting position, you can import it. Or you can look up the position number.
I decided to add the entire list to the chess engine, as there's plenty of memory on the Arduino Giga microcontroller in the 3Robot, and I like to have the position number available.
The variables holding the starting squares of the king and rooks play an important role in the castling code, as discussed later.
Once a starting position is chosen, it's displayed on the LCD screen for the user to set up the board. The user can press Go to accept, or any other key to show another position.

Not surprisingly, the 3Robot engine played Chess960 without any problems, as the rules are the same as standard chess, except for castling.
Chess960's quirky castling
If there's one thing that put me off for a long time from adding Chess960 to 3Robot, it's the castling. These rules, though mostly familiar, can result in some mind-bending castling scenarios, and I had my doubts how easy it would be to crowbar them into the chess engine code.
Here's now Chess960 castling works. As in standard chess, h-side castling moves the king and rook at the same time, such they end up on the g and f files respectively, and on the c and d files for a-side castling. The king cannot castle out of check, across check or finish in check. Castling rights are lost when king and rooks move. There mustn't be any pieces in the way of the king reaching its final square, or the rook reaching its final square. But here's the twist... the king and castling rook are allowed to get in each other's way! This can leads to some funky castlings, as the following h-side examples demonstrate.
abcdefgh comment
xK.....R not unlike standard castling, and the K gets to move five squares in one go
xKR....x R blocks the K's path to the g square, but is permitted
xxxK..Rx R sits on the K's final square, again it's legal
xxxxxKRx K and R sit on each other's final squares! Castling simply swaps them over
xxxxxK.R moving the K to the g square is ambiguous... is the K castling or just moving one square?
xxxxx.KR K sits on its own final square, and so only the R moves on castling
_____RK_ final castled position, same as in standard chess
x = maybe empty or not
. = must be empty
Note that the king can only approach the final square from one direction. In contrast, the king can approach the final c square from both directions in a-side castling. Here are some a-side examples.
abcdefgh comment
R.....Kx not unlike standard castling, and the K gets to move four squares in one go
xx...RKx R blocks the K's path to the c square, but castling is legal
xR.Kxxxx moving the K to the c square is ambiguous... is the K castling or just moving one square?
xxRKxxxx K and R sit on each other's final squares! Castling simply swaps them over
R.K.xxxx K sits on its own final square, and so only the R moves on castling
xRK.xxxx ditto
RK..xxxx K can approach its final square from either direction, unlike h-side castling
__KR____ final castled position, same as in standard chess
As you can see, castling in Chess960 is pretty insane. But I do like this extra element in the game!
I want to castle... but how?
On physical chess computers, the usual way to castle is to press the king and move it two squares to the left or right. But the examples above show this won't work. The king's initial position may be on the g square, in which case it's already on its final square... so to castle you press the king and press it again without moving it, but this usually indicates you've changed your mind! Or the king may be on the f square, and you move it to the g square... but are you castling or just moving one square to the right?
The only practical way, it seems, to signal castling is to press the king and then the rook, which looks like the king is capturing its own rook. This is the same as dragging the king onto the rook when playing Chess960 online.
Hard coding vs Soft coding
When you write a computer program to play chess, it's normal to make some assumptions, and hard code accordingly. Kings always start on the e file. Rooks are always in the corners.
Looking through the 3Robot's chess engine code, there's lots of hard coding and constants used. So, a first step is to generalise the castling process, and remove all assumptions by using soft coding. Constants are replaced by variables that store the initial position of kings and rooks.
Once the code is generalised to Chess960's castling rules, then the standard game's castling will work automatically, as standard chess is just one starting position in the Chess960 universe. Also, I wanted to avoid forking the castling code, i.e.
if (STANDARD_CHESS)
do this
else if (CHESS960)
do that
which I think is a clumsy way to implement it.
Generalising the code
Here's some C code from the engine, which updates the board when White castles short in standard chess.
board[60] = 0; // e1
board[61] = wr; // f1
board[62] = wk; // g1
board[63] = 0; // h1
The array board[0..63] is an array of the board, with board[0] being the a8 square and board[63] the h1 square.
To accommodate Chess960 rules, soft coding gives:
board[whiteKstartPos] = 0;
board[61] = wr;
board[62] = wk;
board[whiteRStartPos_HSide] = 0;
Here whiteKstartPos = 60 and whiteRStartPos_HSide = 63 for the standard game, and are set to whatever their positions are in Chess960. Similar variables are used for the other king and rooks.
The next step is to add code to ensure the king and rook's paths to their final squares f1 and g1 are clear, but allowing for each other to get in the way. Here's some code for White's h-side castling.
isClear = true;
// check K's path to g1 is clear (allowing for R)
// only loops if K is to the left of g1
for (int i = white_K_StartPos + 1; i<=62; i++) // 62 is g1
if ((board[i] != 0) && (i != whiteRStartPos_HSide))
{
isClear = false;
break;
}
// check R's path to f1 is clear (allowing for K)
// only loops if R is to the right of f1
for (int i = whiteRStartPos_HSide - 1; i>=61; i--) // 61 is f1
if ((board[i] != 0) && (board[i] != wk))
{
isClear = false;
break;
}
Together these two loops ensure there are no illegal pieces obstructing castling. Allowing the king and rook to get in the way is catered for by the two boolean expression (i != whiteRStartPos_HSide) and (board[i] != wk).
In fact, the king loop does most of the checking, and the rook loop is only strictly needed if the king is on g1 and the rook h1 (when the king is on g1, the king loop doesn't run, and the rook loop checks f1 is clear).
Note the need to check for the presence of a rook using (i != whiteRStartPos_HSide), and not (board[i] != wr). This is because the non-castling rook can get in the way, and if it just checks for a rook, then an illegal castling move may be allowed.
The code then needs to ensure the king is not castling through check.
if (isClear)
{
isCheck = false;
for (int i = white_K_StartPos; i<63; i++)
{
setUpBoardWithKingOnSquare(i); // put K on square i
if (isWhiteKingInCheck())
{
isCheck = true;
break;
}
}
restoreBoard(); // put K back on original square
if (!isCheck) addWhiteCastlingHSideMoveToLegalMoves();
}
If the king doesn't move through check, the castling move is added to the list of legal moves. This list is used to verify the user's move, and to generate the computer's move, so it kills two birds with one stone.
White's a-side castling code follows the same pattern, and the whole lot can be cloned for Black's castling.
Once done, the standard game's castling works automatically. In fact, there's no flag in the engine saying it's playing a standard or Chess960 game... only the initial setup of the board distinguishes the two variants.
Changes in the user interface
The major one, as discussed, is how to tell the 3Robot you want to castle. So, no more moving the king two squares to the side, just press the king and the rook. This takes a bit of getting used to! Other minor changes involved display issues, such as displaying "0-0", rather than Ke1xRh1.
Changes to the robot arm
Some of the castling situations present a problem for the robot arm, as programmed for standard chess. The examples where the king and rook sit on each other's final squares before castling now require a new special move, where the arm moves the king to a temporary place (the king's square in the car park comes in handy here), then the rook, and finally the king back to its final square. Other examples are where the king or rook already sit on their final squares before castling, in which case the arm ignores that part of the move.
My First Game
Here's my first full Chess960 game with 3Robot with all the coding done. I got off to a bad start but slowly got back into the game. I've only played Chess960 a handful of times, but I like how you really have to expect the unexpected right from the start.
Conclusion
Adding the Chess960 variant to 3Robot's on-board engine took a few days, and most of that time was spent understanding how Chess960 castling works, and how the engine handled castling in the standard game, and then working out how to generalise that code to accommodate the new castling rules.
The easy way would've been to use Stockfish's Chess960 engine, which 3Robot can connect to, but where's the fun and challenge in that? And besides, I wanted the Chess960 variant available in the on-board engine.
Happy chessing! ![]()