or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

board-representation.mdfen-support.mdgame-analysis.mdgame-management.mdindex.mdmove-operations.mdpgn-support.md
tile.json

fen-support.mddocs/

FEN Support

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.

Capabilities

FEN Validation

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);
}

FEN Generation

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 capture

FEN Loading

Load 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 preserved

FEN Format Specification

FEN strings consist of six space-separated fields:

1. Piece Placement

Describes piece positions rank by rank, from rank 8 to rank 1:

  • r, n, b, q, k, p = black pieces
  • R, N, B, Q, K, P = white pieces
  • 1-8 = number of empty squares
  • / = rank separator

Example: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR

2. Active Color

  • w = white to move
  • b = black to move

3. Castling Rights

  • K = white kingside castling available
  • Q = white queenside castling available
  • k = black kingside castling available
  • q = black queenside castling available
  • - = no castling rights available

Example: KQkq (all castling rights), Kq (white kingside, black queenside), - (none)

4. En Passant Target Square

  • Square behind pawn that just moved two squares (e.g., e3 after e2-e4)
  • - if no en passant capture possible

5. Halfmove Clock

Number of halfmoves since last pawn move or capture (for 50-move rule)

6. Fullmove Number

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

Common FEN Patterns

// 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';

Error Handling

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 };
  }
}

Types

interface FenValidationResult {
  ok: boolean;
  error?: string;
}

interface FenOptions {
  forceEnpassantSquare?: boolean;
}

interface FenLoadOptions {
  skipValidation?: boolean;
  preserveHeaders?: boolean;
}

interface ConstructorOptions {
  skipValidation?: boolean;
}