marcos-projects

Sjeng for the browser

This folder is the complete source of the chess engine in Marco’s Chess. It is Sjeng 11.2 by Gian-Carlo Pascutto, the engine that macOS Chess runs, compiled to WebAssembly. build.sh turns it into ../js/sjeng/sjeng.js and ../js/sjeng/sjeng.wasm.

Licensing: GPL-3.0-or-later. See ../NOTICE.md and ../LICENSE.

Where it comes from

src/ and books/ are copied from Apple’s open-source macOS Chess: apple-oss-distributions/Chess at tag Chess-570.1 (commit 6b3de1f4f307f265b09720f0aa53689248c67a29), folder sjeng/.

What was changed

Each change is marked in the source with “WebAssembly build” or “Fixed”, and each changed file says so in its header.

File Change Why
src/sjeng.c sd now reads its number: sscanf(input+3, …) instead of sscanf(input, …). A bug in Apple’s copy. The scan starts at the letters “sd”, so it never reads the depth, and the maximum stays 40. macOS Chess sets its strength only with sd, so its strength slider never changes how the engine plays.
src/sjeng.c <machine/endian.h> became <endian.h>. That header only exists on macOS, and nothing in the file uses it.
src/sjeng.h Includes <sys/time.h> itself. macOS’s headers pulled it in indirectly; Emscripten’s do not.
src/config.h HAVE_SELECT is off. A browser has no stdin for the engine to poll. The cost: Sjeng can’t read input in the middle of a search. So the page sends easy (no thinking on your time), and “Move now” restarts the engine.
src/utils.c rinput() takes commands from the page. In the browser, commands arrive as messages, not on stdin.
wasm/browser_io.c New. Pauses the engine until the page sends the next command (Emscripten Asyncify).
wasm/ndbm.h, wasm/ndbm_stub.c New. Apple’s Sjeng can open an optional ndbm “BinBook” opening book. Browsers have no ndbm, so dbm_open() always fails. Sjeng then uses the .opn books.

Build settings in build.sh:

How the page talks to it

The page uses the same xboard commands that macOS Chess sends to this engine: xboard, confirm_moves, new, force, the moves, sd, go. It also sends level to set the thinking time and easy (see HAVE_SELECT above). See ../js/sjeng-worker.js and ../js/ui/engine-client.js.

Build

You need Docker. The script uses the pinned image emscripten/emsdk:6.0.12.

cd marco-chess/sjeng && ./build.sh

Tests

node --test marco-chess/tests/sjeng.test.mjs

These tests run the compiled engine in Node. On a Mac they also send the same commands to sjeng.ChessEngine inside Chess.app and check that both engines give the same replies and moves. The one expected difference is the depth that sd 4 sets: 4 here, 40 in Chess.app.