protected virtual GameCreationData FenStringToGameCreationData(string fen)
{
Dictionary<char, Piece> fenMappings = FenMappings;
string[] parts = fen.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (!AllowedFenPartsLength.Contains(parts.Length)) throw new ArgumentException("The FEN string has too much, or too few, parts.");
Piece[][] board = new Piece[8][];
string[] rows = parts[0].Split('/');
if (rows.Length != 8) throw new ArgumentException("The board in the FEN string does not have 8 rows.");
GameCreationData data = new GameCreationData();
for (int i = 0; i < 8; i++)
{
string row = rows[i];
Piece[] currentRow = new Piece[8] { null, null, null, null, null, null, null, null };
int j = 0;
foreach (char c in row)
{
if (char.IsDigit(c))
{
j += (int)char.GetNumericValue(c);
continue;
}
if (!fenMappings.ContainsKey(c)) throw new ArgumentException("The FEN string contains an unknown piece.");
currentRow[j] = fenMappings[c];
j++;
}
if (j != 8)
{
throw new ArgumentException("Not enough pieces provided for a row in the FEN string.");
}
board[i] = currentRow;
}
data.Board = board;
if (parts[1] == "w")
{
data.WhoseTurn = Player.White;
}
else if (parts[1] == "b")
{
data.WhoseTurn = Player.Black;
}
else
{
throw new ArgumentException("Expected `w` or `b` for the active player in the FEN string.");
}
if (parts[2].Contains('K')) data.CanWhiteCastleKingSide = true;
else data.CanWhiteCastleKingSide = false;
if (parts[2].Contains('Q')) data.CanWhiteCastleQueenSide = true;
else data.CanWhiteCastleQueenSide = false;
if (parts[2].Contains('k')) data.CanBlackCastleKingSide = true;
else data.CanBlackCastleKingSide = false;
if (parts[2].Contains('q')) data.CanBlackCastleQueenSide = true;
else data.CanBlackCastleQueenSide = false;
if (parts[3] == "-") data.EnPassant = null;
else
{
Position ep = new Position(parts[3]);
if ((data.WhoseTurn == Player.White && (ep.Rank != 6 || !(data.Board[3][(int)ep.File] is Pawn))) ||
(data.WhoseTurn == Player.Black && (ep.Rank != 3 || !(data.Board[4][(int)ep.File] is Pawn))))
{
throw new ArgumentException("Invalid en passant field in FEN.");
}
data.EnPassant = ep;
}
int halfmoveClock;
if (int.TryParse(parts[4], out halfmoveClock))
{
data.HalfMoveClock = halfmoveClock;
}
else
{
throw new ArgumentException("Halfmove clock in FEN is invalid.");
}
int fullMoveNumber;
if (int.TryParse(parts[5], out fullMoveNumber))
{
data.FullMoveNumber = fullMoveNumber;
}
else
{
throw new ArgumentException("Fullmove number in FEN is invalid.");
}
return data;
}