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
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
Or open engine.html in your browser locally.
๐ฆ Installation
NPM
npm install chess-movegen-jsUsage
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 engineisready- Check availabilityucinewgame- New gameposition [fen|startpos] [moves ...]- Set positionmove <move>- Make move (e.g., e2e4)undo- Unmake moveperft <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 direction2. 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
x88 (Recommended for learning)
- 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 6Available 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 messageTest 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 outthis.debug()calls in production.
Troubleshooting
If tests fail or show errors:
- Ensure Node.js is installed: The tests require Node.js v14 or higher
- Check all files are present: Make sure
tests/directory exists with all test files - 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
CIcorre los tests rรกpidos (npm test) automรกticamente enpushypull_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:
- Ve a la pestaรฑa Actions del repositorio.
- Selecciona el workflow
CI. - Pulsa Run workflow, elige la rama (
mainomaster) y ejecuta.
Usando la CLI gh (GitHub CLI) puedes lanzar el workflow asรญ:
gh workflow run ci.yml --ref mainNota: 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:
- Fork the project
- Create a branch for your feature (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - 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!