The FEN module provides functions for parsing and generating FEN strings, which are used to describe chess positions.
Constants
Position Constants
import {
INITIAL_BOARD_FEN,
INITIAL_EPD,
INITIAL_FEN,
EMPTY_BOARD_FEN,
EMPTY_EPD,
EMPTY_FEN
} from 'chessops/fen';
console.log(INITIAL_FEN);
// 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
Board part of starting position: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
Starting position EPD (without move counters): INITIAL_BOARD_FEN + ' w KQkq -'
Complete starting position FEN: INITIAL_EPD + ' 0 1'
Empty board: '8/8/8/8/8/8/8/8'
Empty position EPD: EMPTY_BOARD_FEN + ' w - -'
Complete empty position FEN: EMPTY_EPD + ' 0 1'
Error Handling
InvalidFen
Enum of possible FEN parsing errors.
import { InvalidFen } from 'chessops/fen';
enum InvalidFen {
Fen = 'ERR_FEN',
Board = 'ERR_BOARD',
Pockets = 'ERR_POCKETS',
Turn = 'ERR_TURN',
Castling = 'ERR_CASTLING',
EpSquare = 'ERR_EP_SQUARE',
RemainingChecks = 'ERR_REMAINING_CHECKS',
Halfmoves = 'ERR_HALFMOVES',
Fullmoves = 'ERR_FULLMOVES',
}
FenError
Error class for FEN parsing failures.
import { FenError, parseFen } from 'chessops/fen';
const result = parseFen('invalid');
if (result.isErr) {
const error: FenError = result.error;
console.log(error.message); // One of the InvalidFen values
}
Parsing Functions
parseFen
Parses a complete FEN string into a Setup.
import { parseFen } from 'chessops/fen';
const result = parseFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
if (result.isOk) {
const setup = result.value;
console.log(setup.turn); // 'white'
console.log(setup.fullmoves); // 1
} else {
console.error('Invalid FEN:', result.error.message);
}
The FEN string to parse. Supports:
- Standard FEN
- FEN with pockets (Crazyhouse):
[Qq] or /Qq notation
- FEN with remaining checks (Three-check):
+1+2 notation
- Promoted pieces marked with
~
A Result containing either the parsed Setup or a FenError
parseBoardFen
Parses only the board part of a FEN string.
import { parseBoardFen } from 'chessops/fen';
const result = parseBoardFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR');
if (result.isOk) {
const board = result.value;
console.log(board.occupied.size()); // 32
}
The board part of a FEN string (before the first space)
A Result containing either the parsed Board or a FenError
parsePockets
Parses pocket notation for Crazyhouse.
import { parsePockets } from 'chessops/fen';
const result = parsePockets('Qq'); // White queen, black queen
if (result.isOk) {
const pockets = result.value;
console.log(pockets.white.queen); // 1
console.log(pockets.black.queen); // 1
}
String of piece letters (uppercase for white, lowercase for black)
return
Result<Material, FenError>
A Result containing either the parsed Material (pockets) or a FenError
parseCastlingFen
Parses castling rights from FEN notation.
import { parseCastlingFen, parseBoardFen } from 'chessops/fen';
const board = parseBoardFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR').unwrap();
const result = parseCastlingFen(board, 'KQkq');
if (result.isOk) {
const castlingRights = result.value;
console.log(castlingRights.has(0)); // true (a1 rook for white queenside)
console.log(castlingRights.has(7)); // true (h1 rook for white kingside)
}
The board to use for determining rook positions
Castling rights string: ‘KQkq’, ‘Kk’, ‘AHah’ (Chess960), or ’-’
return
Result<SquareSet, FenError>
A Result containing either a SquareSet of rook squares with castling rights or a FenError
parseRemainingChecks
Parses remaining checks notation for Three-check variant.
import { parseRemainingChecks } from 'chessops/fen';
const result = parseRemainingChecks('2+1');
if (result.isOk) {
const checks = result.value;
console.log(checks.white); // 2
console.log(checks.black); // 1
}
Remaining checks string: ‘3+3’, ‘2+1’, ‘+1+2’, etc.
return
Result<RemainingChecks, FenError>
A Result containing either the parsed RemainingChecks or a FenError
parsePiece
Parses a single piece from a string.
import { parsePiece } from 'chessops/fen';
const piece = parsePiece('K');
console.log(piece); // { role: 'king', color: 'white' }
const promoted = parsePiece('q~');
console.log(promoted); // { role: 'queen', color: 'black', promoted: true }
A piece character (K, Q, R, B, N, P for white; k, q, r, b, n, p for black), optionally followed by ’~’ for promoted
The parsed Piece, or undefined if invalid
Generation Functions
makeFen
Generates a FEN string from a Setup.
import { makeFen } from 'chessops/fen';
import { Chess } from 'chessops/chess';
const pos = Chess.default();
pos.play({ from: 12, to: 28 }); // e2-e4
const fen = makeFen(pos.toSetup());
console.log(fen);
// 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1'
The position setup to convert to FEN
Options:
epd?: boolean - If true, omits halfmove and fullmove counters (generates EPD instead of FEN)
The FEN string representation of the position
makeBoardFen
Generates only the board part of a FEN string.
import { makeBoardFen } from 'chessops/fen';
import { Board } from 'chessops/board';
const board = Board.default();
const boardFen = makeBoardFen(board);
console.log(boardFen);
// 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
The board to convert to FEN notation
The board part of a FEN string
makePiece
Generates the FEN notation for a single piece.
import { makePiece } from 'chessops/fen';
const piece = { role: 'queen', color: 'white' };
console.log(makePiece(piece)); // 'Q'
const promoted = { role: 'queen', color: 'black', promoted: true };
console.log(makePiece(promoted)); // 'q~'
The FEN notation for the piece
makePockets
Generates pocket notation for Crazyhouse.
import { makePockets } from 'chessops/fen';
import { Material } from 'chessops/setup';
const pockets = Material.empty();
pockets.white.queen = 1;
pockets.black.pawn = 2;
console.log(makePockets(pockets)); // 'Qpp'
The material in pockets for both sides
The pocket notation string
makeCastlingFen
Generates castling rights notation.
import { makeCastlingFen } from 'chessops/fen';
import { Board } from 'chessops/board';
import { SquareSet } from 'chessops';
const board = Board.default();
const castlingRights = SquareSet.fromSquares([0, 7, 56, 63]);
console.log(makeCastlingFen(board, castlingRights)); // 'KQkq'
The board (used to determine standard vs Chess960 notation)
Set of squares containing rooks with castling rights
The castling rights notation
makeRemainingChecks
Generates remaining checks notation for Three-check.
import { makeRemainingChecks, RemainingChecks } from 'chessops/fen';
const checks = new RemainingChecks(2, 1);
console.log(makeRemainingChecks(checks)); // '2+1'
The remaining checks for both sides
The remaining checks notation
Usage Examples
Round-Trip Conversion
import { parseFen, makeFen } from 'chessops/fen';
const originalFen = 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1';
const setup = parseFen(originalFen).unwrap();
const regeneratedFen = makeFen(setup);
console.log(originalFen === regeneratedFen); // true
Handling Variants
import { parseFen, makeFen } from 'chessops/fen';
// Crazyhouse with pockets
const zhFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[Qq] w KQkq - 0 1';
const zhSetup = parseFen(zhFen).unwrap();
console.log(zhSetup.pockets?.white.queen); // 1
// Three-check with remaining checks
const tcFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1';
const tcSetup = parseFen(tcFen).unwrap();
console.log(tcSetup.remainingChecks?.white); // 3
Custom Position Setup
import { parseFen, makeFen } from 'chessops/fen';
import { setupPosition } from 'chessops/variant';
const fen = '8/8/8/4k3/8/8/4K3/8 w - - 0 1';
const setup = parseFen(fen).unwrap();
const pos = setupPosition('chess', setup).unwrap();
console.log(pos.isEnd()); // true (insufficient material)