feat: add validateFEN
This commit is contained in:
+127
-1
@@ -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)[] = [];
|
||||
|
||||
Reference in New Issue
Block a user