From 198117bb678d0e470bfa8118b06d05118f4f60b4 Mon Sep 17 00:00:00 2001 From: QueensGambit Date: Tue, 8 Sep 2020 23:45:05 +0200 Subject: [PATCH] Added functionality to ffish.js (closes #177) + board.fullmoveNumber() + board.isCheck() + board.isBikjang() + board.sanMove(notation) + board.variationSan(uciMoves) + board.variationSan(uciMoves, notation) + board.variationSan(uciMoves, notation, moveNumbers) + enum ffish.Notation + ffish.setOption() + ffish.setOptionInt() + ffish.setOptionBool() + ES6 module export --- Readme.md | 1 + src/ffishjs.cpp | 201 +++++++++++++++++++++++++++++++++++-------------- tests/js/README.md | 158 +++++++++++++++++++++++---------------- tests/js/package.json | 6 +- tests/js/test.js | 118 +++++++++++++++++++++++++++-- 5 files changed, 355 insertions(+), 129 deletions(-) diff --git a/Readme.md b/Readme.md index 97b8466..c246836 100644 --- a/Readme.md +++ b/Readme.md @@ -5,6 +5,7 @@ [![Build Status](https://travis-ci.org/ianfab/Fairy-Stockfish.svg?branch=master)](https://travis-ci.org/ianfab/Fairy-Stockfish) [![Build Status](https://ci.appveyor.com/api/projects/status/github/ianfab/Fairy-Stockfish?branch=master&svg=true)](https://ci.appveyor.com/project/ianfab/Fairy-Stockfish/branch/master) [![PyPI version](https://badge.fury.io/py/pyffish.svg)](https://badge.fury.io/py/pyffish) +[![NPM version](https://img.shields.io/npm/v/ffish.svg?sanitize=true)](https://www.npmjs.com/package/ffish) Fairy-Stockfish is a chess variant engine derived from [Stockfish](https://github.com/official-stockfish/Stockfish/) designed for the support of fairy chess variants and easy extensibility with more games. It can play various regional, historical, and modern chess variants as well as [games with user-defined rules](https://github.com/ianfab/Fairy-Stockfish/wiki/Variant-configuration). For [compatibility with graphical user interfaces](https://github.com/ianfab/Fairy-Stockfish/wiki/Usage) it supports the UCI, UCCI, USI, and CECP/XBoard protocols. diff --git a/src/ffishjs.cpp b/src/ffishjs.cpp index 73eb6b6..462c65a 100644 --- a/src/ffishjs.cpp +++ b/src/ffishjs.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "misc.h" #include "types.h" @@ -39,7 +40,7 @@ using namespace emscripten; -void initializeStockfish(std::string& uciVariant) { +void initialize_stockfish(std::string& uciVariant) { pieceMap.init(); variants.init(); UCI::init(Options); @@ -57,20 +58,21 @@ private: Position pos; Thread* thread; std::vector moveStack; - static bool sfInitialized; bool is960; public: + static bool sfInitialized; + Board(): Board("chess", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" , false) { } - Board(std::string uciVariant) { - init(uciVariant, "", is960); + Board(std::string uciVariant): + Board(uciVariant, "", false) { } Board(std::string uciVariant, std::string fen): - Board(uciVariant, fen , false) { + Board(uciVariant, fen, false) { } Board(std::string uciVariant, std::string fen, bool is960) { @@ -81,12 +83,12 @@ public: std::string moves = ""; bool first = true; for (const ExtMove& move : MoveList(this->pos)) { - if (first) { - moves = UCI::move(this->pos, move); - first = false; - } - else - moves += " " + UCI::move(this->pos, move); + if (first) { + moves = UCI::move(this->pos, move); + first = false; + } + else + moves += " " + UCI::move(this->pos, move); } return moves; } @@ -95,17 +97,17 @@ public: std::string movesSan = ""; bool first = true; for (const ExtMove& move : MoveList(this->pos)) { - if (first) { - movesSan = move_to_san(this->pos, move, NOTATION_SAN); - first = false; - } - else - movesSan += " " + move_to_san(this->pos, move, NOTATION_SAN); + if (first) { + movesSan = move_to_san(this->pos, move, NOTATION_SAN); + first = false; + } + else + movesSan += " " + move_to_san(this->pos, move, NOTATION_SAN); } return movesSan; } - int number_legal_moves() { + int number_legal_moves() const { return MoveList(pos).size(); } @@ -115,18 +117,17 @@ public: // TODO: This is a naive implementation which compares all legal SAN moves with the requested string. // If the SAN move wasn't found the position remains unchanged. Alternatively, implement a direct conversion. - void push_san(std::string sanMove) { - Move foundMove = MOVE_NONE; - for (const ExtMove& move : MoveList(pos)) { - if (sanMove == move_to_san(this->pos, move, NOTATION_SAN)) { - foundMove = move; - break; - } - } - if (foundMove != MOVE_NONE) - do_move(foundMove); - } - + void push_san(std::string sanMove) { + Move foundMove = MOVE_NONE; + for (const ExtMove& move : MoveList(pos)) { + if (sanMove == move_to_san(this->pos, move, NOTATION_SAN)) { + foundMove = move; + break; + } + } + if (foundMove != MOVE_NONE) + do_move(foundMove); + } void pop() { pos.undo_move(this->moveStack.back()); @@ -134,17 +135,17 @@ public: states->pop_back(); } - void reset() { - set_fen(v->startFen); - } + void reset() { + set_fen(v->startFen); + } - bool is_960() { - return is960; - } + bool is_960() const { + return is960; + } - std::string fen() const { - return this->pos.fen(); - } + std::string fen() const { + return this->pos.fen(); + } void set_fen(std::string fen) { resetStates(); @@ -157,26 +158,86 @@ public: return move_to_san(this->pos, UCI::to_move(this->pos, uciMove), NOTATION_SAN); } + std::string san_move(std::string uciMove, Notation notation) { + return move_to_san(this->pos, UCI::to_move(this->pos, uciMove), Notation(notation)); + } + std::string variation_san(std::string uciMoves) { + return variation_san(uciMoves, NOTATION_SAN, true); + } + + std::string variation_san(std::string uciMoves, Notation notation) { + return variation_san(uciMoves, notation, true); + } + + std::string variation_san(std::string uciMoves, Notation notation, bool moveNumbers) { + std::stringstream ss(uciMoves); + StateListPtr tempStates; + std::vector moves; + std::string variationSan = ""; + std::string uciMove; + bool first = true; + + while (std::getline(ss, uciMove, ' ')) { + moves.emplace_back(UCI::to_move(this->pos, uciMove)); + if (first) { + first = false; + if (moveNumbers) { + variationSan = std::to_string(fullmove_number()); + if (pos.side_to_move() == WHITE) + variationSan += ". "; + else + variationSan += "..."; + } + variationSan += move_to_san(this->pos, moves.back(), Notation(notation)); + } + else { + if (moveNumbers && pos.side_to_move() == WHITE) + variationSan += " " + std::to_string(fullmove_number()) + "."; + variationSan += " " + move_to_san(this->pos, moves.back(), Notation(notation)); + } + states->emplace_back(); + pos.do_move(moves.back(), states->back()); + } + + // recover initial state + for(auto rIt = std::rbegin(moves); rIt != std::rend(moves); ++rIt) { + pos.undo_move(*rIt); + } + + return variationSan; + } + // returns true for WHITE and false for BLACK - bool turn() { + bool turn() const { return !pos.side_to_move(); } - int halfmove_clock() { + int fullmove_number() const { + return pos.game_ply() / 2 + 1; + } + + int halfmove_clock() const { return pos.rule50_count(); } - int game_ply() { + int game_ply() const { return pos.game_ply(); } - bool is_game_over() { - for (const ExtMove& move : MoveList(pos)) { - return false; - } + bool is_game_over() const { + for (const ExtMove& move: MoveList(pos)) + return false; return true; } + bool is_check() const { + return pos.checkers(); + } + + bool is_bikjang() const { + return pos.bikjang(); + } + // TODO: return board in ascii notation // static std::string get_string_from_instance(const Board& board) { // } @@ -193,14 +254,14 @@ private: } void init(std::string& uciVariant, std::string fen, bool is960) { - if (!Board::sfInitialized) { - initializeStockfish(uciVariant); - Board::sfInitialized = true; - } + if (!Board::sfInitialized) { + initialize_stockfish(uciVariant); + Board::sfInitialized = true; + } this->v = variants.find(uciVariant)->second; this->resetStates(); if (fen == "") - fen = v->startFen; + fen = v->startFen; this->pos.set(this->v, fen, is960, &this->states->back(), this->thread); this->is960 = is960; } @@ -208,14 +269,19 @@ private: // returns the version of the Fairy-Stockfish binary std::string info() { - return engine_info(); + return engine_info(); } bool Board::sfInitialized = false; +template +void set_option(std::string name, T value) { + Options[name] = value; + Board::sfInitialized = false; +} + // binding code EMSCRIPTEN_BINDINGS(ffish_js) { - function("info", &info); class_("Board") .constructor<>() .constructor() @@ -231,11 +297,32 @@ EMSCRIPTEN_BINDINGS(ffish_js) { .function("is960", &Board::is_960) .function("fen", &Board::fen) .function("setFen", &Board::set_fen) - .function("sanMove", &Board::san_move) + .function("sanMove", select_overload(&Board::san_move)) + .function("sanMove", select_overload(&Board::san_move)) + .function("variationSan", select_overload(&Board::variation_san)) + .function("variationSan", select_overload(&Board::variation_san)) + .function("variationSan", select_overload(&Board::variation_san)) .function("turn", &Board::turn) + .function("fullmoveNumber", &Board::fullmove_number) .function("halfmoveClock", &Board::halfmove_clock) .function("gamePly", &Board::game_ply) - .function("isGameOver", &Board::is_game_over); - // TODO: enable to string conversion method - // .class_function("getStringFromInstance", &Board::get_string_from_instance); + .function("isGameOver", &Board::is_game_over) + .function("isCheck", &Board::is_check) + .function("isBikjang", &Board::is_bikjang); + // usage: e.g. ffish.Notation.DEFAULT + enum_("Notation") + .value("DEFAULT", NOTATION_DEFAULT) + .value("SAN", NOTATION_SAN) + .value("LAN", NOTATION_LAN) + .value("SHOGI_HOSKING", NOTATION_SHOGI_HOSKING) + .value("SHOGI_HODGES", NOTATION_SHOGI_HODGES) + .value("SHOGI_HODGES_NUMBER", NOTATION_SHOGI_HODGES_NUMBER) + .value("JANGGI", NOTATION_JANGGI) + .value("XIANGQI_WXF", NOTATION_XIANGQI_WXF); + function("info", &info); + function("setOption", &set_option); + function("setOptionInt", &set_option); + function("setOptionBool", &set_option); + // TODO: enable to string conversion method + // .class_function("getStringFromInstance", &Board::get_string_from_instance); } diff --git a/tests/js/README.md b/tests/js/README.md index 8d2f881..443368a 100644 --- a/tests/js/README.md +++ b/tests/js/README.md @@ -1,68 +1,60 @@ -# ffish.js +

ffish.js

-A high performance WebAssembly chess variant library based on _Fairy-Stockfish_. +

+Package +Downloads +Version +

-It is built using emscripten/Embind from C++ source code. +

+Package-ES6 +Downloads-ES6 +Version-ES6 +

-* https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + +The package **ffish.js** is a high performance WebAssembly chess variant library based on [_Fairy-Stockfish_](https://github.com/ianfab/Fairy-Stockfish). + +It is available as a [standard module](https://www.npmjs.com/package/ffish) and as an [ES6 module](https://www.npmjs.com/package/ffish-es6). ## Install instructions +### Standard module + ```bash npm install ffish ``` -## Build instuctions - -```bash -cd Fairy-Stockfish/src -``` +### ES6 module ```bash -emcc -O3 --bind -s TOTAL_MEMORY=67108864 -s ALLOW_MEMORY_GROWTH=1 \ - -s WASM_MEM_MAX=2147483648 -DLARGEBOARDS -DPRECOMPUTED_MAGICS \ -ffishjs.cpp \ -benchmark.cpp \ -bitbase.cpp \ -bitboard.cpp \ -endgame.cpp \ -evaluate.cpp \ -material.cpp \ -misc.cpp \ -movegen.cpp \ -movepick.cpp \ -parser.cpp \ -partner.cpp \ -pawns.cpp \ -piece.cpp \ -position.cpp \ -psqt.cpp \ -search.cpp \ -thread.cpp \ -timeman.cpp \ -tt.cpp \ -uci.cpp \ -syzygy/tbprobe.cpp \ -ucioption.cpp \ -variant.cpp \ -xboard.cpp \ --o ../tests/js/ffish.js +npm install ffish-es6 ``` -If you want to disable variants with a board greater than 8x8, - you can remove the flags `-s TOTAL_MEMORY=67108864 -s - ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2147483648 - -DLARGEBOARDS` ``-DPRECOMPUTED_MAGICS`. - -The pre-compiled wasm binary is built with `-DLARGEBOARDS`. - ## Examples Load the API in JavaScript: +### Standard module + ```javascript const ffish = require('ffish'); ``` +### ES6 module + +```javascript +import Module from 'ffish'; +let ffish = null; + +new Module().then(loadedModule => { + ffish = loadedModule; + console.log(`initialized ${ffish} ${loadedModule}`); + } +}); +``` + +### Board object + Create a new variant board from its default starting position. The even `onRuntimeInitialized` ensures that the wasm file was properly loaded. @@ -105,21 +97,58 @@ Therefore, you need to call `.delete()` to free the heap memory of an object. board.delete(); ``` -## Instructions to run the tests -```bash -npm install -npm test -``` -## Instructions to run the example server +## Build instuctions + +It is built using emscripten/Embind from C++ source code. + +* https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + + +If you want to disable variants with a board greater than 8x8, + you can remove the flags `-s TOTAL_MEMORY=67108864 -s + ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2147483648 + -DLARGEBOARDS -DPRECOMPUTED_MAGICS`. + +The pre-compiled wasm binary is built with `-DLARGEBOARDS`. + +### Compile as standard module + ```bash -npm install +cd Fairy-Stockfish/src ``` ```bash -node index.js +emcc -O3 --bind -s TOTAL_MEMORY=67108864 -s ALLOW_MEMORY_GROWTH=1 \ + -s WASM_MEM_MAX=2147483648 -DLARGEBOARDS -DPRECOMPUTED_MAGICS \ +ffishjs.cpp \ +benchmark.cpp \ +bitbase.cpp \ +bitboard.cpp \ +endgame.cpp \ +evaluate.cpp \ +material.cpp \ +misc.cpp \ +movegen.cpp \ +movepick.cpp \ +parser.cpp \ +partner.cpp \ +pawns.cpp \ +piece.cpp \ +position.cpp \ +psqt.cpp \ +search.cpp \ +thread.cpp \ +timeman.cpp \ +tt.cpp \ +uci.cpp \ +syzygy/tbprobe.cpp \ +ucioption.cpp \ +variant.cpp \ +xboard.cpp \ +-o ../tests/js/ffish.js ``` -## Compile as ES6/ES2015 module +### Compile as ES6/ES2015 module Some environments such as [vue-js](https://vuejs.org/) may require the library to be exported as a ES6/ES2015 module. @@ -160,17 +189,18 @@ xboard.cpp \ -o ../tests/js/ffish.js ``` -Later the module can be imported as follows: +Reference: [emscripten/#10114](https://github.com/emscripten-core/emscripten/issues/10114) -```javascript -import Module from './ffish.js'; -let ffish = null; - -new Module().then(loadedModule => { - ffish = loadedModule; - console.log(`initialized ${ffish} ${loadedModule}`); - } -}); +## Instructions to run the tests +```bash +npm install +npm test +``` +## Instructions to run the example server +```bash +npm install +``` +```bash +node index.js ``` -References: [emscripten/#10114](https://github.com/emscripten-core/emscripten/issues/10114) diff --git a/tests/js/package.json b/tests/js/package.json index ee83576..ad237c1 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -1,6 +1,6 @@ { "name": "ffish", - "version": "0.1.5", + "version": "0.2.0", "description": "A high performance WebAssembly chess variant library based on Fairy-Stockfish", "main": "ffish.js", "scripts": { @@ -17,6 +17,10 @@ "url": "https://github.com/QueensGambit" } ], + "repository": { + "type": "git", + "url": "git+https://github.com/ianfab/Fairy-Stockfish.git" + }, "keywords": ["wasm", "library", "chess-variants", "fairy-stockfish"], "license": "GPL-3.0", "homepage": "https://github.com/ianfab/Fairy-Stockfish/tree/master/tests/js#readme", diff --git a/tests/js/test.js b/tests/js/test.js index 177b810..e92e0ea 100644 --- a/tests/js/test.js +++ b/tests/js/test.js @@ -8,7 +8,7 @@ before(() => { }); }); -describe('Constructor: no parameter ', function () { +describe('Board()', function () { it("it creates a chess board from the default position", () => { const board = new ffish.Board(); chai.expect(board.fen()).to.equal("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); @@ -17,7 +17,7 @@ describe('Constructor: no parameter ', function () { }); }); -describe('Constructor: variant parameter ', function () { +describe('Board(uciVariant) ', function () { it("it creates a board object from a given UCI-variant", () => { const board = new ffish.Board("chess"); chai.expect(board.fen()).to.equal("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); @@ -26,7 +26,7 @@ describe('Constructor: variant parameter ', function () { }); }); -describe('Constructor: variant parameter with large board', function () { +describe('Board(uciVariant) with large board', function () { it("it creates a large-board object from a given UCI-variant", () => { const board = new ffish.Board("xiangqi"); chai.expect(board.fen()).to.equal("rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1"); @@ -35,7 +35,7 @@ describe('Constructor: variant parameter with large board', function () { }); }); -describe('Constructor: variant parameter + fen ', function () { +describe('Board(uciVariant, fen) ', function () { it("it creates a board object for a given UCI-variant with a given FEN", () => { const board = new ffish.Board("crazyhouse", "rnbqkb1r/pp3ppp/5p2/2pp4/8/5N2/PPPP1PPP/RNBQKB1R/Np w KQkq - 0 5"); chai.expect(board.fen()).to.equal("rnbqkb1r/pp3ppp/5p2/2pp4/8/5N2/PPPP1PPP/RNBQKB1R[Np] w KQkq - 0 5"); @@ -44,7 +44,7 @@ describe('Constructor: variant parameter + fen ', function () { }); }); -describe('Constructor: variant parameter + fen + is960', function () { +describe('Board(uciVariant, fen, is960)', function () { it("it creates a board object for a given UCI-variant with a given FEN and is960 identifier", () => { const board = new ffish.Board("chess", "rnknb1rq/pp2ppbp/3p2p1/2p5/4PP2/2N1N1P1/PPPP3P/R1K1BBRQ b KQkq - 1 5", true); chai.expect(board.fen()).to.equal("rnknb1rq/pp2ppbp/3p2p1/2p5/4PP2/2N1N1P1/PPPP3P/R1K1BBRQ b GAga - 1 5"); @@ -87,7 +87,7 @@ describe('board.numberLegalMoves()', function () { }); }); -describe('board.push()', function () { +describe('board.push(uciMove)', function () { it("it pushes a move in uci notation to the board", () => { let board = new ffish.Board(); board.push("e2e4"); @@ -156,7 +156,7 @@ describe('board.fen()', function () { }); }); -describe('board.setFen()', function () { +describe('board.setFen(fen)', function () { it("it sets a custom position via fen", () => { let board = new ffish.Board(); board.setFen("r1bqkbnr/ppp2ppp/2np4/1B6/3NP3/8/PPP2PPP/RNBQK2R b KQkq - 0 5"); @@ -174,6 +174,51 @@ describe('board.sanMove()', function () { }); }); +describe('board.sanMove(ffish.Notation)', function () { + it("it converts an uci move into san using a given notation", () => { + const board = new ffish.Board(); + chai.expect(board.sanMove("g1f3", ffish.Notation.DEFAULT)).to.equal("Nf3"); + chai.expect(board.sanMove("g1f3", ffish.Notation.SAN)).to.equal("Nf3"); + chai.expect(board.sanMove("g1f3", ffish.Notation.LAN)).to.equal("Ng1-f3"); + chai.expect(board.sanMove("g1f3", ffish.Notation.SHOGI_HOSKING)).to.equal("N36"); + chai.expect(board.sanMove("g1f3", ffish.Notation.SHOGI_HODGES)).to.equal("N-3f"); + chai.expect(board.sanMove("g1f3", ffish.Notation.SHOGI_HODGES_NUMBER)).to.equal("N-36"); + chai.expect(board.sanMove("g1f3", ffish.Notation.JANGGI)).to.equal("N87-66"); + chai.expect(board.sanMove("g1f3", ffish.Notation.XIANGQI_WXF)).to.equal("N2+3"); + board.delete(); + }); +}); + +describe('board.variationSan(uciMoves)', function () { + it("it converts a list of uci moves into san notation. The board will not changed by this method.", () => { + let board = new ffish.Board(); + board.push("e2e4") + const sanMoves = board.variationSan("e7e5 g1f3 b8c6 f1c4"); + chai.expect(sanMoves).to.equal("1...e5 2. Nf3 Nc6 3. Bc4"); + board.delete(); + }); +}); + +describe('board.variationSan(uciMoves, notation)', function () { + it("it converts a list of uci moves into san notation given a notation format", () => { + let board = new ffish.Board(); + board.push("e2e4") + const sanMoves = board.variationSan("e7e5 g1f3 b8c6 f1c4", ffish.Notation.LAN); + chai.expect(sanMoves).to.equal("1...e7-e5 2. Ng1-f3 Nb8-c6 3. Bf1-c4"); + board.delete(); + }); +}); + +describe('board.variationSan(uciMoves, notation, moveNumbers)', function () { + it("it converts a list of uci moves into san notation given a notation format and optionally disabling move numbers", () => { + let board = new ffish.Board(); + board.push("e2e4") + const sanMoves = board.variationSan("e7e5 g1f3 b8c6 f1c4", ffish.Notation.SAN, false); + chai.expect(sanMoves).to.equal("e5 Nf3 Nc6 Bc4"); + board.delete(); + }); +}); + describe('board.turn()', function () { it("it returns the side to move", () => { let board = new ffish.Board(); @@ -184,6 +229,21 @@ describe('board.turn()', function () { }); }); +describe('board.fullmoveNumber()', function () { + it("it returns the move number starting with 1 and is increment after each move of the 2nd player", () => { + let board = new ffish.Board(); + chai.expect(board.fullmoveNumber()).to.equal(1); + board.push("e2e4"); + chai.expect(board.fullmoveNumber()).to.equal(1); + board.push("e7e5"); + board.push("g1f3"); + board.push("g8f6"); + board.push("f3e5"); + chai.expect(board.fullmoveNumber()).to.equal(3); + board.delete(); + }); +}); + describe('board.halfmoveClock()', function () { it("it returns the halfmoveClock / 50-move-rule-counter", () => { let board = new ffish.Board(); @@ -226,8 +286,52 @@ describe('board.isGameOver()', function () { }); }); +describe('board.isCheck()', function () { + it("it checks if a player is in check", () => { + let board = new ffish.Board(); + chai.expect(board.isCheck()).to.equal(false); + board.setFen("rnbqkb1r/pppp1Bpp/5n2/4p3/4P3/8/PPPP1PPP/RNBQK1NR b KQkq - 0 3"); + chai.expect(board.isCheck()).to.equal(true); + board.setFen("r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4"); + board.pushSan("Qxf7#"); + chai.expect(board.isCheck()).to.equal(true); + board.delete(); + }); +}); + +describe('board.isBikjang()', function () { + it("it checks if a player is in bikjang (only relevant for janggi)", () => { + let board = new ffish.Board("janggi"); + chai.expect(board.isBikjang()).to.equal(false); + board.setFen("rnba1abnr/4k4/1c5c1/p1p3p1p/9/9/P1P3P1P/1C5C1/4K4/RNBA1ABNR w - - 0 1"); + chai.expect(board.isBikjang()).to.equal(true); + board.delete(); + }); +}); + describe('ffish.info()', function () { it("it returns the version of the Fairy-Stockfish binary", () => { chai.expect(ffish.info()).to.be.a('string'); }); }); + +describe('ffish.setOption(name, value)', function () { + it("it sets a string uci option value pair", () => { + ffish.setOption("VariantPath", "variants.ini"); + chai.expect(true).to.equal(true); + }); +}); + +describe('ffish.setOptionInt(name, value)', function () { + it("it sets a int uci option value pair", () => { + ffish.setOptionInt("Threads", 4); + chai.expect(true).to.equal(true); + }); +}); + +describe('ffish.setOptionBool(name, value)', function () { + it("it sets a boolean uci option value pair", () => { + ffish.setOptionBool("Ponder", true); + chai.expect(true).to.equal(true); + }); +}); -- 1.7.0.4