feat: add validateFEN

This commit is contained in:
Cozma Rares
2023-04-04 23:57:26 +03:00
parent b0eb98901a
commit a5c27883f7
+127 -1
View File
@@ -10,6 +10,15 @@ export const PIECE = Object.freeze({
KING: "k"
} as const);
const PIECE_SYMBOLS = Object.freeze([
PIECE.PAWN,
PIECE.KNIGHT,
PIECE.BISHOP,
PIECE.ROOK,
PIECE.QUEEN,
PIECE.KING
] as string[]);
export type PiecePromotionType =
| typeof PIECE.KNIGHT
| typeof PIECE.BISHOP
@@ -127,7 +136,124 @@ export function swapColor(color: Color): Color {
return color === COLOR.WHITE ? COLOR.BLACK : COLOR.WHITE;
}
export function validateFEN(fen: string) {}
export function validateFEN(fen: string): { ok: boolean; error?: string } {
const fields = fen.split(" ");
if (fields.length != 6)
return {
ok: false,
error: "FEN string must contain 6 space delimited fields"
};
const validatePosition = (position: string) => {
const rows = position.split("/");
if (rows.length != 8)
throw new Error(
"Invalid FEN: board position must contain 8 rows delimited by '/'"
);
const kings = [
{ regex: /K/g, color: "white" },
{ regex: /k/g, color: "black" }
];
for (const king of kings) {
const matches = position.match(king.regex) ?? [];
if (matches.length == 0)
throw new Error(
`Invalid FEN: board position is missing ${king.color} king`
);
if (matches.length > 1)
throw new Error(
`Invalid FEN: board position contains too many ${king.color} kings`
);
}
rows.forEach(row => {
let numSquares = 0;
let previousWasNumber = false;
[...row].forEach(symbol => {
if (isDigit(symbol)) {
if (previousWasNumber)
throw new Error(
"Invalid FEN: board position contains consecutive digits"
);
numSquares += parseInt(symbol);
previousWasNumber = true;
return;
}
if (PIECE_SYMBOLS.includes(symbol) == false)
throw new Error(
"Invalid FEN: board position contains an invalid piece symbol: " +
symbol
);
numSquares++;
previousWasNumber = false;
});
if (numSquares != 8)
throw new Error(
"Invalid FEN: board position contains a row that does not have 8 squares"
);
});
};
const validateTurn = (turn: string) => {
if (/^(w|b)$/.test(turn) == false)
throw new Error("Invalid FEN: invalid side to move");
};
const validateCastling = (castling: string) => {
if (/[^kKqQ-]/.test(castling))
throw new Error("Invalid FEN: string contains invalid castling rights");
};
const validateEnPassant = (enPassant: string, turn: string) => {
if (!/^(-|[abcdefgh][36])$/.test(enPassant))
throw new Error("Invalid FEN: invalid en-passant square");
if (turn == "w" && enPassant[1] == "3")
throw new Error("Invalid FEN: invalid en-passant square");
if (turn == "b" && enPassant[1] == "6")
throw new Error("Invalid FEN: invalid en-passant square");
};
const validateHalfMoves = (halfMoves: string) => {
if (/^\d+$/.test(halfMoves) == false)
throw new Error(
"Invalid FEN: move number must be a non-negative integer"
);
};
const validateFullMoves = (fullMoves: string) => {
if (/^[1-9]\d+$/.test(fullMoves) == false)
throw new Error(
"Invalid FEN: number of full moves must be a positive integer"
);
};
try {
validateTurn(fields[1]);
validateCastling(fields[2]);
validateEnPassant(fields[3], fields[1]);
validateHalfMoves(fields[4]);
validateFullMoves(fields[5]);
validatePosition(fields[0]);
} catch (e) {
return { ok: false, error: e as string };
}
return { ok: true };
}
console.log(validateFEN(""));
export class Chess {
private _board: (Piece | null)[] = [];