Complete Forsyth-Edwards Notation support for position serialization and validation. FEN (Forsyth-Edwards Notation) is a standard notation for describing chess positions, allowing positions to be stored, shared, and recreated accurately.
Validates FEN strings according to the official FEN specification.
/**
* Validate a FEN string
* @param fen - FEN string to validate
* @returns Validation result with success status and error details
*/
function validateFen(fen: string): FenValidationResult;
interface FenValidationResult {
/** True if FEN is valid, false otherwise */
ok: boolean;
/** Error description if validation failed */
error?: string;
}Usage Examples:
import { validateFen } from "chess.js";
// Valid starting position
const result1 = validateFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
console.log(result1); // { ok: true }
// Valid mid-game position
const result2 = validateFen('r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3');
console.log(result2); // { ok: true }
// Invalid FEN - missing king
const result3 = validateFen('rnbq1bnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
console.log(result3);
// { ok: false, error: 'Invalid FEN: missing black king' }
// Invalid FEN - wrong number of fields
const result4 = validateFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq');
console.log(result4);
// { ok: false, error: 'Invalid FEN: must contain six space-delimited fields' }
// Use for input validation
function loadPosition(fenString: string) {
const validation = validateFen(fenString);
if (!validation.ok) {
throw new Error(`Invalid position: ${validation.error}`);
}
return new Chess(fenString);
}The Chess class automatically generates FEN strings from the current position.
class Chess {
/**
* Get FEN string for current position
* @param options - FEN generation options
* @returns FEN string representing current position
*/
fen(options?: FenOptions): string;
}
interface FenOptions {
/** Always include en passant square even if no legal capture exists */
forceEnpassantSquare?: boolean;
}Usage Examples:
import { Chess } from "chess.js";
const chess = new Chess();
// Starting position FEN
console.log(chess.fen());
// 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
// After some moves
chess.move('e4');
chess.move('e5');
chess.move('Nf3');
console.log(chess.fen());
// 'rnbqkbnr/pppp1ppp/8/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2'
// Force en passant square display
chess.move('d5');
chess.move('d4');
chess.move('c5');
chess.move('dxc6'); // En passant capture available
console.log(chess.fen({ forceEnpassantSquare: true }));
// Includes en passant square even if no legal captureLoad positions from FEN strings with comprehensive validation and error handling.
class Chess {
/**
* Load position from FEN string
* @param fen - FEN string to load
* @param options - Loading options
* @throws Error if FEN is invalid and validation is enabled
*/
load(fen: string, options?: FenLoadOptions): void;
/**
* Constructor with FEN loading
* @param fen - Initial FEN position
* @param options - Constructor options
*/
constructor(fen?: string, options?: ConstructorOptions);
}
interface FenLoadOptions {
/** Skip FEN validation (dangerous) */
skipValidation?: boolean;
/** Preserve existing PGN headers */
preserveHeaders?: boolean;
}
interface ConstructorOptions {
/** Skip FEN validation during construction */
skipValidation?: boolean;
}Usage Examples:
const chess = new Chess();
// Load valid position
chess.load('r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3');
// Error handling for invalid FEN
try {
chess.load('invalid-fen-string');
} catch (error) {
console.error('Failed to load position:', error.message);
}
// Skip validation (use with caution)
chess.load('potentially-invalid-fen', { skipValidation: true });
// Load via constructor
const chess2 = new Chess('r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3');
// Preserve headers when loading new position
chess.setHeader('Event', 'World Championship');
chess.load('8/8/8/8/8/8/8/8 w - - 0 1', { preserveHeaders: true });
console.log(chess.getHeaders()); // Headers preservedFEN strings consist of six space-separated fields:
Describes piece positions rank by rank, from rank 8 to rank 1:
r, n, b, q, k, p = black piecesR, N, B, Q, K, P = white pieces1-8 = number of empty squares/ = rank separatorExample: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
w = white to moveb = black to moveK = white kingside castling availableQ = white queenside castling availablek = black kingside castling availableq = black queenside castling available- = no castling rights availableExample: KQkq (all castling rights), Kq (white kingside, black queenside), - (none)
e3 after e2-e4)- if no en passant capture possibleNumber of halfmoves since last pawn move or capture (for 50-move rule)
Number of complete moves in the game (increments after black's move)
Complete Example:
rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e6 0 2// Starting position
const START_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
// Empty board
const EMPTY_FEN = '8/8/8/8/8/8/8/8 w - - 0 1';
// King vs King (insufficient material)
const KVK_FEN = '4k3/8/8/8/8/8/8/4K3 w - - 0 1';
// Famous positions
const SCHOLAR_MATE_FEN = 'rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3';
const STALEMATE_FEN = '4k3/4P3/4K3/8/8/8/8/8 b - - 0 78';
// Test positions
const PERFT_POSITION = 'r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1';Common FEN validation errors and their meanings:
// Examples of validation errors
const errors = [
'Invalid FEN: must contain six space-delimited fields',
'Invalid FEN: move number must be a positive integer',
'Invalid FEN: half move counter number must be a non-negative integer',
'Invalid FEN: en-passant square is invalid',
'Invalid FEN: castling availability is invalid',
'Invalid FEN: side-to-move is invalid',
'Invalid FEN: piece data does not contain 8 \'/\'-delimited rows',
'Invalid FEN: piece data is invalid (invalid piece)',
'Invalid FEN: piece data is invalid (too many squares in rank)',
'Invalid FEN: illegal en-passant square',
'Invalid FEN: missing white king',
'Invalid FEN: missing black king',
'Invalid FEN: too many white kings',
'Invalid FEN: some pawns are on the edge rows'
];
// Robust FEN loading
function safeLoadFen(fenString: string): { success: boolean; error?: string } {
const validation = validateFen(fenString);
if (!validation.ok) {
return { success: false, error: validation.error };
}
try {
const chess = new Chess(fenString);
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}interface FenValidationResult {
ok: boolean;
error?: string;
}
interface FenOptions {
forceEnpassantSquare?: boolean;
}
interface FenLoadOptions {
skipValidation?: boolean;
preserveHeaders?: boolean;
}
interface ConstructorOptions {
skipValidation?: boolean;
}