chessPGN

logo

chessPGN

GitHub Workflow Status npm npm GitHub stars License

chessPGN is a comprehensive TypeScript chess library for chess move generation, validation, and PGN parsing. Based on a fork of chess.js, it extends the original with powerful multi-game PGN file parsing capabilities while maintaining full backward compatibility.

โœจ Features

๐Ÿ“ฆ Installation

npm install @chess-pgn/chess-pgn

๐Ÿš€ Quick Start

Basic Game

import { ChessPGN } from '@chess-pgn/chess-pgn'

const chess = new ChessPGN()

// Make some moves
chess.move('e4')
chess.move('e5')
chess.move('Nf3')
chess.move('Nc6')

// Get current position
console.log(chess.fen())
// rnbqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3

// Check game state
console.log(chess.isCheck()) // false
console.log(chess.isCheckmate()) // false

// Get legal moves
console.log(chess.moves())
// ['a3', 'a4', 'b3', 'b4', 'c3', 'c4', 'd3', 'd4', ...]

// Export as PGN
console.log(chess.pgn())
// 1. e4 e5 2. Nf3 Nc6

Random Game

import { ChessPGN } from '@chess-pgn/chess-pgn'

const chess = new ChessPGN()

while (!chess.isGameOver()) {
  const moves = chess.moves()
  const move = moves[Math.floor(Math.random() * moves.length)]
  chess.move(move)
}

console.log(chess.pgn())

Load and Parse PGN

import { ChessPGN } from '@chess-pgn/chess-pgn'

const pgn = `[Event "Casual Game"]
[Site "New York"]
[Date "2025.01.15"]
[White "Alice"]
[Black "Bob"]
[Result "1-0"]

1. e4 e5 2. Nf3 Nc6 3. Bb5 1-0`

const chess = new ChessPGN()
chess.loadPgn(pgn)

console.log(chess.getHeaders())
// { Event: 'Casual Game', Site: 'New York', ... }

console.log(chess.history())
// ['e4', 'e5', 'Nf3', 'Nc6', 'Bb5']

Multi-Game PGN Files

Efficiently parse large PGN files with multiple games:

import { indexPgnGames } from '@chess-pgn/chess-pgn'
import * as fs from 'fs'

const pgnContent = fs.readFileSync('games.pgn', 'utf8')

// Create cursor with worker threads for parallel parsing
const cursor = indexPgnGames(pgnContent, {
  workers: 4,
  workerBatchSize: 10,
  onError: (err, idx) => console.error(`Game ${idx}: ${err.message}`),
})

// Iterate through games
for await (const game of cursor) {
  const headers = game.getHeaders()
  console.log(`${headers.White} vs ${headers.Black}: ${headers.Result}`)

  // Analyze final position
  if (game.isCheckmate()) {
    console.log('Checkmate!')
  }
}

// Clean up worker threads
await cursor.terminate()

Position Analysis

import { ChessPGN } from '@chess-pgn/chess-pgn'

const chess = new ChessPGN()
chess.move('e4')
chess.move('e5')
chess.move('Nf3')

// Check if square is attacked
console.log(chess.isAttacked('e5', 'w')) // true (knight attacks e5)

// Get all attackers of a square
console.log(chess.attackers('e5'))
// ['f3']

// Find pieces
console.log(chess.findPiece({ type: 'n', color: 'w' }))
// ['b1', 'f3']

// Get piece at square
console.log(chess.get('f3'))
// { type: 'n', color: 'w' }

Verbose Move Details

import { ChessPGN } from '@chess-pgn/chess-pgn'

const chess = new ChessPGN()
chess.move('e4')
chess.move('e5')
chess.move('Nf3')

// Get detailed move history
const history = chess.history({ verbose: true })
console.log(history)
/*
[
  {
    color: 'w',
    from: 'e2',
    to: 'e4',
    piece: 'p',
    san: 'e4',
    before: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
    after: 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1'
  },
  ...
]
*/

Comments and Annotations

import { ChessPGN } from '@chess-pgn/chess-pgn'

const chess = new ChessPGN()

chess.move('e4')
chess.setComment('The most popular opening move')
chess.setSuffixAnnotation('!!') // Brilliant move

chess.move('e5')
chess.setComment('Symmetric response')
chess.setSuffixAnnotation('!') // Good move

// Get all comments
const comments = chess.getComments()
console.log(comments)
/*
[
  {
    fen: 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1',
    comment: 'The most popular opening move',
    suffixAnnotation: '!!'
  },
  ...
]
*/

// Export with comments
console.log(chess.pgn())
// 1. e4!! {The most popular opening move} e5! {Symmetric response}

๐ŸŽ“ API Overview

Core Classes

Common Methods

Position Manipulation

Making Moves

Game State

Position Queries

PGN Operations

Comments and Annotations

Multi-Game API

Options:

๐Ÿ“š Documentation

๐Ÿ—๏ธ Architecture

chessPGN uses a delegation pattern where ChessPGN wraps the core Game class:

Both classes implement the same interface and produce identical results, verified through extensive parity testing across 469 real games.

๐Ÿ”ง Development

# Install dependencies
npm install

# Run tests
npm test

# Run all checks (format, lint, test, build)
npm run check

# Build the project
npm run build

# Format code
npm run format

๐Ÿงช Testing

chessPGN has comprehensive test coverage:

๐Ÿ“Š Browser and Node.js Support

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide to get started.

Ways to contribute:

๐Ÿ“„ License

This project is licensed under the BSD 2-Clause License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

๐Ÿ“ž Support