Home

Awesome

scalachess.js

scalachess.js is a chess library that runs in a webworker, with multi-variants support.

It is based on the awesome scalachess library compiled to JavaScript, thanks to Scala.js.

It is currently used in production in lichess.org mobile application. So you can see a real world usage on the mobile app repo.

Features

Build

$ git submodule update --init
$ ./build.sh

Generated file will be in build dir.

API

Message Format

The same format is used for requests and responses:

interface ScalachessMessage {
  topic: string
  payload?: Object
  reqid?: string
}

The worker will always reply with the same topic field of the request. payload is either request or response data. The optional reqid can be used to differentiate responses if you are sending a lot of requests with the same topic at the same time.

Topics

An up-to-date and complete API documentation for all topics can be found in the typescript interfaces of lichess mobile client.

Init

Request:

chessWorker.postMessage({
  topic: 'init',
  payload: {
    variant: 'chess960'
  }
});

Response:

{
    "payload": {
        "setup": {
            "check": false,
            "dests": {
              "a2": [ "a3", "a4" ], "b2": [ "b3", "b4" ], "c1": [ "b3", "d3" ], "c2": [ "c3", "c4" ], "d2": [ "d3", "d4" ], "e2": [ "e3", "e4" ], "f2": [ "f3", "f4" ], "g2": [ "g3", "g4" ], "h1": [ "g3" ], "h2": [ "h3", "h4" ]
            },
            "fen": "rbnkbqrn/pppppppp/8/8/8/8/PPPPPPPP/RBNKBQRN w KQkq - 0 1",
            "pgnMoves": [],
            "playable": true,
            "player": "white",
            "ply": 0
        },
        "variant": {
            "key": "chess960",
            "name": "Chess960",
            "shortName": "960",
            "title": "Starting position of the home rank pieces is randomized."
        }
    },
    "topic": "init"
}

Dests

Request:

chessWorker.postMessage({
  topic: 'dests',
  payload: {
    fen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
    variant: 'kingOfTheHill'
  }
});

Response:

{
    "payload": {
        "dests": {
            "a2": [ "a3", "a4" ], "b1": [ "a3", "c3" ], "b2": [ "b3", "b4" ], "c2": [ "c3", "c4" ], "d2": [ "d3", "d4" ], "e2": [ "e3", "e4" ], "f2": [ "f3", "f4" ], "g1": [ "f3", "h3" ], "g2": [ "g3", "g4" ], "h2": [ "h3", "h4" ]
        }
    },
    "topic": "dests"
}

Move

Request:

worker.postMessage({
  topic: 'move',
  payload: {
    fen: 'rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2 +0+0',
    variant: 'threeCheck',
    pgnMoves: ['e4', 'e5'],
    uciMoves: ['e2e4', 'e7e5'],
    orig: 'd2',
    dest: 'd4',
    path: '0'
  },
  reqid: '1'
});

Response:

{
    "reqid": "1",
    "path": "0",
    "situation": {
        "check": false,
        "checkCount": {
            "black": 0,
            "white": 0
        },
        "dests": {
            "a7": [ "a6", "a5" ], "b7": [ "b6", "b5" ], "b8": [ "a6", "c6" ], "c7": [ "c6", "c5" ], "d7": [ "d6", "d5" ], "d8": [ "e7", "f6", "g5", "h4" ], "e5": [ "d4" ], "e8": [ "e7" ], "f7": [ "f6", "f5" ], "f8": [ "e7", "d6", "c5", "b4", "a3" ], "g7": [ "g6", "g5" ], "g8": [ "e7", "f6", "h6" ], "h7": [ "h6", "h5" ]
        },
        "end": false,
        "fen": "rnbqkbnr/pppp1ppp/8/4p3/3PP3/8/PPP2PPP/RNBQKBNR b KQkq - 0 2 +0+0",
        "pgnMoves": [
            "e4", "e5", "d4"
        ],
        "playable": true,
        "player": "black",
        "ply": 3,
        "uciMoves": [
            "e2e4", "e7e5", "d2d4"
        ],
        "variant": "threeCheck"
    }
}

pgnRead

Request


var pgn = '[Event "Fischer - Spassky World Championship Match"]\n' +
'[Site "Reykjavik ISL"]\n' +
'[Date "1972.08.22"]\n' +
'[EventDate "?"]\n' +
'[Round "17"]\n' +
'[Result "1/2-1/2"]\n' +
'[White "Boris Spassky"]\n' +
'[Black "Robert James Fischer"]\n' +
'[ECO "B09"]\n' +
'[WhiteElo "?"]\n' +
'[BlackElo "?"]\n' +
'[PlyCount "89"]\n' +
'\n' +
'1. e4 d6 2. d4 g6 3. Nc3 Nf6 4. f4 Bg7 5. Nf3 c5 6. dxc5 Qa5\n' +
'7. Bd3 Qxc5 8. Qe2 O-O 9. Be3 Qa5 10. O-O Bg4 11. Rad1 Nc6\n' +
'12. Bc4 Nh5 13. Bb3 Bxc3 14. bxc3 Qxc3 15. f5 Nf6 16. h3 Bxf3\n' +
'17. Qxf3 Na5 18. Rd3 Qc7 19. Bh6 Nxb3 20. cxb3 Qc5+ 21. Kh1\n' +
'Qe5 22. Bxf8 Rxf8 23. Re3 Rc8 24. fxg6 hxg6 25. Qf4 Qxf4\n' +
'26. Rxf4 Nd7 27. Rf2 Ne5 28. Kh2 Rc1 29. Ree2 Nc6 30. Rc2 Re1\n' +
'31. Rfe2 Ra1 32. Kg3 Kg7 33. Rcd2 Rf1 34. Rf2 Re1 35. Rfe2 Rf1\n' +
'36. Re3 a6 37. Rc3 Re1 38. Rc4 Rf1 39. Rdc2 Ra1 40. Rf2 Re1\n' +
'41. Rfc2 g5 42. Rc1 Re2 43. R1c2 Re1 44. Rc1 Re2 45. R1c2\n' +
'1/2-1/2';

worker.postMessage({
  topic: 'pgnRead',
  payload: {
    pgn: pgn
  }
});

Response

{
    "replay": [
        {
            "check": false,
            "checkCount": {
                "black": 0,
                "white": 0
            },
            "dests": {
                "a2": [ "a3", "a4" ], "b1": [ "a3", "c3" ], "b2": [ "b3", "b4" ], "c2": [ "c3", "c4" ], "d2": [ "d3", "d4" ], "e2": [ "e3", "e4" ], "f2": [ "f3", "f4" ], "g1": [ "f3", "h3" ], "g2": [ "g3", "g4" ], "h2": [ "h3", "h4" ]
            },
            "end": false,
            "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
            "pgnMoves": [],
            "playable": true,
            "player": "white",
            "ply": 0,
            "uciMoves": [],
            "variant": "standard"
        },
        {
            "check": false,
            "checkCount": {
                "black": 0,
                "white": 0
            },
            "dests": {
                "a7": [ "a6", "a5" ], "b7": [ "b6", "b5" ], "b8": [ "a6", "c6" ], "c7": [ "c6", "c5" ], "d7": [ "d6", "d5" ], "e7": [ "e6", "e5" ], "f7": [ "f6", "f5" ], "g7": [ "g6", "g5" ], "g8": [ "f6", "h6" ], "h7": [ "h6", "h5" ]
            },
            "end": false,
            "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1",
            "pgnMoves": [
                "e4"
            ],
            "playable": true,
            "player": "black",
            "ply": 1,
            "uciMoves": [
                "e2e4"
            ],
            "variant": "standard"
        },
        {
            "check": false,
            "checkCount": {
                "black": 0,
                "white": 0
            },
            "dests": {
                "a2": [ "a3", "a4" ], "b1": [ "a3", "c3" ], "b2": [ "b3", "b4" ], "c2": [ "c3", "c4" ], "d1": [ "e2", "f3", "g4", "h5" ], "d2": [ "d3", "d4" ], "e1": [ "e2" ], "e4": [ "e5" ], "f1": [ "e2", "d3", "c4", "b5", "a6" ], "f2": [ "f3", "f4" ], "g1": [ "f3", "h3", "e2" ], "g2": [ "g3", "g4" ], "h2": [ "h3", "h4" ]
            },
            "end": false,
            "fen": "rnbqkbnr/ppp1pppp/3p4/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2",
            "pgnMoves": [
                "e4",
                "d6"
            ],
            "playable": true,
            "player": "white",
            "ply": 2,
            "uciMoves": [
                "d7d6"
            ],
            "variant": "standard"
        },
        {
            "check": false,
            "checkCount": {
                "black": 0,
                "white": 0
            },
            "dests": {
                "a7": [ "a6", "a5" ], "b7": [ "b6", "b5" ], "b8": [ "d7", "a6", "c6" ], "c7": [ "c6", "c5" ], "c8": [ "d7", "e6", "f5", "g4", "h3" ], "d6": [ "d5" ], "d8": [ "d7" ], "e7": [ "e6", "e5" ], "e8": [ "d7" ], "f7": [ "f6", "f5" ], "g7": [ "g6", "g5" ], "g8": [ "f6", "h6" ], "h7": [ "h6", "h5" ]
            },
            "end": false,
            "fen": "rnbqkbnr/ppp1pppp/3p4/8/3PP3/8/PPP2PPP/RNBQKBNR b KQkq - 0 2",
            "pgnMoves": [
                "e4",
                "d6",
                "d4"
            ],
            "playable": true,
            "player": "black",
            "ply": 3,
            "uciMoves": [
                "d2d4"
            ],
            "variant": "standard"
        },
        ... // till up to ply 89
    ],
    "setup": {
        "check": false,
        "checkCount": {
            "black": 0,
            "white": 0
        },
        "dests": {
            "a2": [ "a3", "a4" ], "b1": [ "a3", "c3" ], "b2": [ "b3", "b4" ], "c2": [ "c3", "c4" ], "d2": [ "d3", "d4" ], "e2": [ "e3", "e4" ], "f2": [ "f3", "f4" ], "g1": [ "f3", "h3" ], "g2": [ "g3", "g4" ], "h2": [ "h3", "h4" ]
        },
        "end": false,
        "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
        "pgnMoves": [],
        "playable": true,
        "player": "white",
        "ply": 0,
        "uciMoves": [],
        "variant": "standard"
    },
    "variant": {
        "key": "standard",
        "name": "Standard",
        "shortName": "Std",
        "title": "Standard rules of chess (FIDE)"
    }
}