Skip to content

Commit

Permalink
Merge branch 'fairy-stockfish:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRat authored Dec 29, 2024
2 parents 23c6942 + c3c6b21 commit 6842608
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 6 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/ffishjs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,48 @@ jobs:
- name: Run unit tests
working-directory: tests/js
run: npm test

build:
runs-on: ubuntu-20.04
needs: [test] #Building process must start after successful testing process

strategy:
matrix:
node-version: [12.x]

steps:
- uses: actions/checkout@v4
- name: Setup cache
id: cache-system-libraries
uses: actions/cache@v2
with:
path: ${{env.EM_CACHE_FOLDER}}
key: emsdk-${{env.EM_VERSION}}-${{ runner.os }}
- uses: mymindstorm/setup-emsdk@v7
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Build ffish.js ES6/ES2015 module
working-directory: src
run: rm -f ../tests/js/ffish.js & rm -f ../tests/js/ffish.wasm & make -f Makefile_js build es6=yes
- name: Upload ffish.js ES6/ES2015 module ZIP archive
uses: actions/upload-artifact@v4
with:
name: ffishjs-es6
path: tests/js/*
if-no-files-found: error
compression-level: 9
- name: Build ffish.js standard module
working-directory: src
run: rm -f ../tests/js/ffish.js & rm -f ../tests/js/ffish.wasm & make -f Makefile_js build
- name: Upload ffish.js standard module ZIP archive
uses: actions/upload-artifact@v4
with:
name: ffishjs-standard
path: tests/js/*
if-no-files-found: error
compression-level: 9
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
sources=sources,
extra_compile_args=args)

setup(name="pyffish", version="0.0.84",
setup(name="pyffish", version="0.0.85",
description="Fairy-Stockfish Python wrapper",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
6 changes: 3 additions & 3 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ Position& Position::set(const string& code, Color c, StateInfo* si) {
/// Position::fen() returns a FEN representation of the position. In case of
/// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.

string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string holdings) const {
string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string holdings, Bitboard fogArea) const {

int emptyCnt;
std::ostringstream ss;
Expand All @@ -690,15 +690,15 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string
{
for (File f = FILE_A; f <= max_file(); ++f)
{
for (emptyCnt = 0; f <= max_file() && !(pieces() & make_square(f, r)); ++f)
for (emptyCnt = 0; f <= max_file() && !(pieces() & make_square(f, r)) && !(fogArea & make_square(f, r)); ++f)
++emptyCnt;

if (emptyCnt)
ss << emptyCnt;

if (f <= max_file())
{
if (empty(make_square(f, r)))
if (empty(make_square(f, r)) || fogArea & make_square(f, r))
// Wall square
ss << "*";
else if (unpromoted_piece_on(make_square(f, r)))
Expand Down
17 changes: 16 additions & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Position {
// FEN string input/output
Position& set(const Variant* v, const std::string& fenStr, bool isChess960, StateInfo* si, Thread* th, bool sfen = false);
Position& set(const std::string& code, Color c, StateInfo* si);
std::string fen(bool sfen = false, bool showPromoted = false, int countStarted = 0, std::string holdings = "-") const;
std::string fen(bool sfen = false, bool showPromoted = false, int countStarted = 0, std::string holdings = "-", Bitboard fogArea = 0) const;

// Variant rule properties
const Variant* variant() const;
Expand Down Expand Up @@ -328,6 +328,7 @@ class Position {
Score psq_score() const;
Value non_pawn_material(Color c) const;
Value non_pawn_material() const;
Bitboard fog_area() const;

// Position consistency check, for debugging
bool pos_is_ok() const;
Expand Down Expand Up @@ -1407,6 +1408,20 @@ inline Piece Position::captured_piece() const {
return st->capturedPiece;
}

inline Bitboard Position::fog_area() const {
Bitboard b = board_bb();
// Our own pieces are visible
Bitboard visible = pieces(sideToMove);
// Squares where we can move to are visible as well
for (const auto& m : MoveList<LEGAL>(*this))
{
Square to = to_sq(m);
visible |= to;
}
// Everything else is invisible
return ~visible & b;
}

inline const std::string Position::piece_to_partner() const {
if (!st->capturedPiece) return std::string();
Color color = color_of(st->capturedPiece);
Expand Down
19 changes: 18 additions & 1 deletion src/pyffish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void buildPosition(Position& pos, StateListPtr& states, const char *variant, con
}

extern "C" PyObject* pyffish_version(PyObject* self) {
return Py_BuildValue("(iii)", 0, 0, 84);
return Py_BuildValue("(iii)", 0, 0, 85);
}

extern "C" PyObject* pyffish_info(PyObject* self) {
Expand Down Expand Up @@ -383,6 +383,22 @@ extern "C" PyObject* pyffish_validateFen(PyObject* self, PyObject *args) {
return Py_BuildValue("i", FEN::validate_fen(std::string(fen), variants.find(std::string(variant))->second, chess960));
}

// INPUT variant, fen
extern "C" PyObject* pyffish_getFogFEN(PyObject* self, PyObject *args) {
PyObject* moveList = PyList_New(0);
Position pos;
const char *fen, *variant;

int chess960 = false, sfen = false, showPromoted = false, countStarted = 0;
if (!PyArg_ParseTuple(args, "ss|p", &fen, &variant, &chess960)) {
return NULL;
}
StateListPtr states(new std::deque<StateInfo>(1));
buildPosition(pos, states, variant, fen, moveList, chess960);

Py_XDECREF(moveList);
return Py_BuildValue("s", pos.fen(sfen, showPromoted, countStarted, "-", pos.fog_area()).c_str());
}

static PyMethodDef PyFFishMethods[] = {
{"version", (PyCFunction)pyffish_version, METH_NOARGS, "Get package version."},
Expand All @@ -405,6 +421,7 @@ static PyMethodDef PyFFishMethods[] = {
{"is_optional_game_end", (PyCFunction)pyffish_isOptionalGameEnd, METH_VARARGS, "Get result from given FEN it rules enable game end by player."},
{"has_insufficient_material", (PyCFunction)pyffish_hasInsufficientMaterial, METH_VARARGS, "Checks for insufficient material."},
{"validate_fen", (PyCFunction)pyffish_validateFen, METH_VARARGS, "Validate an input FEN."},
{"get_fog_fen", (PyCFunction)pyffish_getFogFEN, METH_VARARGS, "Get Fog of War FEN from given FEN."},
{NULL, NULL, 0, NULL}, // sentinel
};

Expand Down
34 changes: 34 additions & 0 deletions src/variants.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2010,3 +2010,37 @@ passOnStalemate = true

[andersanti:antichess]
passOnStalemate = true

# A 10x10 drop variant consisting of only Leapers, Shogi pawns, and Kings.
[leaperhouse]
variantTemplate = shogi
pieceToCharTable = PN...OU.CR.+Kpn...ou.cr.+k
maxFile = 10
maxRank = 10
pocketSize = 6
startFen = oncurkucno/10/pppppppppp/10/10/10/10/PPPPPPPPPP/10/ONCUKRUCNO[] w - - 0 1
pieceDrops = true
capturesToHand = true
shogiPawn = p
knight = n
customPiece1 = u:Z
customPiece2 = c:C
customPiece3 = r:GH
customPiece4 = o:AD
commoner = g
king = k
promotionRegionWhite = *8 *9 *10
promotionRegionBlack = *3 *2 *1
promotedPieceType = p:g
doubleStep = false
castling = false
perpetualCheckIllegal = true
dropNoDoubled = p
stalemateValue = loss
nMoveRule = 0
nFoldValue = loss
flagPiece = k
flagRegionWhite = *10
flagRegionBlack = *1
immobilityIllegal = true
mandatoryPiecePromotion = true
17 changes: 17 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@
customPiece5 = f:mBpBmWpR2
promotedPieceType = u:w a:w c:f i:f
startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] w 0 1
[fogofwar:chess]
king = -
commoner = k
castlingKingPiece = k
extinctionValue = loss
extinctionPieceTypes = k
"""

sf.load_variant_config(ini_text)
Expand Down Expand Up @@ -1156,5 +1163,15 @@ def test_validate_fen(self):
fen = sf.start_fen(variant)
self.assertEqual(sf.validate_fen(fen, variant), sf.FEN_OK)

def test_get_fog_fen(self):
fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" # startpos
result = sf.get_fog_fen(fen, "fogofwar")
self.assertEqual(result, "********/********/********/********/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")

fen = "rnbqkbnr/p1p2ppp/8/Pp1pp3/4P3/8/1PPP1PPP/RNBQKBNR w KQkq b6 0 1"
result = sf.get_fog_fen(fen, "fogofwar")
self.assertEqual(result, "********/********/2******/Pp*p***1/4P3/4*3/1PPP1PPP/RNBQKBNR w KQkq b6 0 1")


if __name__ == '__main__':
unittest.main(verbosity=2)

0 comments on commit 6842608

Please sign in to comment.