JavaScript chess move generator with strictly legal move generation
| English | Espaรฑol |
Or open visualizer/engine.html in your browser locally.
npm install chess-movegen-js
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
If you are already using chess.js, you can use ChessJSAdapter as a high-performance drop-in replacement. It provides the same API (.moves(), .move(), .fen(), .isCheck(), etc.) but uses the x88 engine under the hood, making it ~50x faster.
const { ChessJSAdapter } = require('chess-movegen-js/chessjs');
// Works exactly like chess.js
const chess = new ChessJSAdapter();
chess.move('e4');
console.log(chess.fen());
console.log(chess.moves()); // Standard Algebraic Notation (SAN)
Performance measured in Node.js (Depth 4 avg):
| Generator | NPS (Nodes Per Second) | Speedup vs chess.js |
|---|---|---|
| chess.js (Original) | ~75,000 | 1x (Base) |
| ChessJSAdapter (x88) | ~3,500,000 | 47x Faster |
| JS x88 Generator | ~3,500,000 | 47x Faster |
| AssemblyScript x88 | ~3,800,000 | 51x Faster |
| Rust X88 | ~10,800,000 | 145x Faster |
| Rust Bitboard | ~15,800,000 | 213x Faster |
// 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);
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 a move
const move = board.moves[0];
board.makemove(move);
// Unmake
board.undomove();
// 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);
movegen/
โโโ js/
โ โโโ x88.js # x88 representation generator (JS)
โ โโโ bitboard.js # Bitboard generator (JS)
โ โโโ magic-tables.js # Magic tables for bitboard
โโโ rust-movegen/ # Rust implementation (x88 & Bitboard, WASM)
โโโ asmovegen/ # AssemblyScript implementation (x88, WASM)
โโโ visualizer/ # Interactive web interface
โ โโโ engine.html # Main demo page
โ โโโ js/ # Engine workers and UI logic
โโโ tests/ # Comprehensive Perft test suite
โโโ ANALISIS.md # Detailed technical analysis
โโโ README.md # This file
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);
};
uci - Initialize engineisready - Check availabilityucinewgame - New gameposition [fen|startpos] [moves ...] - Set positionmove <move> - Make move (e.g., e2e4)undo - Unmake moveperft <depth> - Move generation testBenchmarks from initial position (Depth 5):
| Implementation | Platform | NPS |
|---|---|---|
| Rust Bitboard | WASM/Browser | ~25.8M |
| Rust x88 | WASM/Browser | ~18.0M |
| AssemblyScript | WASM/Browser | ~12.5M |
| JS x88 | Node.js / Browser | ~5.6M |
| JS Bitboard | Node.js / Browser | ~4.2M |
Perft from initial position (Node.js v20+, no debug): All versions pass 100% of Perft tests up to depth 6+.
Pinned pieces are detected during generation. Illegal moves are never generated:
// pinDirection[side][square] indicates if a piece is pinned
// and in which direction
Each move contains flags indicating:
if (sq & 0x88) continueFor a complete technical analysis of the code, see ANALISIS.md.
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
The project includes a comprehensive Perft test suite to validate move generation correctness and measure performance.
# 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 specific generator
node tests/perft-test.js --generator rust-bb --depth 6
node tests/perft-test.js [options]
Options:
--generator <x88|bb|as|rust-x88|rust-bb|all> Select generator to test (default: all)
--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
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 |
Chess Move Generator - Perft Test Suite
Configuration:
Generator: all
Positions: 7
Max depth: 4
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Total tests: 140 (5 generators * 7 positions * 4 depths)
Passed: 140
Failed: 0
Pass rate: 100.0%
README.CI workflow automatically runs quick tests (npm test) on push and pull_request. Full bitboard tests (npm run test:bb) are configured for manual execution to avoid long runs on every push.How to launch the full test from GitHub UI:
CI workflow.main or master), and execute.Using the gh CLI (GitHub CLI):
gh workflow run ci.yml --ref main
Note: The CI workflow includes a matrix of Node versions for quick tests and reserves a manual job (test-bitboard-full) with a longer timeout for intensive testing.
Contributions are welcome. Please:
git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)This project is under the MIT License - see the LICENSE file for details.
Mario Raรบl Carbonell Martรญnez
โญ If you find this project useful, consider giving it a star on GitHub!