xchess2
v2.8.2
Published
Chess Engine
Readme
Chess Engine Features
A powerful and flexible chess engine supporting classic and custom variants, move validation, full history, and Chess960.
Features
- Accepts moves in algebraic notation
- Lists valid moves in algebraic notation
- Fuzzy algebraic notation parsing
- En Passant validation
- 3-fold and 5-fold repetition detection
- 50-move and 75-move rule detection
- Dead position detection
- Stalemate detection
- Check detection
- Checkmate detection
- Supports resignations
- Flag (timeout) detection
- Forfait (technical loss)
- Draw offers and acceptance
- Undo and redo moves
- Full event log of all actions
- Full FEN support
- PGN support
- Custom board sizes
- Custom pieces with unique moves
- Custom castling rules
- Chess960 (Fischer Random Chess) support
- Fairy/variant chess support
- Generates valid moves for any custom piece, supporting leapers, riders, and hoppers
- ASCII visualizations of board, position, moves, and reachability
- Works in both Node.js and browser environments
import { Game } from "xchess2"
// Create a new game with the standard board
const game = new Game();
// Setup position
game.position.setup();
// Play game
game.play();
game.on('check', () => console.log('Check!'));
game.on('gameover', () => console.log(game.reason));
// Make moves in algebraic notation
game.move("e4");
game.move("e5");Work with a custom board and custom pieces
import { Game } from "xchess2"
const game = new Game({board: [10, 8], bestiary: ["chess", "princess"]});
// FEN position
game.fen = 'rnbsqksbrn/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBSQKSBNR w KQkq - 0 1';
// Show position
game.on('state', () => console.log(game.position.text()))
game.play();
game.move("a3");
// Get the full event log of the game
for(const state of game.moveLog())
console.log(state.toSAN());
// Generate FEN and PGN
console.log(game.fen);
console.log(game.toPGN());Example of a custom piece class — Elephant
import { Game, Piece, moves, hits} from "xchess2"
class Elephant extends Piece {
static id = "elephant"; // Unique identifier of the piece
static whiteFen = "E"; // Symbol in FEN for the white piece
static blackFen = "e"; // Symbol in FEN for the black piece
static moveLetter = "E"; // Letter used in algebraic notation
static whiteSign = "🐘"; // Unicode symbol for white Elephant
static blackSign = "🦏"; // Unicode symbol for black Elephant
static code = 6; // Internal code for the engine
// Method to generate legal moves (customizable)
moves(state, from){
return moves.A(from, this, state.position);
}
// Check attacks (customizable)
attacks(position, from, to){
return hits.A(from, to);
}
}
// Using the custom piece in a game
const customGame = new Game({
board: [10, 8],
bestiary: ['chess', Elephant]
});
game.fen = 'renbqkbner/pppppppppp/10/10/10/10/PPPPPPPPPP/RENBQKBNER w KQkq - 0 1';
// Place Elephant on a1 and make a move
game.position.set("a1", "E");
pos.move("a3");
// Check FEN after the move
console.log(pos.fen);Table of Contents
- Game
- Game.is(value)
- Game.from(value)
- new Game(config)
- game.board
- game.bestiary
- game.rules
- game.tags
- game.current
- game.first
- game.last
- game.time
- game.prevEvent
- game.nextEvent
- game.eventID
- game.status
- game.state
- game.ply
- game.result
- game.prev
- game.next
- game.plyID
- game.drawOffer
- game.fen
- game.color
- game.position
- game.castling
- game.enPassant
- game.fullmoveNumber
- game.halfmoveClock
- game.lastMove
- game.moves
- game.checkSquares
- game.isCheck
- game.repetitionCount
- game.isDeadPisition
- game.hash
- game.wk
- game.wq
- game.bk
- game.bq
- game.reason
- game.isSetup
- game.isPromotion
- game.isState
- game.isMeta
- game.isPly
- game.canMove
- game.canMeta
- game.isIrreversible
- game.isGameOver
- game.isWin
- game.isDraw
- game.isCheckmate
- game.isStalemate
- game.winner
- game.loser
- game.stats()
- game.traceMoves(square, piece)
- game.play()
- game.move(query)
- game.promote(piece)
- game.forfeit(color)
- game.resign(color)
- game.flagFall()
- game.draw(color)
- game.nag(value)
- game.comment(comment)
- game.undo()
- game.redo()
- game.go(offset)
- game.goto(plyID)
- game.rewind()
- game.end()
- game.undoEvent()
- game.redoEvent()
- game.goEvent(offset)
- game.gotoEvent(eventID)
- game.log()
- game.moveLog()
- game.events()
- game.toPGN()
- game.on(eventType, listener)
- game.off(eventType, listener)
- game.once(eventType, listener)
- game.emit(eventType, ... args)
- game.subscribe(listener)
- game.unsubscribe(listener)
- game.on('transition', listener)
- game.on('seek', listener)
- game.on('seek-state', listener)
- game.on('seek-ply', listener)
- game.on('event', listener)
- game.on('state', listener)
- game.on('ply', listener)
- game.on('play', listener)
- game.on('50-moves', listener)
- game.on('3-repetition', listener)
- game.on('promotion', listener)
- game.on('move', listener)
- game.on('promote', listener)
- game.on('capture', listener)
- game.on('double-pawn-move', listener)
- game.on('en-passant', listener)
- game.on('castling', listener)
- game.on('draw-offer', listener)
- game.on('nag', listener)
- game.on('comment', listener)
- game.on('gameover', listener)
- game.on('win', listener)
- game.on('draw', listener)
- game.on('checkmate', listener)
- game.on('forfeit', listener)
- game.on('resignation', listener)
- game.on('win-on-time', listener)
- game.on('stalemate', listener)
- game.on('dead-position', listener)
- game.on('draw-by-3-repetition', listener)
- game.on('draw-by-5-repetition', listener)
- game.on('draw-by-50-moves', listener)
- game.on('draw-by-75-moves', listener)
- game.on('draw-by-agreement', listener)
- game.on('draw-by-resignation', listener)
- game.on('draw-on-time', listener)
- game.on('change', listener)
- Position Change Events
- Board
- Board.from(value)
- board.width
- board.height
- board.size
- board.width10Length
- board.height10Length
- board.maxFileLength
- board.maxPackedLength
- board.files
- board.ranks
- board.ranksReversed
- board.filesReversed
- board.squares
- board.text(cellCb)
- board.file(value)
- board.hasFile(value)
- board.reqFile(value)
- board.rank(value)
- board.hasRank(value)
- board.reqRank(value)
- board.at(x, y)
- board.get(value)
- board.has(value)
- board.req(value)
- board.rand()
- board.pack(... squares)
- board.unpack(value, length)
- board.packString(...squares)
- board.unpackString(value)
- Bestiary
- RuleEngine
- File
- Rank
- Square
- Color
- Color.white
- Color.black
- Color.w
- Color.b
- Color.from(value)
- Color.invert(value)
- Color.rand()
- Color.all()
- Color.is(value)
- Color.isWhite(value)
- Color.isBlack(value)
- color.code
- color.char
- color.name
- color.fen
- color.isWhite
- color.isBlack
- color.moveDir
- color.invert()
- color.valueOf()
- color.toString()
- color.toJSON()
- color.eq(value)
- color.opposite(value)
- color.relRank(square)
- ColorSet
- new ColorSet(value)
- colorSet.size
- colorSet.setAll(colors)
- colorSet.add(value)
- colorSet.delete(value)
- colorSet.toggle(value)
- colorSet.has(value)
- colorSet.clear()
- colorSet.addWhite()
- colorSet.addBlack()
- colorSet.deleteWhite()
- colorSet.deleteBlack()
- colorSet.toggleWhite()
- colorSet.toggleBlack()
- colorSet.hasWhite()
- colorSet.hasBlack()
- colorSet.toArray()
- colorSet.toJSON()
- colorSet.keys()
- colorSet.values()
- colorSet.entries()
- colorSet.forEach(cb, thisArg)
- colorSet.onChange()
- Piece
- Built-in Piece Classes
- Custom Pieces
- Piece.id
- Piece.code
- Piece.whiteFen
- Piece.blackFen
- Piece.whiteSign
- Piece.blackSign
- Piece.moveLetter
- Piece.weight
- Piece.isPromotable
- Piece.is(value)
- new Piece(color)
- piece.color
- piece.id
- piece.code
- piece.fen
- piece.sign
- piece.moveLetter
- piece.weight
- piece.isRoyal
- piece.isPawn
- piece.isLocked
- piece.isPromotable
- piece.isIrreversible
- piece.isMating
- piece.isCastlingActor
- piece.isCastlingPartner
- piece.isCapturable(piece)
- piece.isPassable(piece)
- piece.advantage(color)
- piece.moves(state, square)
- piece.attacks(position, from, to)
- piece.valueOf()
- Move
- move.color
- move.isPieceMove
- move.isCapture
- move.isIrreversible
- move.isPromotable
- move.disambiguation
- move.piece
- move.from
- move.to
- move.captured
- move.capturedAt
- move.promoteTo
- move.qc
- move.kc
- move.promotes
- move.code
- move.match(query)
- move.apply(prev)
- move.project(position)
- move.enPassant()
- move.trigger(game)
- move.isCheck(position)
- move.toSAN(options)
- move.toString(options)
- MoveList
- Position
- new Position(game, position)
- position.game
- position.board
- position.bestiary
- position.size
- position.fen
- position.at(x, y)
- position.get(square)
- position.has(square)
- position.find(piece)
- position.contains(piece)
- position.keys()
- position.values()
- position.entries()
- position.byColor(color)
- position.whites()
- position.blacks()
- position.forEach(cb, thisArg)
- position.toString()
- position.toJSON()
- position.text(pieceCb)
- position.clone()
- position.freeze()
- position.weight()
- position.advantage(color)
- position.density()
- position.stats(color)
- position.attacks(square, piece)
- position.moves(state)
- position.checks(color)
- position.isCheck(color)
- MutablePosition, SetupPosition
- setupPosition.set(square, piece)
- setupPosition.delete(square)
- setupPosition.clear()
- setupPosition.move(from, to)
- setupPosition.setAll(position)
- setupPosition.merge(position)
- setupPosition.fill(piece)
- setupPosition.fillFile(file, piece)
- setupPosition.fillRank(rank, piece)
- setupPosition.sample(probability)
- setupPosition.shuffle()
- setupPosition.setup()
- setupPosition.setup960()
- setupPosition.king(square, color)
- setupPosition.queen(square, color)
- setupPosition.rook(square, color)
- setupPosition.bishop(square, color)
- setupPosition.knight(square, color)
- setupPosition.pawn(square, color)
- setupPosition.K(square)
- setupPosition.Q(square)
- setupPosition.R(square)
- setupPosition.B(square)
- setupPosition.N(square)
- setupPosition.P(square)
- setupPosition.k(square)
- setupPosition.q(square)
- setupPosition.r(square)
- setupPosition.b(square)
- setupPosition.n(square)
- setupPosition.p(square)
- Castling
- SetupCastling
- SetupCastling.from(game, value)
- setupCastling.game
- setupCastling.wk
- setupCastling.wq
- setupCastling.bk
- setupCastling.bq
- setupCastling.fen
- setupCastling.size
- setupCastling.setWK(value)
- setupCastling.setWQ(value)
- setupCastling.setBK(value)
- setupCastling.setBQ(value)
- setupCastling.add(kingFrom, kingTo, rookFrom, rookTo)
- setupCastling.delete(castle)
- setupCastling.clear()
- setupCastling.has(castle)
- setupCastling.toArray()
- setupCastling.valid(position)
- setupCastling.prepare(position)
- Castle
- moves
- moves.walk(from, piece, position, squares)
- moves.trace(from, piece, position, squares)
- moves.ray(from, piece, position, dx, dy)
- moves.hop(from, piece, position, dx, dy)
- moves.T(from, piece, position, R)
- moves.X(from, piece, position, R)
- moves.L(from, piece, position, A, B)
- moves.W(from, piece, position)
- moves.D(from, piece, position)
- moves.H(from, piece, position)
- moves.F(from, piece, position)
- moves.A(from, piece, position)
- moves.G(from, piece, position)
- moves.N(from, piece, position)
- moves.C(from, piece, position)
- moves.Z(from, piece, position)
- moves.Q(from, piece, position)
- moves.TT(from, piece, position, R)
- moves.XX(from, piece, position, R)
- moves.LL(from, piece, position, A, B)
- moves.WW(from, piece, position)
- moves.DD(from, piece, position)
- moves.HH(from, piece, position)
- moves.FF(from, piece, position)
- moves.AA(from, piece, position)
- moves.GG(from, piece, position)
- moves.NN(from, piece, position)
- moves.CC(from, piece, position)
- moves.ZZ(from, piece, position)
- moves.QQ(from, piece, position)
- moves.hopT(from, piece, position, R)
- moves.hopX(from, piece, position, R)
- moves.hopL(from, piece, position, A, B)
- moves.hopW(from, piece, position)
- moves.hopD(from, piece, position)
- moves.hopH(from, piece, position)
- moves.hopF(from, piece, position)
- moves.hopA(from, piece, position)
- moves.hopG(from, piece, position)
- moves.hopN(from, piece, position)
- moves.hopC(from, piece, position)
- moves.hopZ(from, piece, position)
- moves.hopQ(from, piece, position)
- moves.pawn(from, piece, state)
- hits
- hits.walk(to, squares)
- hits.trace(from, to, piece, position, squares)
- hits.ray(from, to, piece, position, dx, dy)
- hits.hop(from, to, piece, position, dx, dy)
- hits.T(from, to, R)
- hits.X(from, to, R)
- hits.L(from, to, A, B)
- hits.W(from, to)
- hits.D(from, to)
- hits.H(from, to)
- hits.F(from, to)
- hits.A(from, to)
- hits.G(from, to)
- hits.N(from, to)
- hits.C(from, to)
- hits.Z(from, to)
- hits.Q(from, to)
- hits.TT(from, to, piece, position, R)
- hits.XX(from, to, piece, position, R)
- hits.LL(from, to, piece, position, A, B)
- hits.WW(from, to, piece, position)
- hits.DD(from, to, piece, position)
- hits.HH(from, to, piece, position)
- hits.FF(from, to, piece, position)
- hits.AA(from, to, piece, position)
- hits.GG(from, to, piece, position)
- hits.NN(from, to, piece, position)
- hits.CC(from, to, piece, position)
- hits.ZZ(from, to, piece, position)
- hits.QQ(from, to, piece, position)
- hits.hopT(from, to, piece, position, R)
- hits.hopX(from, to, piece, position, R)
- hits.hopL(from, to, piece, position, A, B)
- hits.hopW(from, to, piece, position)
- hits.hopD(from, to, piece, position)
- hits.hopH(from, to, piece, position)
- hits.hopF(from, to, piece, position)
- hits.hopA(from, to, piece, position)
- hits.hopG(from, to, piece, position)
- hits.hopN(from, to, piece, position)
- hits.hopC(from, to, piece, position)
- hits.hopZ(from, to, piece, position)
- hits.hopQ(from, to, piece, position)
- hits.pawn(from, to, pawn)
Game
Game is the main class representing a chess game. It manages the game state, move history, and gameplay logic.
States
Setup Mode (
game.isSetup = true):- The game is in edit mode immediately after creation.
- You can freely modify the position, castling rights, and other parameters.
- Move history does not exist, and methods related to gameplay or history navigation are unavailable.
Game Mode (
game.isSetup = false):- Activated by calling
game.play(). - The game cannot return to setup mode once started.
- Manual editing of game parameters is not allowed; all state changes are determined by game logic.
- You can trigger game events or navigate the move history.
- The current game cursor (
game.current) points to a specific position in the event chain.
- Activated by calling
Game.is(value)
Checks if the given value is a Game instance.
Parameters
value(any): The value to check.
Returns
boolean:trueifvalueis aGameinstance, otherwisefalse.
Game.from(value)
Creates a Game instance from the given value.
If value is already a Game instance, it is returned as-is.
Otherwise, a new Game is created using new Game(value).
Parameters
value(Game|string|object):
The source to create the game from:Game: returned directly.string: a FEN string representing a board position.object: a set of game parameters (e.g., initial position, options).
Returns
Game: the existing game (ifvaluewas aGame) or a new game created from the value.
new Game(config)
Creating a New Game
A new game is created using the Game constructor with a config parameter.
The config parameter can be:
- A string — a FEN string representing the starting position.
- An object — with detailed configuration options.
- An instance of
Game— another game object. In this case, the constructor creates a clone of the current state of that game in editing mode.
Unlike a full copy, it does not duplicate the move history, but only transfers the current board state and related parameters.
config.board
- Board instance (
Board) - Object
{ width, height } - Array
[width, height]
See:Board.from(value)
config.bestiary
- Bestiary instance (
Bestiary) - Identifier of a built-in piece class or bestiary
- Piece subclass (custom piece class)
- Iterator of any of the above
See:Bestiary.from(value)
config.tags
- Iterator of key-value string pairs
- Object of tags
config.rules
- EngineRules subclass instance
See:EngineRules
config.position
- FEN string of the starting position
- Position instance (
Position) - Iterator of
[square, piece]pairs - An object in the form
{a1: 'Q', ...}where keys are square names and values are pieces See: new Position(game, position)
config.color (default: Color.white)
- String values:
'white','black','w','b' - Numeric codes:
0(white),1(black) - Color instance:
Color.white,Color.black
See: Color.from(value)
config.enPassant (default: null)
null- String — square name
- Number — square ID
- Square instance (
Square) See: board.get(value)
config.fullmoveNumber (default: 1)
- Positive integer
config.halfmoveClock (default: 0)
- Non-negative integer
config.wk / config.wq / config.bk / config.bq
- Boolean flags for castling rights
- Ignored if
config.castlingis provided
config.castling
- String — FEN castling rights
- Castling or SetupCastling instance
- Object
{ wk, wq, bk, bq } - Iterator of custom castlings, where each castling can be:
- Array of squares
[kingFrom, kingTo, rookFrom, rookTo] - Object of squares
{ kingFrom, kingTo, rookFrom, rookTo }
See: SetupCastling.from(game, value)
- Array of squares
Notes:
- Immediately after creation, the game is in setup mode (
game.isSetup = true). - No move history exists at this point.
- You can freely edit the position, castling rights, and other parameters before starting the game.
- To start the game, call
game.play(). - Once the game is started, it is impossible to return to setup mode.
- In game mode, all state changes are governed by game logic, and manual editing of parameters is disabled.
game.board
- Represents the chessboard of the game.
- Instance of
Board. - Provides access to squares, files, ranks, and board dimensions.
- Use
game.board.at(x, y)orgame.board.get(value)to access individual squares. - See: Board
game.bestiary
- Contains the pieces used in the game.
- Instance of
Bestiary. - Defines piece types, promotions, and custom piece rules.
- You can check if a piece type is supported or get a random piece of a given color.
- See: Bestiary
game.rules
- Holds the rules engine for the game.
- Instance of
RuleEngineor subclass. - Determines valid moves, checks, repetitions, dead positions, and game results.
- Provides methods like
rules.moves(state)orrules.repetitionCount(state). - See: RuleEngine
game.tags
- Stores game metadata (e.g., players, event, date).
- Can be an object of key-value pairs or an iterator of string pairs.
- Example:
{ White: "Alice", Black: "Bob", Event: "Friendly Match" }
game.current
- Represents the current event in the game.
- Points to the event at the current position of the game cursor in the event chain.
- Used for navigating, inspecting, or applying moves relative to the current game state.
- In game mode, it always points to a specific event, allowing methods like
game.goEvent(offset)orgame.gotoEvent(eventID)to navigate the history.
game.first
- Represents the first event in the game history.
- Useful for rewinding or iterating from the beginning of the game.
- In setup mode,
game.firstisnullbecause no events exist yet. - In game mode, it always points to the very first move or event played.
game.last
- Represents the last event in the game history.
- Useful for checking the most recent move or appending new events.
- In setup mode,
game.lastisnullsince no moves have been made. - In game mode, it points to the latest event in the event chain.
game.time
- Represents the timestamp or sequence number of the current event in the game.
- Indicates the chronological order of events.
- In setup mode,
game.timeis typicallynullbecause no events have occurred. - In game mode, it updates automatically as new moves or events are applied.
- Can be used to compare the relative timing of events or for logging purposes.
game.prevEvent
- Represents the previous event relative to the current position (
game.current) in the event chain. - Returns
nullifgame.currentis the first event or if in setup mode. - Useful for navigating backward in the game's history or undoing moves.
game.nextEvent
- Represents the next event relative to the current position (
game.current) in the event chain. - Returns
nullifgame.currentis the last event or if in setup mode. - Useful for navigating forward in the game's history or redoing moves.
game.eventID
- Unique identifier of the current event (
game.current) in the event chain. - Can be used to reference, navigate to, or log specific events.
- In setup mode, usually
nullbecause no events exist yet.
game.status
- Represents the status of the current event (
game.current) as a string. - Indicates the type or phase of the event, e.g.,
'move','promotion','draw-offer','gameover'. - Useful for identifying what kind of action or outcome the current event represents.
- In setup mode,
game.statusis usually'setup'.
game.state
- Represents the current state of the game at the event pointed to by
game.current. - Includes all relevant parameters: position, active color, castling rights, en passant, move counters, etc.
- In setup mode, reflects the manually configured setup.
- In game mode, reflects the state determined by game logic and event history.
game.ply
- Represents the last completed ply (half-move) or the initial game state corresponding to the current event (
game.current). - Provides the reference point for the game state at that moment.
- Returns
nullin setup mode, because no moves have been made yet. - Useful for inspecting the state of the board, move history, or for performing navigations relative to completed plies.
game.result
- Instance of the
Resultclass representing the outcome of the game for the current event (game.current). - Contains:
reason— the reason the game ended (e.g., checkmate, resignation, draw).winner— color of the winning side (Color.whiteorColor.black), if applicable.loser— color of the losing side, if applicable.pgn— PGN string representing the game conclusion.
- If the game is not finished,
game.resultcontains a placeholder objectNoResult. - Updated automatically based on game logic and event outcomes.
game.prev
- Represents the previous ply event relative to
game.current. - Returns
nullif the current event is the first in the history or if in setup mode. - Useful for navigating backward through the sequence of completed plies in the game.
game.next
- Represents the next ply event relative to
game.current. - Returns
nullif the current event is the last in the history or if in setup mode. - Useful for navigating forward through the sequence of completed plies in the game.
game.plyID
- Unique identifier of the current ply (half-move) in the game.
- Starts at
0for the initial game position. - Corresponds to the ply associated with
game.current. - Useful for navigating to a specific ply using methods like
game.goto(plyID)orgame.go(offset). - In setup mode,
game.plyIDisnullbecause no moves have been made yet.
game.drawOffer
- Instance of the
Colorclass representing the player who offered a draw. - Updated when a draw is proposed using
game.draw(color). - Returns
nullif no draw offer has been made after the last move. - Useful for checking if a draw offer is currently active and which player made it.
game.fen
- Represents the FEN string of the current game state.
- Automatically updated as moves are applied or the position changes.
- Can be extended in the following cases:
- The board is not 8×8.
- The bestiary contains additional custom pieces.
- Custom castlings are added via
game.castling.add(...).
- In setup mode, the property is writable, allowing you to set the position manually:
game.fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; - In game mode, it reflects the position determined by game logic and move history and is read-only.
- Useful for exporting, saving, or analyzing the current board state.
game.color
- Instance of the
Colorclass representing the active color (the side to move next). - Indicates which player's turn it is in the current game state.
- In setup mode, the property is writable:
- Can be set using string values:
'white','black','w','b'. - Can be set using numeric codes:
0(white) or1(black). - Can be set using Color instances:
Color.whiteorColor.black.
- Can be set using string values:
- In game mode, the value is determined automatically by game logic and is read-only.
- Useful for configuring the initial turn or inspecting whose move it is.
game.position
- Represents the current board position in the game.
- Returns different objects depending on the mode:
- Setup mode: returns a SetupPosition instance (writable, editable).
- Game mode: returns a Position instance (immutable, read-only).
- In setup mode, the property is writable and supports all variants of assigning a position:
- FEN string
- Position object
- Object of square-piece pairs, e.g.,
{ a1: 'Q', b1: 'N', ... } - Iterator of
[square, piece]pairs - Another
PositionorSetupPositioninstance
- In game mode, the position is determined by game logic and the history of events, and cannot be manually changed.
- Useful for configuring, inspecting, or exporting the current board state.
Example: Setting game.position in setup mode
// 1. Using a FEN string
game.position = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
// 2. Using an object of square-piece pairs
game.position = {
a1: 'R', b1: 'N', c1: 'B', d1: 'Q', e1: 'K', f1: 'B', g1: 'N', h1: 'R',
a2: 'P', b2: 'P', c2: 'P', d2: 'P', e2: 'P', f2: 'P', g2: 'P', h2: 'P'
};
// 3. Using an iterator of [square, piece] pairs
game.position = [
['a1', 'R'], ['b1', 'N'], ['c1', 'B'], ['d1', 'Q'], ['e1', 'K'],
['f1', 'B'], ['g1', 'N'], ['h1', 'R']
];
// 4. Using another Position or SetupPosition instance
const game2 = new Game("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
game.position = game2.position;
// Output the current position to the console
console.log(game.position.text());game.castling
- Represents the current castling rights in the game.
- Returns a Castling or SetupCastling instance depending on the mode:
- Setup mode: writable, allows adding, modifying, or clearing castling rights.
- Game mode: read-only, determined by the position and game history.
- Supports multiple ways to assign castling rights in setup mode:
- FEN string (e.g.,
"KQkq"for standard castling rights). - Object of flags
{ wk, wq, bk, bq }. - Castling / SetupCastling instance with custom castling definitions.
- Iterator of custom castling moves, each defined as an array
[kingFrom, kingTo, rookFrom, rookTo].
- FEN string (e.g.,
- Useful for configuring the initial castling rights or inspecting the current castling possibilities.
Example: Setting game.castling in setup mode
// 1. Using a FEN string for castling rights
game.castling = "KQkq";
// 2. Using an object of castling flags
game.castling = { wk: true, wq: true, bk: true, bq: true };
// 3. Using a Castling
game.castling.add('e1', 'g1', 'h1', 'f1'); // custom white kingside
game.castling.add('e8', 'c8', 'a8', 'd8'); // custom black queenside
// 4. Using an iterator of custom castlings
game.castling = [
['e1', 'g1', 'h1', 'f1'], // white kingside
['e8', 'c8', 'a8', 'd8'] // black queenside
];
// Output current castling configuration
console.log(game.castling.toArray());game.enPassant
- Represents the en passant target square in the current game state.
- Returns a
Squareinstance, ornullif no en passant target exists. - In setup mode, the property is writable and supports multiple ways to assign a square:
null— no en passant target.- String square name, e.g.,
'e6'. - Numeric square ID.
- Square instance from the board, e.g.,
board.get('e6').
- In game mode, the value is determined automatically by the game logic based on the last move and is read-only.
- Useful for determining whether an en passant capture is possible.
game.fullmoveNumber
- Represents the fullmove number of the game (counts complete turns, i.e., pairs of White and Black moves).
- Starts at
1for the initial position. - In setup mode, the property is writable, allowing manual configuration.
- In game mode, automatically updated by the game logic after each move.
- Useful for PGN export and move tracking.
game.halfmoveClock
- Represents the halfmove clock used for the fifty-move rule.
- Counts the number of half-moves (plies) since the last pawn advance or capture.
- Starts at
0for the initial position. - In setup mode, the property is writable for manual configuration.
- In game mode, automatically updated by the game logic.
- Useful for enforcing the fifty-move draw rule and analyzing game state.
game.wk
game.wq
game.bk
game.bq
- Shorthand properties for individual castling rights:
game.wk— White kingside castlinggame.wq— White queenside castlinggame.bk— Black kingside castlinggame.bq— Black queenside castling
- In setup mode, all these properties are writable, allowing manual configuration of castling rights.
- In game mode, they are read-only and reflect the castling possibilities determined by the game state.
- Internally, they map directly to
game.castling.wk,game.castling.wq,game.castling.bk, andgame.castling.bq. - Useful for quickly reading or modifying individual castling permissions without interacting with the full
game.castlingobject.
game.lastMove
- Represents the last move played in the game as a
Moveinstance. - Returns
nullin the following cases:- Setup mode, because no moves have been made.
- At the initial game position, before any moves.
- In game mode, updated automatically as moves are applied.
- Useful for inspecting the most recent action, including its source and destination squares, captured pieces, promotion, or special move properties (castling, en passant, etc.).
game.moves
- Represents the list of legal moves available for the current player.
- Returns a MoveList instance.
- Always available, even if the list is empty (e.g., checkmate or stalemate).
- In setup mode, not applicable; moves are determined only in game mode.
- Useful for:
- Displaying legal moves to the player.
- AI or move selection.
- Validating player input before applying a move.
game.checkSquares
- Returns an array of squares currently under check for the side to move.
- Each element is a Square instance.
- Empty array if the king is not under check.
- Useful for highlighting threats or detecting checks programmatically.
game.isCheck
- Boolean indicating whether the current player is in check.
- Returns
trueifgame.checkSquaresis non-empty, otherwisefalse. - Useful for enforcing rules that prevent illegal moves or for UI indicators.
game.repetitionCount
- Represents the number of times the current position has occurred in the game history.
- Returns a positive integer starting from
1. - Useful for detecting threefold (or fivefold) repetition draws and other repetition-based rules.
game.isDeadPisition
- Boolean indicating whether the current position is a dead position, i.e., a position where checkmate is impossible by any legal sequence of moves.
- Useful for detecting automatic draws in scenarios like king vs. king or insufficient material.
game.hash
- Represents a BigInt hash of the current game state.
- Includes in the hash calculation:
- Board position
- Castling rights
- En passant target square
- Active color (side to move)
- Used primarily for implementing threefold and fivefold repetition rules.
- Useful for efficiently detecting repeated positions without comparing entire board states.
game.reason
Represents the reason for the game ending or the current game state.
Returns a string, one of the following values:
'no result'— game is ongoing or in setup mode'checkmate'— game ended by checkmate'forfeit'— game ended by forfeit'resignation'— game ended by resignation'win on time'— game ended due to time expiration'stalemate'— game ended by stalemate'dead position'— game ended because checkmate is impossible'3-repetition'— draw by threefold repetition'5-repetition'— draw by fivefold repetition'50 moves'— draw by fifty-move rule'75 moves'— draw by seventy-five-move rule'draw by agreement'— draw agreed by players'draw by resignation'— draw due to resignation of a player'draw on time'— draw because both players’ time expired
game.isSetup
trueif the game is in setup/edit mode;falsein game mode.
game.isPromotion
trueif the current move involves a promotion.
game.isState
trueif the current event is a game state change rather than a player move.
game.isMeta
trueif the current event is a meta event, like comment, NAG, or draw offer.
game.isPly
trueif the current event represents a ply/move in the game.
game.canMove
- Boolean indicating whether moves can currently be made.
- Returns
falsein the following cases:- Setup mode (editing the game).
- The current move is a promotion that has not been completed.
- The game is finished (checkmate, draw, resignation, etc.).
- Returns
trueonly in game mode when a move is legally allowed for the current player. - Useful for validating whether a player or AI can make a move at the current point in the game.
game.canMeta
- Boolean indicating whether meta events can currently be added.
- Meta events are events that do not alter the core game state, such as:
- Comments
- NAG (Numeric Annotation Glyphs)
- Draw offers
- Returns
truein setup mode or in game mode when the current event allows meta actions. - Returns
falseif the current event or game state does not allow meta events, e.g., during an incomplete promotion or after game over. - Useful for determining whether you can attach annotations or auxiliary events at the current point in the game history.
game.isIrreversible
- Boolean indicating whether the current event irreversibly changes the game state.
- Returns
truefor moves that cannot be undone without altering game history, such as:- Pawn advances
- Captures
- The initial game state is also considered irreversible.
- Used internally for enforcing rules such as:
- Threefold/fivefold repetition
- Fifty-move and seventy-five-move rules
- Returns
falsefor meta events or reversible moves that do not affect these rules.
game.isGameOver
trueif the game has finished (checkmate, draw, resignation, etc.).
game.isWin
trueif the game ended with a win for one of the players.
game.isDraw
trueif the game ended in a draw for any reason.
game.isCheckmate
trueif the current player is checkmated.
game.isStalemate
trueif the current position is a stalemate.
game.winner
- Returns the Color of the winning player, or
nullif the game is not finished or ended in a draw.
game.loser
- Returns the Color of the losing player, or
nullif the game is not finished or ended in a draw.
game.stats()
- Returns a simple object containing various statistics of the game
game.traceMoves(square, piece)
Returns a map of reachable squares and the minimum number of moves required to reach them.
Parameters
square(Square):
The starting square for the calculation.piece?(Piece, optional):
If provided, the calculation assumes the given piece is standing on the specified square, regardless of the actual board state.
If omitted, the method uses the piece currently occupying the square (if any).
Behavior
- The search is performed based on the current board state, including the positions of all pieces.
- The starting square itself is excluded from the results.
- The turn order (which side is to move) is ignored.
Returns
Returns a TraceMap, which is like a Map but specialized for board cells.
- Keys must be
Squares. - Has an extra method
text(limit = Infinity)that renders the board as ASCII graphics:- Each cell is marked with the minimal number of moves required to reach it from
from. - The optional
limitparameter restricts how far (in moves) cells will be shown. For example:text(1)shows only the start cell as0and all cells reachable in one move as1.- By default,
text(Infinity)shows all reachable cells.
- Each cell is marked with the minimal number of moves required to reach it from
Examples
const trace = game.traceMoves('D4', 'N');
console.log(trace.text(1));
// a b c d e f g h
// ┌───┬───┬───┬───┬───┬───┬───┬───┐
// 8 │ │ │ │ │ │ │ │ │ 8
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 7 │ │ │ │ │ │ │ │ │ 7
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 6 │ │ │ 1 │ │ 1 │ │ │ │ 6
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 5 │ │ 1 │ │ │ │ 1 │ │ │ 5
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 4 │ │ │ │ 0 │ │ │ │ │ 4
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 3 │ │ 1 │ │ │ │ 1 │ │ │ 3
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 2 │ │ │ 1 │ │ 1 │ │ │ │ 2
// ├───┼───┼───┼───┼───┼───┼───┼───┤
// 1 │ │ │ │ │ │ │ │ │ 1
// └───┴───┴───┴───┴───┴───┴───┴───┘
// a b c d e f g h game.play()
Starts the game execution.
This method is irreversible: once the game is switched from setup mode to play mode, it cannot go back.
Behavior
On the first call, the game leaves setup mode and enters play mode.
On repeated calls, the method does nothing and returns
false.While entering play mode, the game validates and applies editing state options:
Castling flags (
wk,wq,bk,bq):- The engine searches for a valid pair of pieces on the same rank: a "king" (
isCastlingActor) and a "rook" (isCastlingPartner). - On an 8×8 board, final castling squares are determined according to Chess960 rules.
- On non-standard boards, the king jumps two squares, and the rook is placed on the other side.
- If no valid pair is found, the flag is ignored.
- The engine searches for a valid pair of pieces on the same rank: a "king" (
Custom castling rules (
config.castling):- For each defined castling, the engine checks whether the required pieces are present on the specified squares.
- If not, the castling option is ignored.
En passant square (
enPassant):- The target square must be empty.
- A pawn must exist in front of it in the correct position.
- If conditions are not satisfied, the en passant option is ignored.
Returns
true— if this is the first call (setup → play mode).false— if the game was already in play mode.
game.move(query)
Performs a move in game mode if it is valid.
Throws an error if the move is not allowed.
Parameters
- query
Can be one of:- A string — the move in SAN format.
- An existing Move object – will be matched against the moves in the list.
- A number representing the numeric move code, unique for the combination of start and end squares.
- An object — a move search template with possible properties:
piece— piece type (e.g.,"N","Q", etc.)from— starting squareto— destination squarefromFile— originating filefromRank— originating rankpromoteTo— piece type to promote toqc— queenside castling indicatorkc— kingside castling indicator
⚠️ The list of properties may be extended for custom moves.
- If omitted, the call is only valid when there is exactly one legal move available.
Behavior
- If exactly one move matches the query, it is executed and returned.
- If multiple moves match, an ambiguity error is thrown.
- If no move matches, a not found error is thrown.
- If the move requires promotion but no promotion piece is provided,
the game enters promotion state (game.isPromotion = true),
and expects a further call to:game.promote(piece)
Returns
- The found move (instance of class Move) if the move is successfully executed.
Using
// Using a SAN string
const move1 = game.move("e4");
// Using a search template object
const move2 = game.move({
piece: "N",
from: "g1",
to: "f3"
});
// Custom property example for extended moves
const move3 = game.move({
piece: "P",
from: "e7",
to: "e8",
promoteTo: "Q"
});game.promote(piece)
Completes a pawn promotion move.
This method can only be called while the game is in promotion state (game.isPromotion = true).
Calling it outside this state will throw an error.
Parameters
- piece — the piece to promote to. Can be one of:
- An instance of Piece.
- A string identifier of a piece type; the piece color will be determined automatically according to
game.color.
⚠️ The chosen piece must be among those allowed for promotion (
game.lastMove.promotes).
The color must match the current player's color; otherwise, an error is thrown.
Behavior
- Completes the promotion move.
- Updates the game state accordingly.
- Exits promotion state (
game.isPromotion = false).
Returns
- The completed Move object representing the promotion.
Using
// Assuming the game is in promotion state after moving a pawn to the last rank
game.isPromotion; // true
// Promoting by piece instance
const queenPiece = game.bestiary.from("Q", game.color);
const move = game.promote(queenPiece);
// Promoting by piece identifier string
const move2 = game.promote("Q");
// After promotion, promotion state ends
game.isPromotion; // falsegame.forfeit(color)
Forfeits the game for the specified player.
This method can only be called in game mode.
Parameters
- color — the color of the player who wants to forfeit:
Color.white,Color.black- or any value accepted by Color.from(value)
Behavior
- Immediately ends the game.
- Sets the winner to the opposite color.
- Updates
game.resultwith the reason"forfeit". - Can be called at any point during play.
Returns
- The final
Resultobject representing the game's outcome.
game.resign(color)
Registers a resignation for the specified player.
This method can only be called in game mode.
Parameters
- color — the color of the player who resigns:
Color.white,Color.black- or any value accepted by Color.from(value)
Behavior
- Ends the game immediately.
- Sets the winner to the opposite color.
- Updates
game.resultwith the reason"resignation"or"draw by resignation". - Can be called at any point during play.
game.flagFall()
Registers a time forfeit (flag fall) for the current player.
This method can only be called in game mode.
Behavior
- Ends the game immediately.
- Sets the winner to the opposite color of the player whose time ran out.
- Updates
game.resultwith the reason"win on time"or"draw on time"depending on the rules. - Can be called at any point during play.
game.draw(color)
Offers or enforces a draw in the game, depending on the context.
This method can only be called in game mode.
Parameters
- color — the color of the player proposing the draw:
Color.white,Color.black- or any value accepted by Color.from(value)
Behavior
Immediate draw occurs if any of the following conditions are met:
- The opposite player already proposed a draw (
game.drawOfferis set to the opposite color) after the last move. - A draw is allowed according to the 50-move rule.
- A draw is allowed according to the threefold repetition rule.
- The opposite player already proposed a draw (
Otherwise, a DrawOffer event is added to the game history:
game.drawOfferis set to the color of the player who proposed the draw.- The offer remains active until the next move or until the method is called again by another color.
game.nag(value)
Adds a Numeric Annotation Glyph (NAG) to the current move in the game.
This method can only be called in game mode.
Parameters
- value — the NAG to add. Can be:
- A number representing the NAG code
- A string such as
"!","!!","?","!?","??", etc.
Behavior
- Attaches the NAG to the current move (
game.current). - Can be used to annotate the game with standard chess commentary symbols.
game.comment(comment)
Adds a text comment to the current move in the game.
This method can only be called in game mode.
Parameters
- comment — a string containing the text of the comment.
Behavior
- Attaches the comment to the current move (
game.current). - Comments are preserved when exporting the game to PGN.
game.undo()
Moves the game game.current to the previous completed ply.
This method is used to navigate backward in game history.
Behavior
- Returns to the previous ply state.
- If the current state is a promotion, it returns to the last completed ply before the promotion (since promotion itself is not a full ply).
- In edit mode or if the current ply is the first ply, the method does nothing.
- Updates
game.currentto reflect the new cursor position.
Returns
trueif the undo successfully moved the cursor.falseif no movement was possible (edit mode or first ply).
game.redo()
Moves the game game.current to the next completed ply.
This method is used to navigate forward in game history.
Behavior
- Advances to the next ply state.
- In edit mode or if the current ply is the last ply, the method does nothing.
- Updates
game.currentto reflect the new cursor position.
Returns
trueif the redo successfully moved the cursor.falseif no movement was possible (edit mode or last ply).
game.go(offset)
Moves the game game.current by a specified number of completed plies.
Used to jump forward or backward in game history.
Parameters
- offset — a signed integer representing the number of plies to move:
- Positive: move forward
- Negative: move backward
0: does not move
Behavior
- Moves the cursor by up to
offsetplies. - If the offset exceeds the available history, it stops at the first or last ply.
- In edit mode or if
offsetis0, the method does nothing. - Updates
game.currentto reflect the new cursor position.
Returns
trueif the cursor moved.falseif no movement was possible (edit mode, offset 0, or at the bounds of history).
game.goto(plyID)
Moves the game game.current to a specific ply by its ID.
Parameters
- plyID — integer representing the target ply ID:
0— first ply-1or any negative value — first ply- Values greater than the last ply ID — moves to the last ply
Behavior
- Sets
game.currentto the specified ply. - If
plyIDis out of bounds, clamps to the first or last ply. - In edit mode, the cursor cannot move and the method does nothing.
Returns
trueif the cursor moved.falseif no movement was possible (edit mode or already at the target ply).
game.rewind()
Moves the game game.current back to the first ply (beginning of the game).
Behavior
- Sets
game.currentto the initial state. - In edit mode, the cursor cannot move and the method does nothing.
Returns
trueif the cursor moved.falseif already at the first ply or in edit mode.
game.end()
Moves the game game.current to the last event (most recent ply).
Behavior
- Sets
game.currentto the last completed move or event. - In edit mode, the cursor cannot move and the method does nothing.
Returns
trueif the cursor moved.falseif already at the last event or in edit mode.
game.undoEvent()
Moves the game game.current back by one event in the history chain.
Behavior
- Advances to the previous event, regardless of ply boundaries.
- In edit mode, the cursor cannot move and the method does nothing.
Returns
trueif the cursor moved.falseif already at the first event or in edit mode.
game.redoEvent()
Moves the game game.current forward by one event in the history chain.
Behavior
- Advances to the next event, regardless of ply boundaries.
- In edit mode, the cursor cannot move and the method does nothing.
Returns
trueif the cursor moved.falseif already at the last event or in edit mode.
game.goEvent(offset)
Moves the game game.current by a specified number of events in the history chain.
Parameters
- offset — a signed integer representing the number of events to move:
- Positive: move forward
- Negative: move backward
0: does not move
Behavior
- Moves the cursor by up to
offsetevents. - If the offset exceeds the available events, it stops at the first or last event.
- In edit mode or if
offsetis0, the method does nothing. - Updates
game.currentto reflect the new cursor position.
Returns
trueif the cursor moved.falseif no movement was possible (edit mode, offset 0, or at the bounds of history).
game.gotoEvent(eventID)
Move
