项目作者: medegw01

项目描述 :
A JavaScript chess engine that is used for chess position evaluation; best move search; move generation or validation; piece placement or movement; check, checkmate, stalemate, and insufficient material detection.
高级语言: JavaScript
项目地址: git://github.com/medegw01/raccoon.js.git
创建时间: 2020-02-05T04:26:33Z
项目社区:https://github.com/medegw01/raccoon.js

开源协议:GNU General Public License v3.0

下载


raccoon.js 🦝

Build Status

raccoon.js is a JavaScript chess engine that is used for chess position evaluation; best move search; move generation
or validation; piece placement or movement; check, checkmate, stalemate, and insufficient material detection.

raccoon.js has been extensively tested in node.js and most modern browsers.

Example Code

The code below plays a complete game of chess … randomly.

  1. let { Raccoon } = require('./raccoon.js');
  2. let raccoon = new Raccoon();
  3. while (!raccoon.game_over()) {
  4. let moves = raccoon.moves();
  5. let move = moves[Math.floor(Math.random() * moves.length)];
  6. raccoon.move(move);
  7. }
  8. console.log(raccoon.ascii()) /* replace with pgn */

This can also be used as a UCI chess engine via Workers. Below show how this can be done

  1. let raccoon = new Worker('raccoon.js');
  2. raccoon.onmessage = function (e) {
  3. $('#dump').append(e.data); //receive message from raccoon engine
  4. };
  5. /* send UCI commands as in below */
  6. raccoon.postMessage('uci');
  7. raccoon.postMessage('ucinewgame');
  8. raccoon.postMessage('position startpos');
  9. raccoon.postMessage('go depth 10');

For more information on UCI Protocol, visit UCIProtocol

Need a user interface? Try Chris Oakman’s excellent
chessboard.js library. See My personal Website
and the Integration Source code

API

Constructor: Raccoon([ fen ])

The Raccoon() constructor takes an optional parameter which specifies the board configuration
in Forsyth-Edwards Notation.

  1. // board defaults to the starting position when called with no parameters
  2. let raccoon = new Raccoon();
  3. // pass in a FEN string to load a particular position and/or path to opening book
  4. let raccoon = new Raccoon(
  5. 'r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1'
  6. );

.ascii()

Returns a string containing an ASCII diagram of the current position.

  1. let raccoon = new Raccoon('rnbqkbnr/p3pppp/2p5/1pPp4/3P4/8/PP2PPPP/RNBQKBNR w KQkq b6 0 4');
  2. raccoon.ascii();
  3. // => +-----------------+
  4. // 8| r n b q k b n r |
  5. // 7| p . . . p p p p |
  6. // 6| . . p . . . . . |
  7. // 5| . p P p . . . . |
  8. // 4| . . . P . . . . |
  9. // 3| . . . . . . . . |
  10. // 2| P P . . P P P P |
  11. // 1| R N B Q K B N R |
  12. // +-----------------+
  13. // a b c d e f g h
  14. // INFO
  15. // turn: w
  16. // enpass: 72
  17. // castling: KQkq
  18. // poly key: 0xf5b10215c5fb8d1e

.clear()

Clears the board.

  1. raccoon.clear();
  2. raccoon.fen();
  3. // => '8/8/8/8/8/8/8/8 w - - 0 1' <- empty board

.fen()

Returns the FEN string for the current position.

  1. let raccoon = new Raccoon();
  2. // make some moves
  3. raccoon.move('e4');
  4. raccoon.move('e5');
  5. raccoon.move('Nf4');
  6. chess.fen();
  7. // => 'rnbqkbnr/pppp1ppp/8/4p3/4P3/2N5/PPPP1PPP/R1BQKBNR b KQkq - 1 2'

.game_over()

Returns true if the game has ended via checkmate, stalemate, draw, threefold repetition, or insufficient material. Otherwise, returns false.

  1. let raccoon = new Raccoon();
  2. raccoon.game_over();
  3. // => false
  4. // stalemate
  5. raccoon.load('1R6/8/8/8/8/8/7R/k6K b - - 0 1');
  6. raccoon.game_over();
  7. // => true
  8. // checkmate
  9. raccoon.load('r3k2r/ppp2p1p/2n1p1p1/8/2B2P1q/2NPb1n1/PP4PP/R2Q3K w kq - 0 8')
  10. raccoon.game_over();
  11. // => true

.get(square)

Returns the piece on the square:

  1. let raccoon = new Raccoon();
  2. raccoon.clear();
  3. raccoon.put({ type: 'p', color: 'b' }, 'a5'); // put a black pawn on a5
  4. raccoon.get('a5');
  5. // => { type: 'p', color: 'b' },
  6. raccoon.get('a6');
  7. // => null

.history([ options ])

Returns a list containing the moves of the current game in SAN. Options is an optional
parameter which may contain a ‘verbose’ flag. See .moves() for a description of the
verbose move fields.

  1. let raccoon = new Raccoon();
  2. raccoon.move('e4');
  3. raccoon.move('e5');
  4. raccoon.move('f4');
  5. raccoon.move('exf4');
  6. raccoon.history();
  7. // => ['e4', 'e5', 'f4', 'exf4']
  8. raccoon.history({ verbose: true });
  9. // => [{ color: 'w', from: 'e2', to: 'e4', flags: 'b', piece: 'p', san: 'e4' },
  10. // { color: 'b', from: 'e7', to: 'e5', flags: 'b', piece: 'p', san: 'e5' },
  11. // { color: 'w', from: 'f2', to: 'f4', flags: 'b', piece: 'p', san: 'f4' },
  12. // { color: 'b', from: 'e5', to: 'f4', flags: 'c', piece: 'p', captured: 'p', san: 'exf4' }]

.in_check()

Returns true or false if the side to move is in check.

  1. let raccoon = new Raccoon(
  2. 'rnb1kbnr/pppp1ppp/8/4p3/5PPq/8/PPPPP2P/RNBQKBNR w KQkq - 1 3'
  3. );
  4. raccoon.in_check();
  5. // => true

.in_checkmate()

Returns true or false if the side to move has been checkmated.

  1. let raccoon = new Raccoon(
  2. 'rnb1kbnr/pppp1ppp/8/4p3/5PPq/8/PPPPP2P/RNBQKBNR w KQkq - 1 3'
  3. );
  4. raccoon.in_checkmate();
  5. // => true

.in_draw()

Returns true or false if the game is drawn (50-move rule or insufficient material).

  1. let raccoon = new Raccoon('4k3/4P3/4K3/8/8/8/8/8 b - - 0 78');
  2. raccoon.in_draw();
  3. // => true

.in_stalemate()

Returns true or false if the side to move has been stalemated.

  1. let raccoon = new Raccoon('4k3/4P3/4K3/8/8/8/8/8 b - - 0 78');
  2. raccoon.in_stalemate();
  3. // => true

.in_threefold_repetition()

Returns true or false if the current board position has occurred three or more
times.

  1. let raccoon = new Raccoon('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
  2. // rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq occurs 1st time
  3. raccoon.in_threefold_repetition();
  4. // => false
  5. raccoon.move('Nf3');
  6. raccoon.move('Nf6');
  7. raccoon.move('Ng1');
  8. raccoon.move('Ng8');
  9. // rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq occurs 2nd time
  10. raccoon.in_threefold_repetition();
  11. // => false
  12. raccoon.move('Nf3');
  13. raccoon.move('Nf6');
  14. raccoon.move('Ng1');
  15. raccoon.move('Ng8');
  16. // rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq occurs 3rd time
  17. raccoon.in_threefold_repetition();
  18. // => true

.insufficient_material()

Returns true if the game is drawn due to insufficient material; otherwise false.

  1. let raccoon = new Raccoon('8/b7/B7/8/8/8/8/k6K w - - 0 1');
  2. raccoon.insufficient_material()
  3. // -> true

.load(fen)

The board is cleared, and the FEN string is loaded. Returns {value: true, error: “no error!”} if the position was
successfully loaded, otherwise {value: false, error: “some specific error”}.

  1. let raccoon = new Raccoon();
  2. raccoon.load('8/b7/B7/8/8/8/8/k6K w - - 0 1');
  3. // => {value: true, error: "no error!"}
  4. raccoon.load('8/T7/B7/8/8/8/8/k6K w - - 0 1')
  5. // => {value: false, error: "Illegal character T"}

.polyglot()

Get the polyglot key of current function. See polyglot for more info

  1. raccoon.load('rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2');
  2. raccoon.polyglot();
  3. // => 0x0756b94461c50fb0

.move(move, [ options ])

Attempt to make a move. If successfully, return the move object. Otherwise return null. I can take a move object as shown below
or a move string in most common chess notations.

  1. let raccoon = new Raccoon();
  2. let same_moves = [
  3. 'e2e4', 'Pe2e4', 'e2-e4', 'e4', { from: 'e2', to: '34' },
  4. ];
  5. // all the different move notations above represent the same move. The second to the last is SAN notation
  6. for(let mv of same_moves){
  7. raccoon.move(mv);
  8. // => {from: "e2", to: "e4", color: "w", pieces: "p", flag: "b", san: "e4"}
  9. raccoon.undo();
  10. // => {from: "e2", to: "e4", color: "w", pieces: "p", flag: "b", san: "e4"}
  11. }
  12. raccoon.move("a1a1"); //-- invalid move
  13. //=> null

.moves([ options ])

Returns a list of legal moves from the current position in smith notation. If verbose is set to true, it return the moves
in a detailed object explained below.

  1. let raccoon = new Raccoon();
  2. raccoon.moves();
  3. // => ["a2a3", "a2a4", "b2b3", "b2b4", "c2c3", "c2c4", "d2d3", "d2d4", "e2e3", "e2e4", "f2f3", "f2f4", "g2g3", "g2g4",
  4. // "h2h3", "h2h4", "b1a3", "b1c3", "g1f3", "g1h3"]
  5. raccoon.moves({ verbose: true })
  6. // => [{ from: "a2"
  7. // to: "a3",
  8. // color: "w",
  9. // pieces: "p",
  10. // flag: "n",
  11. // san: "a3",
  12. // },
  13. // ...
  14. // ]

The piece, captured, and promotion fields contain the lowercase
representation of the applicable piece.

The flags field in verbose mode may contain one or more of the following values:

  • ‘n’ - a non-capture
  • ‘b’ - a pawn push of two squares
  • ‘e’ - an en passant capture
  • ‘c’ - a standard capture
  • ‘p’ - a promotion
  • ‘pc’ - promotion with a capture
  • ‘k’ - kingside castling
  • ‘q’ - queenside castling

A flag of ‘pc’ would mean that a pawn captured a piece on the 8th rank and promoted.

.put(piece, square)

Place a piece on the square where piece is an object with the form
{ type: …, color: … }. Returns true if the piece was successfully placed,
otherwise, the board remains unchanged and false is returned. put() will fail
when passed an invalid piece or square, or when two or more kings of the
same color are placed.

type can be:(not case sensitive)

  • ‘k’ or ‘K’ - king
  • ‘q’ or ‘Q’ - queen
  • ‘r’ or ‘R’ - rook
  • ‘b’ or ‘B’ - bishop
  • ‘n’ or ‘N’ - knight
  • ‘p’ or ‘P’ - pawn

color can be: case sensitive

  • ‘w’ - white
  • ‘b’ - black
  1. raccoon.clear();
  2. raccoon.put({type: 'r', color: 'w'}, 'e4'); // put a white rook on e4
  3. // => true
  4. raccoon.put({type: 'm', color: 'w'}, 'e4'); // invalid piece
  5. // => false
  6. raccoon.put({type: 'k', color: 'w'}, 'e6'); // can not have more than one king
  7. // => false

.remove(square)

Remove and return the piece on square.

  1. raccoon.clear();
  2. raccoon.put({type: 'r', color: 'w'}, 'e4'); // put a white rook on e4
  3. raccoon.put({type: 'k', color: 'b'}, 'e6'); // put white king on e6
  4. raccoon.remove('e4');
  5. // -> { type: 'r', color: 'w' },
  6. raccoon.remove('e6');
  7. // -> { type: 'k', color: 'w' },
  8. raccoon.remove('e6');// board is now empty
  9. // -> null

.reset()

Reset the board to the initial starting position.

.square_color(square)

Returns the color of the square (‘light’ or ‘dark’).

  1. let raccoon = new Raccoon();
  2. raccoon.square_color('h1');
  3. // => 'light'
  4. raccoon.square_color('a7');
  5. // => 'dark'
  6. raccoon.square_color('bogus square');
  7. // => null

.turn()

Returns the current side to move.

  1. raccoon.load('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1');
  2. raccoon.turn();
  3. // -> 'b'

.undo()

Takeback the last half-move, returning a move object if successful, otherwise null.

  1. let raccoon = new Raccoon();
  2. raccoon.undo();
  3. // -> null
  4. raccoon.move('e4');
  5. chess.undo();
  6. // => { color: 'w', from: 'e2', to: 'e4', flags: 'b', piece: 'p', san: 'e4' }

.perft(depth)

A debugging function to walk the move generation tree of strictly legal moves and count all the leaf nodes to depth

  1. let raccoon = new Raccoon();
  2. raccoon.load('8/PPP4k/8/8/8/8/4Kppp/8 w - - 0 1');
  3. raccoon.perft(4);
  4. // => 89363

.perft_summary(depth)

Works exactly as .perft(depth) but prints out more details to console.

  1. raccoon.perft_summary(4);
  2. /** CONSOLE.LOG
  3. About to start perf testing, with depth: 4
  4. raccoon.js:2065 move: 1 c7c8q 6006
  5. raccoon.js:2065 move: 2 c7c8r 5937
  6. raccoon.js:2065 move: 3 c7c8b 4995
  7. raccoon.js:2065 move: 4 c7c8n 4619
  8. raccoon.js:2065 move: 5 b7b8q 5697
  9. raccoon.js:2065 move: 6 b7b8r 6149
  10. raccoon.js:2065 move: 7 b7b8b 3744
  11. raccoon.js:2065 move: 8 b7b8n 4568
  12. raccoon.js:2065 move: 9 a7a8q 5900
  13. raccoon.js:2065 move: 10 a7a8r 6196
  14. raccoon.js:2065 move: 11 a7a8b 3648
  15. raccoon.js:2065 move: 12 a7a8n 3924
  16. raccoon.js:2065 move: 13 e2d2 5568
  17. raccoon.js:2065 move: 14 e2f2 2630
  18. raccoon.js:2065 move: 15 e2e3 5911
  19. raccoon.js:2065 move: 16 e2d1 3051
  20. raccoon.js:2065 move: 17 e2f3 5031
  21. raccoon.js:2065 move: 18 e2d3 5789
  22. raccoon.js:2067 Total nodes: 89363
  23. **/
  24. // => 89363

.set_book(arrayBuffer)

A functions that allows you tho send the chess book used by the engine. The book should first be send in the form of
arrayBuffer. One way to open a book is,

  1. let bookBuffer = null;
  2. var bookRequest = new XMLHttpRequest();
  3. bookRequest.open('GET', 'book.bin', true);
  4. bookRequest.responseType = "arraybuffer";
  5. bookRequest.onload = function(event) {
  6. if(bookRequest.status == 200){
  7. bookBuffer = bookRequest.response;
  8. engine.postMessage({book: bookRequest.response});
  9. }
  10. };
  11. bookRequest.send(null);
  12. if(bookBuffer){
  13. // can be used via API
  14. let raccoon = new Raccoon();
  15. raccoon.set_book(bookBuffer);
  16. //OR via worker as
  17. let engine = Worker("racccon.js");
  18. engine.postMessage({book: bookBuffer}); //This is a work around and not an actual UCI command
  19. }

.evaluation() NOT COMPLETED

An evaluation function used to heuristically determine the relative value of a positions, i.e. the chances of winning.
If we could see to the end of the game in every line, the evaluation would only have values of -inf (loss), 0 (draw),
and +inf (win). It considers psqt table, imbalance, pawns, pieces, material value, mobility, threat,
passed, space, and king.

TODO

  • finish threat
  • passed pawn evaluation
  • space check
  • king safety
  1. let raccoon = new Raccoon();
  2. raccoon.evaluation(); // Positive score for white as it has the tempo
  3. //=> 28

.search(option) NOT COMPLETED

TODO

  • Transposition table
  • Static Exchange Evaluation(See)
  • Quiescence search
  • Alpha-beta search
    1) Aspiration window
    2) Interactive deepening
    3) Null move reduction
    4) Razoring pruning
    5) Futility pruning
    6) Late Move Reduction
    7) Late move pruning
    8) History futility pruning
  • Move Ordering
    1) Most value victim / Lowest Value Attacker
    2) Killer moves
    3) Butterfly history

Overall Game TODO

For optimization

  • Bitboard representation
  • Magic bitboard
  • UCI protocol