rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
Each string in between the slashes represents a rank in the chessboard, starting from the 8th rank. Lower case is black, upper case is white. Numbers represents empty squares between pieces. For example '4P3' represents four empty squares, followed by a pawn, followed by three more empty squares, totaling eight. The '/8/' therefore means (you've guessed it!) a complete empty rank.
The remaining string 'b KQkq e3 0 1' represents the side to move, the castling rights (e.g. 'K' means white can caste king-side, 'q' that black can caste queen-side, etc.), en-passant square and the move counters. The en-passant square is the square directly behind the pawn that made the two-square move. In this case, white move e4, which means that e3 is the en-passant square. Black can capture the pawn if he had a pawn on either d4 or f4. Regardless, the en-passant square is always indicated, whether it can be taken or not. The move counts are the half-moves since a last capture or pawn move (for the 50-move draw rule), followed by the number of full moves.
I found myself constantly checking the validity of the FEN string during the parsing stage, which started to look really ugly. So I turned to one of my best friends... regular expressions!
Regular expressions can get tricky...quickly, but is incredibly powerful to recognise patterns in strings. Here is a short extract from Vicki that shows how a FEN string can be checked:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Returns true if the rank contains 8 elements (that is, a combination of | |
// pieces and empty spaces). Assumes string contains valid chess pieces and | |
// the digits 1..8. | |
private static boolean verifyRank(String rank) { | |
int count = 0; | |
for (int i = 0; i < rank.length(); i++) { | |
if (rank.charAt(i) >= '1' && rank.charAt(i) <= '8') { | |
count += (rank.charAt(i) - '0'); | |
} else { | |
count++; | |
} | |
} | |
return count == 8; | |
} | |
/** | |
* Returns true if a FEN string is valid. | |
* | |
* @param fen | |
* @return | |
*/ | |
public static boolean isValidFen(String fen) { | |
Pattern pattern = Pattern.compile("((([prnbqkPRNBQK12345678]*/){7})([prnbqkPRNBQK12345678]*)) (w|b) ((K?Q?k?q?)|\\-) (([abcdefgh][36])|\\-) (\\d*) (\\d*)"); | |
Matcher matcher = pattern.matcher(fen); | |
if (!matcher.matches()) { | |
LOGGER.debug("Invalid FEN, not following specified format."); | |
return false; | |
} | |
// Check each rank. | |
String[] ranks = matcher.group(2).split("/"); | |
for (String rank : ranks) { | |
if (!verifyRank(rank)) { | |
LOGGER.debug("Invalid FEN, rank '{}' does not add up to 8.", rank); | |
return false; | |
} | |
} | |
if (!verifyRank(matcher.group(4))) { | |
LOGGER.debug("Invalid FEN, rank '{}' does not add up to 8.", matcher.group(3)); | |
return false; | |
} | |
// Check two kings. | |
if (!matcher.group(1).contains("k") || !matcher.group(1).contains("K")) { | |
LOGGER.debug("Missing one or both kings."); | |
return false; | |
} | |
return true; | |
} |
The 'verifyRank()' method simply verifies that the a rank adds up to eight. Doing that in a regular expression may get very hairy (actually I don't think it can be done). The code also verifies that there are 2 kings at least. Of course, that can easily be done by the regular expression, but the string will get rather long.