[ngnchess] How to validate a FEN string

Forsyth-Edwards Notation (FEN) is a standard system used to represent a chess position in a single line of text. This notation is widely used in chess engines, databases, and software applications to save and share positions. A FEN string fully describes the current state of a game, allowing it to be reconstructed at any time.

Structure of the FEN String

A FEN string consists of six sections, each separated by a space, detailing different aspects of the chess position.

string[] parts = fen.Split(' ');
if (parts.Length != 6)
    return false;

The first section represents the placement of pieces on the board. It starts from the 8th rank (the topmost rank from White’s perspective) and moves downward to the 1st rank. Pieces are denoted by letters, with uppercase characters for White's pieces (K for king, Q for queen, R for rook, B for bishop, N for knight, and P for pawn) and lowercase characters for Black’s pieces (k, q, r, b, n, p). Empty squares are represented by numbers, indicating the count of consecutive empty squares. Each rank is separated by a forward slash (/). For example, the notation rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR corresponds to the standard starting position in chess, where White's and Black’s pieces are arranged symmetrically.

 // Board size validation
 string board = parts[0];
 string[] rows = board.Split('/');
 if (rows.Length != 8)
     return false;

 // Line validation
 Regex rowRegex = new Regex(@"^[rnbqkpRNBQKP1-8]+$");
 foreach (string row in rows) {
     if (!rowRegex.IsMatch(row))
         return false;

     // Square count validation
     int squareCount = 0;
     foreach (char c in row) {
         if (char.IsDigit(c))
             squareCount += (int)char.GetNumericValue(c);
         else
             squareCount++;
     }
     if (squareCount != 8)
         return false;
 }

The second section specifies which side is to move next. This is denoted by a single character: "w" if it is White’s turn to move, or "b" if it is Black’s turn. For instance, if this section contains "w", it means White has the next move.

// Active turn validation
Regex activeRegex = new Regex("^(w|b)$");
if (!activeRegex.IsMatch(parts[1]))
    return false;

The third section provides information about castling rights. If castling is still possible, specific letters indicate which castling options remain available: "K" represents White’s kingside castling, "Q" represents White’s queenside castling, "k" represents Black’s kingside castling, and "q" represents Black’s queenside castling. If no castling rights remain for either player, this section contains a hyphen ("-"). A notation such as "KQkq" means that both White and Black still have all their castling rights intact.

// Castling validation
string castling = parts[2];
if (castling != "-") {
    Regex castlingRegex = new Regex(@"^(?:(?!.*(.).*\1)
[KQkq]{1,4})$");
    if (!castlingRegex.IsMatch(castling))
        return false;
}

The fourth section records en passant opportunities. If an en passant capture is available, this section contains the file (column) where such a capture can occur, such as "e3" or "d6", indicating the square where a pawn may be captured en passant. If no en passant capture is possible, this section simply contains a hyphen ("-"). For example, if a Black pawn has just moved two squares forward from e7 to e5, and White has the opportunity to capture it en passant, this section would display "e6".

// En passant validation
Regex enPassantRegex = new Regex(@"^(-|[a-h][36])$");
if (!enPassantRegex.IsMatch(parts[3]))
    return false;

if (parts[3] != "-") {
    char rank = parts[3][1];
    if (parts[1] == "w" && rank != '6')
        return false;
    if (parts[1] == "b" && rank != '3')
        return false;
} 

The fifth section keeps track of the halfmove clock, which is used for the fifty-move rule. This rule states that if fifty consecutive moves occur without a pawn move or a capture, a draw can be claimed. This section contains a number representing the count of half-moves (a half-move being a single turn by either White or Black) since the last capture or pawn move. If this number is "0", it means a capture or pawn move has just been made.

// Halfmove clock validation
Regex halfmoveRegex = new Regex(@"^\d+$");
if (!halfmoveRegex.IsMatch(parts[4]))
    return false;

The final section records the fullmove number, which counts the total number of moves in the game. This count starts at "1" and increases by one after every move made by Black. If this number is "1", it means the game is in its first move.

// Fullmove clock validation
Regex fullmoveRegex = new Regex(@"^[1-9]\d*$");
if (!fullmoveRegex.IsMatch(parts[5]))
    return false;

The full codebase of ngnchess is available on GitHub


You'll only receive email when they publish something new.

More from GSLF
All posts