cm-engine-runner 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +10 -0
- package/CLAUDE.md +57 -0
- package/index.html +2 -2
- package/package.json +3 -2
- package/src/StockfishRunner.js +3 -2
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
cm-engine-runner is a lightweight JavaScript library for running chess engines in the browser. It provides an abstraction layer supporting multiple backends: Stockfish (via WebWorkers) and Polyglot opening books.
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
npm install
|
|
14
|
+
|
|
15
|
+
# Run the demo/test page
|
|
16
|
+
# Open index.html in a browser (uses importmap for ES6 module resolution)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
No build step is required - the library uses pure ES6 modules that run directly in browsers.
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
The project uses an **adapter pattern** with a base class and engine-specific implementations:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
EngineRunner (base class)
|
|
27
|
+
├── StockfishRunner → WebWorker → Stockfish WASM engine
|
|
28
|
+
└── PolyglotRunner → cm-polyglot → Opening book (.bin)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Core Files
|
|
32
|
+
|
|
33
|
+
- `src/EngineRunner.js` - Abstract base class defining the interface and state machine (`ENGINE_STATE`: LOADING, LOADED, READY, THINKING)
|
|
34
|
+
- `src/StockfishRunner.js` - Stockfish adapter implementing UCI protocol communication, skill levels 1-20 with depth mapping
|
|
35
|
+
- `src/PolyglotRunner.js` - Polyglot opening book reader with probability-weighted move selection
|
|
36
|
+
- `engines/stockfish-v10-niklasf.js` - Compiled Stockfish v10 engine (runs in WebWorker)
|
|
37
|
+
|
|
38
|
+
### API Pattern
|
|
39
|
+
|
|
40
|
+
All adapters share this interface:
|
|
41
|
+
```javascript
|
|
42
|
+
runner.calculateMove(fen, props) → Promise<{from, to, promotion?, score?, ponder?}>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Adding a New Engine
|
|
46
|
+
|
|
47
|
+
1. Extend `EngineRunner` class
|
|
48
|
+
2. Implement `init()` to set up the engine
|
|
49
|
+
3. Implement `calculateMove(fen, props)` returning a Promise with move data
|
|
50
|
+
4. Manage engine state via `ENGINE_STATE` constants
|
|
51
|
+
|
|
52
|
+
## Key Implementation Details
|
|
53
|
+
|
|
54
|
+
- Uses `importmap` in index.html for browser-based ES6 module resolution (no bundler)
|
|
55
|
+
- StockfishRunner communicates with the engine via `postMessage` using UCI protocol
|
|
56
|
+
- `responseDelay` prop adds artificial delay for UX purposes
|
|
57
|
+
- `debug` prop enables console logging
|
package/index.html
CHANGED
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
const positionEndGame = "8/8/8/2k5/4K3/8/8/8"
|
|
34
34
|
console.log("polyglot", positionEndGame, await polyglotRunner.calculateMove(positionEndGame))
|
|
35
35
|
|
|
36
|
-
const stockfishRunner = new StockfishRunner({workerUrl: "./
|
|
36
|
+
const stockfishRunner = new StockfishRunner({workerUrl: "./node_modules/stockfish/src/stockfish-17.1-lite-single-03e3232.js", responseDelay: 0, debug: true})
|
|
37
37
|
console.log("stockfish", await stockfishRunner.calculateMove(startingFewMoves))
|
|
38
38
|
const postitionBlackWillWin = "4k3/3r4/8/8/8/8/6K1/8 w - - 0 1"
|
|
39
39
|
console.log("stockfish", await stockfishRunner.calculateMove(postitionBlackWillWin, {level: 1}))
|
|
40
|
-
console.log("stockfish", await stockfishRunner.calculateMove(postitionBlackWillWin, {level:
|
|
40
|
+
console.log("stockfish", await stockfishRunner.calculateMove(postitionBlackWillWin, {level: 20}))
|
|
41
41
|
|
|
42
42
|
const positionManyPawns = "ppppkppp/pppppppp/pppppppp/pppppppp/8/5N2/8/RNBQKB1R b KQ - 0 1"
|
|
43
43
|
console.log("stockfish", await stockfishRunner.calculateMove(positionManyPawns, {level: 3}))
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cm-engine-runner",
|
|
3
3
|
"description": "Abstraction layer to run chess engines, supports opening books",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"teevi": "^2.2.4"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"cm-polyglot": "^1.1.0"
|
|
30
|
+
"cm-polyglot": "^1.1.0",
|
|
31
|
+
"stockfish": "^17.1.0"
|
|
31
32
|
}
|
|
32
33
|
}
|
package/src/StockfishRunner.js
CHANGED
|
@@ -80,8 +80,8 @@ export class StockfishRunner extends EngineRunner {
|
|
|
80
80
|
}
|
|
81
81
|
this.score = tmpScore
|
|
82
82
|
}
|
|
83
|
-
// match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([
|
|
84
|
-
match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([
|
|
83
|
+
// match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([qrbk])?/) // ponder is not always included
|
|
84
|
+
match = line.match(/^bestmove ([a-h][1-8])([a-h][1-8])([qrbk])?( ponder ([a-h][1-8])?([a-h][1-8])?)?/)
|
|
85
85
|
if (match) {
|
|
86
86
|
this.engineState = ENGINE_STATE.READY
|
|
87
87
|
if (match[4] !== undefined) {
|
|
@@ -103,6 +103,7 @@ export class StockfishRunner extends EngineRunner {
|
|
|
103
103
|
|
|
104
104
|
calculateMove(fen, props = { level: 4 }) {
|
|
105
105
|
this.engineState = ENGINE_STATE.THINKING
|
|
106
|
+
this.score = undefined // Reset score to avoid carrying over stale values
|
|
106
107
|
const timeoutPromise = new Promise((resolve) => {
|
|
107
108
|
setTimeout(async () => {
|
|
108
109
|
resolve()
|