GitHunt
MC

mcarbonell/chess-movegen-js

JavaScript chess move generator with strictly legal moves. Integrated check/checkmate/stalemate detection. Two implementations: x88 & Bitboards. Tactical analysis: captures, hanging pieces, safe squares. UCI engine. Perft validated. 7M NPS performance.

Chess Move Generator

JavaScript chess move generator with strictly legal move generation

npm version
npm downloads
CI
JavaScript
License

English | Espaรฑol

๐ŸŽฏ Key Features

  • โœ… Strictly legal move generation - No pseudo-moves requiring post-validation
  • โœ… Integrated check, checkmate, and stalemate detection - During generation, not as a post-processing step
  • โœ… Two implementations: x88 and Bitboards
  • โœ… Automatic tactical analysis - Each move includes information about winning captures, hanging pieces, safe squares
  • โœ… Complete UCI engine - Compatible with standard chess interfaces
  • โœ… Interactive web interface - Visual demo with drag & drop board
  • โœ… Web Workers - Calculations without blocking the UI

๐Ÿš€ Quick Demo

Try it live!

Or open engine.html in your browser locally.

๐Ÿ“ฆ Installation

NPM

npm install chess-movegen-js

Usage

const { Board } = require('chess-movegen-js');

const board = new Board();
board.loadFEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
board.generateMoves();

console.log(`Legal moves: ${board.moves.length}`); // 20

๐Ÿ“– Usage Examples

Basic Initialization

// Create a board
const board = new Board();

// Load a FEN position
board.loadFEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');

// Generate all legal moves
board.generateMoves();

// View the moves
console.log(board.moves);

Move Analysis

Moves include tactical information:

board.generateMoves();

board.moves.forEach(move => {
    const moveStr = board.getMoveStr(move);
    console.log(moveStr);
    
    // Tactical information in move.mask:
    // - mask_check: Gives check
    // - mask_safe: Safe square
    // - mask_hanging: Piece would be hanging
    // - mask_freecapture: Undefended capture
    // - mask_winningcapture: Winning capture
});

Make and Unmake Moves

// Make a move
const move = board.moves[0];
board.makemove(move);

// Unmake
board.undomove();

Perft (Move Generation Testing)

// Count nodes at depth 5
const nodes = board.perft(5);
console.log(`Nodes: ${nodes}`); // 4,865,609 from initial position

// Divide (show nodes per move)
board.divide(4);

๐Ÿ—๏ธ Project Structure

movegen/
โ”œโ”€โ”€ js/
โ”‚   โ”œโ”€โ”€ x88.js           # x88 representation generator (1842 lines)
โ”‚   โ”œโ”€โ”€ bitboard.js      # Bitboard generator
โ”‚   โ”œโ”€โ”€ magic-tables.js  # Magic tables for bitboard
โ”‚   โ””โ”€โ”€ engine.js        # UCI engine with Web Worker
โ”œโ”€โ”€ assets/              # css and js assets for the demo
โ”œโ”€โ”€ img/                 # Graphic resources
โ”œโ”€โ”€ engine.html          # Main interactive demo
โ”œโ”€โ”€ ANALISIS.md          # Detailed technical analysis
โ””โ”€โ”€ README.md            # This file

๐ŸŽฎ UCI Engine

The project includes a complete UCI engine running in a Web Worker:

// Create engine
const w = new Worker("js/engine.js");

// UCI communication
w.postMessage('uci');
w.postMessage('position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
w.postMessage('perft 6');

// Listen for responses
w.onmessage = function(event) {
    console.log(event.data);
};

Supported UCI Commands

  • uci - Initialize engine
  • isready - Check availability
  • ucinewgame - New game
  • position [fen|startpos] [moves ...] - Set position
  • move <move> - Make move (e.g., e2e4)
  • undo - Unmake move
  • perft <depth> - Move generation test

โšก Performance

Perft from initial position (Node.js v20+, no debug):

Depth Nodes Time NPS
1 20 <1ms ~25k
2 400 ~1ms ~268k
3 8,902 ~10ms ~864k
4 197,281 ~83ms 2.4M
5 4,865,609 ~871ms 5.6M
6 119,060,324 ~17s 7.0M

In browser (may vary by browser and hardware):

  • Chrome/Edge: ~3-5M NPS
  • Firefox: ~2-4M NPS

Note: These results are with optimized code (no debug() calls).
Production performance is excellent for pure JavaScript.

๐ŸŽจ Technical Highlights

1. Pin Detection

Pinned pieces are detected during generation. Illegal moves are never generated:

// pinDirection[side][square] indicates if a piece is pinned
// and in which direction

2. Tactical Enrichment

Each move contains flags indicating:

  • If it gives check or checkmate
  • If the piece would be hanging
  • If it's a winning capture
  • If it's a safe square

3. Special Cases

  • โœ… En passant capture with horizontal pins
  • โœ… Discovered checks (including in castling)
  • โœ… Mate-in-one detection
  • โœ… Multiple promotions

๐Ÿ”ฌ Implementations

  • 128-position array (16ร—8)
  • Ultra-fast validation: if (sq & 0x88) continue
  • More readable and easier to understand code
  • File: js/x88.js

Bitboards (Experimental)

  • 64-bit bitboard representation
  • Faster in theory, more complex
  • File: js/bitboard.js

๐Ÿ“š Documentation

For a complete technical analysis of the code, see ANALISIS.md.

๐Ÿงช Testing

The project uses Perft to validate move generation:

// From browser console in engine.html
w.postMessage('perft 5');

// Or in code
const board = new Board();
board.loadFEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
console.log(board.perft(5)); // Should be 4,865,609

๐Ÿงช Running Tests

The project includes a comprehensive Perft test suite to validate move generation correctness and measure performance.

Quick Start

# Run quick test suite (depths 1-4, ~1 minute)
node tests/perft-test.js --quick

# Test specific position
node tests/perft-test.js --position 0 --depth 5

# Test only x88 generator up to depth 6
node tests/perft-test.js --generator x88 --depth 6

Available Options

node tests/perft-test.js [options]

Options:
  --generator <x88|bb|both>   Select generator to test (default: both)
  --position <n>              Test only position n (default: all)
  --depth <n>                 Test up to depth n (default: 6)
  --quick                     Quick test mode (depths 1-4)
  --help                      Show help message

Test Positions

The test suite includes 7 standard positions from Chess Programming Wiki:

Position Description Max Depth Tested
0 Initial position 10
1 Kiwipete (complex middle game) 6
2 En passant edge cases 8
3 Promotions 6
4 Promotions (mirrored) 6
5 Complex tactical position 5
6 Symmetrical position 6

Expected Output

Chess Move Generator - Perft Test Suite

Configuration:
  Generator: x88
  Positions: 7
  Max depth: 4

โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Testing: x88 Generator
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

Initial Position
FEN: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
  โœ“ Depth 1: 20 nodes [1ms, 17,891 NPS]
  โœ“ Depth 2: 400 nodes [2ms, 167,560 NPS]
  โœ“ Depth 3: 8,902 nodes [9ms, 973,343 NPS]
  โœ“ Depth 4: 197,281 nodes [80ms, 2,480,626 NPS]

Kiwipete
FEN: r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1
  โœ“ Depth 1: 48 nodes [0ms, 302,457 NPS]
  โœ“ Depth 2: 2,039 nodes [2ms, 1,220,008 NPS]
  โœ“ Depth 3: 97,862 nodes [32ms, 3,068,986 NPS]
  โœ“ Depth 4: 4,085,603 nodes [548ms, 7,461,185 NPS]

...

โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Summary
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

Total tests: 28
Passed: 28
Failed: 0
Pass rate: 100.0%

Performance Summary:
  Depth 1: 883,697 NPS avg (368 nodes in 2ms)
  Depth 2: 2,126,798 NPS avg (13,446 nodes in 10ms)
  Depth 3: 3,360,700 NPS avg (561,558 nodes in 170ms)
  Depth 4: 4,722,406 NPS avg (22,337,738 nodes in 4.51s)

Performance Benchmarks

Measured on Node.js v20+ with x88 generator (optimized, no debug):

Depth Nodes Time NPS
1 20 <1ms ~25k
2 400 ~1ms ~268k
3 8,902 ~10ms ~864k
4 197,281 ~83ms 2.4M
5 4,865,609 ~871ms 5.6M
6 119,060,324 ~17s 7.0M

Quick test suite (all 7 positions, depths 1-4): ~1.4 seconds

๐Ÿ’ก Tip: Performance is significantly faster with debug logging disabled.
Make sure to comment out this.debug() calls in production.

Troubleshooting

If tests fail or show errors:

  1. Ensure Node.js is installed: The tests require Node.js v14 or higher
  2. Check all files are present: Make sure tests/ directory exists with all test files
  3. Verify x88.js modifications: The file should have Node.js compatibility added

Known Test Positions

// Kiwipete position
board.loadFEN('r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1');
console.log(board.perft(5)); // 193,690,690

// Complex en passant capture
board.loadFEN('8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1');

๐ŸŽฏ Next Steps

  • Automated tests with Perft suite โœ…
  • Publish as NPM package โœ…
  • Repetition check with Zobrist hashing
  • WebAssembly optimization
  • Add position evaluation
  • Implement full alpha-beta search

โš™๏ธ Continuous Integration (GitHub Actions)

  • Badge: agregado arriba en este README.
  • Quรฉ ejecuta: el workflow CI corre los tests rรกpidos (npm test) automรกticamente en push y pull_request. El job de tests completos de bitboard (npm run test:bb) estรก configurado como ejecuciรณn manual para evitar ejecuciones largas en cada push.

Cรณmo lanzar el test completo desde GitHub UI:

  1. Ve a la pestaรฑa Actions del repositorio.
  2. Selecciona el workflow CI.
  3. Pulsa Run workflow, elige la rama (main o master) y ejecuta.

Usando la CLI gh (GitHub CLI) puedes lanzar el workflow asรญ:

gh workflow run ci.yml --ref main

Nota: el workflow CI incluye matrix de versiones Node para los tests rรกpidos y reserva un job manual (test-bitboard-full) con mayor timeout para las pruebas intensivas.

๐Ÿค Contributing

Contributions are welcome. Please:

  1. Fork the project
  2. Create a branch for your feature (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

๐Ÿ“– Resources and References

๐Ÿ“ License

This project is under the MIT License - see the LICENSE file for details.

๐Ÿ‘ค Author

Mario Raรบl Carbonell Martรญnez


โญ If you find this project useful, consider giving it a star on GitHub!

mcarbonell/chess-movegen-js | GitHunt