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
musketeerchess authored Mar 29, 2024
2 parents 0a392b4 + f3c982b commit 57627c6
Show file tree
Hide file tree
Showing 17 changed files with 273 additions and 165 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ build_script:
$dummy = $nnuenet -match "(?<nnuenet>nn-[a-z0-9]{12}.nnue)"
$nnuenet = $Matches.nnuenet
Write-Host "Default net:" $nnuenet
$nnuedownloadurl = "https://tests.stockfishchess.org/api/nn/$nnuenet"
$nnuedownloadurl = "https://github.com/official-stockfish/networks/raw/master/$nnuenet"
$nnuefilepath = "src\${env:CONFIGURATION}\$nnuenet"
if (Test-Path -Path $nnuefilepath) {
Write-Host "Already available."
Expand Down
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.78",
setup(name="pyffish", version="0.0.82",
description="Fairy-Stockfish Python wrapper",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
45 changes: 29 additions & 16 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,10 @@ ifeq ($(optimize),yes)
endif

ifeq ($(comp),clang)
CXXFLAGS += -fexperimental-new-pass-manager
clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.)
ifeq ($(shell expr $(clangmajorversion) \< 16),1)
CXXFLAGS += -fexperimental-new-pass-manager
endif
endif
endif

Expand Down Expand Up @@ -821,25 +824,35 @@ clean: objclean profileclean
net:
$(eval nnuenet := $(shell grep EvalFileDefaultName evaluate.h | grep define | sed 's/.*\(nn-[a-z0-9]\{12\}.nnue\).*/\1/'))
@echo "Default net: $(nnuenet)"
$(eval nnuedownloadurl := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl1 := https://tests.stockfishchess.org/api/nn/$(nnuenet))
$(eval nnuedownloadurl2 := https://github.com/official-stockfish/networks/raw/master/$(nnuenet))
$(eval curl_or_wget := $(shell if hash curl 2>/dev/null; then echo "curl -skL"; elif hash wget 2>/dev/null; then echo "wget -qO-"; fi))
@if test -f "$(nnuenet)"; then \
echo "Already available."; \
else \
if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
else \
echo "Downloading $(nnuedownloadurl)"; $(curl_or_wget) $(nnuedownloadurl) > $(nnuenet);\
fi; \
fi;
@if [ "x$(curl_or_wget)" = "x" ]; then \
echo "Automatic download failed: neither curl nor wget is installed. Install one of these tools or download the net manually"; exit 1; \
fi
$(eval shasum_command := $(shell if hash shasum 2>/dev/null; then echo "shasum -a 256 "; elif hash sha256sum 2>/dev/null; then echo "sha256sum "; fi))
@if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Failed download or $(nnuenet) corrupted, please delete!"; exit 1; \
fi \
else \
@if [ "x$(shasum_command)" = "x" ]; then \
echo "shasum / sha256sum not found, skipping net validation"; \
fi
@for nnuedownloadurl in "$(nnuedownloadurl1)" "$(nnuedownloadurl2)"; do \
if test -f "$(nnuenet)"; then \
echo "$(nnuenet) available."; \
else \
if [ "x$(curl_or_wget)" != "x" ]; then \
echo "Downloading $${nnuedownloadurl}"; $(curl_or_wget) $${nnuedownloadurl} > $(nnuenet);\
fi; \
fi; \
if [ "x$(shasum_command)" != "x" ]; then \
if [ "$(nnuenet)" != "nn-"`$(shasum_command) $(nnuenet) | cut -c1-12`".nnue" ]; then \
echo "Removing failed download"; rm -f $(nnuenet); \
else \
echo "Network validated"; break; \
fi; \
fi; \
done
@if ! test -f "$(nnuenet)"; then \
echo "Failed to download $(nnuenet)."; \
fi

# clean binaries and objects
objclean:
Expand Down
12 changes: 11 additions & 1 deletion src/apiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ inline Disambiguation disambiguation_level(const Position& pos, Move m, Notation
return SQUARE_DISAMBIGUATION;
}

// A disambiguation occurs if we have more then one piece of type 'pt'
// A disambiguation occurs if we have more than one piece of type 'pt'
// that can reach 'to' with a legal move.
Bitboard b = pos.pieces(us, pt) ^ from;
Bitboard others = 0;
Expand Down Expand Up @@ -821,6 +821,16 @@ inline Validation check_number_of_kings(const std::string& fenBoard, const std::
int nbWhiteKingsStart = piece_count(startFenBoard, WHITE, KING, v);
int nbBlackKingsStart = piece_count(startFenBoard, BLACK, KING, v);

if (nbWhiteKings > 1)
{
std::cerr << "Invalid number of white kings. Maximum: 1. Given: " << nbWhiteKings << std::endl;
return NOK;
}
if (nbBlackKings > 1)
{
std::cerr << "Invalid number of black kings. Maximum: 1. Given: " << nbBlackKings << std::endl;
return NOK;
}
if (nbWhiteKings != nbWhiteKingsStart)
{
std::cerr << "Invalid number of white kings. Expected: " << nbWhiteKingsStart << ". Given: " << nbWhiteKings << std::endl;
Expand Down
10 changes: 6 additions & 4 deletions src/bitboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ namespace {
const std::map<Direction, int> GrasshopperDirectionsH { {EAST, 1}, {WEST, 1} };
const std::map<Direction, int> GrasshopperDirectionsD { {NORTH_EAST, 1}, {SOUTH_EAST, 1}, {SOUTH_WEST, 1}, {NORTH_WEST, 1} };

enum MovementType { RIDER, HOPPER, LAME_LEAPER, UNLIMITED_RIDER };
enum MovementType { RIDER, HOPPER, LAME_LEAPER, HOPPER_RANGE };

template <MovementType MT>
#ifdef PRECOMPUTED_MAGICS
Expand All @@ -137,7 +137,9 @@ namespace {
if (MT != HOPPER || hurdle)
{
attack |= s;
if (limit && MT != UNLIMITED_RIDER && ++count >= limit)
// For hoppers we consider limit == 1 as a grasshopper,
// but limit > 1 as a limited distance hopper
if (limit && !(MT == HOPPER_RANGE && limit == 1) && ++count >= limit)
break;
}

Expand Down Expand Up @@ -300,7 +302,7 @@ void Bitboards::init_pieces() {
leaper |= safe_destination(s, c == WHITE ? d : -d);
}
pseudo |= sliding_attack<RIDER>(pi->slider[initial][modality], s, 0, c);
pseudo |= sliding_attack<UNLIMITED_RIDER>(pi->hopper[initial][modality], s, 0, c);
pseudo |= sliding_attack<HOPPER_RANGE>(pi->hopper[initial][modality], s, 0, c);
}
}
}
Expand Down Expand Up @@ -420,7 +422,7 @@ namespace {
// apply to the 64 or 32 bits word to get the index.
Magic& m = magics[s];
// The mask for hoppers is unlimited distance, even if the hopper is limited distance (e.g., grasshopper)
m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack<MT == HOPPER ? UNLIMITED_RIDER : MT>(directions, s, 0)) & ~edges;
m.mask = (MT == LAME_LEAPER ? lame_leaper_path(directions, s) : sliding_attack<MT == HOPPER ? HOPPER_RANGE : MT>(directions, s, 0)) & ~edges;
#ifdef LARGEBOARDS
m.shift = 128 - popcount(m.mask);
#else
Expand Down
9 changes: 8 additions & 1 deletion src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ namespace {
ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {

// Wall placing moves
if (pos.walling())
//if it's "wall or move", and they chose non-null move, skip even generating wall move
if (pos.walling() && !(pos.variant()->wallOrMove && (from!=to)))
{
Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to);
if (T == CASTLING)
Expand Down Expand Up @@ -443,6 +444,12 @@ namespace {
// Workaround for passing: Execute a non-move with any piece
if (pos.pass(Us) && !pos.count<KING>(Us) && pos.pieces(Us))
*moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));

//if "wall or move", generate walling action with null move
if (pos.variant()->wallOrMove)
{
moveList = make_move_and_gating<SPECIAL>(pos, moveList, Us, lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
}
}

// King moves
Expand Down
6 changes: 5 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("wallingRegionBlack", v->wallingRegion[BLACK]);
parse_attribute("wallingRegion", v->wallingRegion[WHITE]);
parse_attribute("wallingRegion", v->wallingRegion[BLACK]);
parse_attribute("wallOrMove", v->wallOrMove);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("commitGates", v->commitGates);
parse_attribute("cambodianMoves", v->cambodianMoves);
Expand Down Expand Up @@ -528,6 +529,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("flagPieceSafe", v->flagPieceSafe);
parse_attribute("checkCounting", v->checkCounting);
parse_attribute("connectN", v->connectN);
parse_attribute("connectPieceTypes", v->connectPieceTypes, v->pieceToChar);
parse_attribute("connectHorizontal", v->connectHorizontal);
parse_attribute("connectVertical", v->connectVertical);
parse_attribute("connectDiagonal", v->connectDiagonal);
Expand All @@ -536,15 +538,17 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("connectRegion1Black", v->connectRegion1[BLACK]);
parse_attribute("connectRegion2Black", v->connectRegion2[BLACK]);
parse_attribute("connectNxN", v->connectNxN);
parse_attribute("collinearN", v->collinearN);
parse_attribute("connectValue", v->connectValue);
parse_attribute("materialCounting", v->materialCounting);
parse_attribute("adjudicateFullBoard", v->adjudicateFullBoard);
parse_attribute("countingRule", v->countingRule);
parse_attribute("castlingWins", v->castlingWins);

// Report invalid options
if (DoCheck)
{
const std::set<std::string>& parsedKeys = config.get_comsumed_keys();
const std::set<std::string>& parsedKeys = config.get_consumed_keys();
for (const auto& it : config)
if (parsedKeys.find(it.first) == parsedKeys.end())
std::cerr << "Invalid option: " << it.first << std::endl;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Config : public std::map<std::string, std::string> {
consumedKeys.insert(s);
return std::map<std::string, std::string>::find(s);
}
const std::set<std::string>& get_comsumed_keys() {
const std::set<std::string>& get_consumed_keys() {
return consumedKeys;
}
private:
Expand Down
66 changes: 55 additions & 11 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
}

// Promoted shogi pieces
else if (token == '+' && (idx = piece_to_char().find(ss.peek())) != string::npos)
else if (token == '+' && (idx = piece_to_char().find(ss.peek())) != string::npos && promoted_piece_type(type_of(Piece(idx))))
{
ss >> token;
put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq, true, Piece(idx));
Expand Down Expand Up @@ -1343,7 +1343,8 @@ bool Position::pseudo_legal(const Move m) const {
return checkers() ? MoveList< EVASIONS>(*this).contains(m)
: MoveList<NON_EVASIONS>(*this).contains(m);

if (walling())
//if walling, and walling is not optional, or they didn't move, do the checks.
if (walling() && (!var->wallOrMove || (from==to)))
{
Bitboard wallsquares = st->wallSquares;

Expand Down Expand Up @@ -2100,7 +2101,8 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}

// Add gated wall square
if (walling())
// if wallOrMove, only actually place the wall if they gave up their move
if (walling() && (!var->wallOrMove || (from==to)))
{
// Reset wall squares for duck walling
if (walling_rule() == DUCK)
Expand Down Expand Up @@ -2771,7 +2773,7 @@ bool Position::is_optional_game_end(Value& result, int ply, int countStarted) co

/// Position::is_immediate_game_end() tests whether the position ends the game
/// immediately by a variant rule, i.e., there are no more legal moves.
/// It does not not detect stalemates.
/// It does not detect stalemates.

bool Position::is_immediate_game_end(Value& result, int ply) const {

Expand Down Expand Up @@ -2857,14 +2859,23 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
result = mated_in(ply);
return true;
}

//Calculate eligible pieces for connection once.
Bitboard connectPieces = 0;
for (PieceSet ps = connect_piece_types(); ps;){
PieceType pt = pop_lsb(ps);
connectPieces |= pieces(pt);
};
connectPieces &= pieces(~sideToMove);

// Connect-n
if (connect_n() > 0)
{
Bitboard b;

for (Direction d : var->connect_directions)
{
b = pieces(~sideToMove);
b = connectPieces;
for (int i = 1; i < connect_n() && b; i++)
b &= shift(d, b);
if (b)
Expand All @@ -2875,15 +2886,15 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
}
}

if ((var->connectRegion1[~sideToMove] & pieces(~sideToMove)) && (var->connectRegion2[~sideToMove] & pieces(~sideToMove)))
if ((var->connectRegion1[~sideToMove] & connectPieces) && (var->connectRegion2[~sideToMove] & connectPieces))
{
Bitboard target = var->connectRegion2[~sideToMove];
Bitboard current = var->connectRegion1[~sideToMove] & pieces(~sideToMove);
Bitboard current = var->connectRegion1[~sideToMove] & connectPieces;

while (true) {
Bitboard newBitboard = 0;
for (Direction d : var->connect_directions) {
newBitboard |= shift(d, current | newBitboard) & pieces(~sideToMove); // the "| newBitboard" here probably saves a few loops
newBitboard |= shift(d, current | newBitboard) & connectPieces; // the "| newBitboard" here probably saves a few loops
}

if (newBitboard & target) {
Expand All @@ -2903,7 +2914,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {

if (connect_nxn())
{
Bitboard connectors = pieces(~sideToMove);
Bitboard connectors = connectPieces;
for (int i = 1; i < connect_nxn() && connectors; i++)
connectors &= shift<SOUTH>(connectors) & shift<EAST>(connectors) & shift<SOUTH_EAST>(connectors);
if (connectors)
Expand All @@ -2913,18 +2924,51 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
}
}

// Check for bikjang rule (Janggi) and double passing
if (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
// Collinear-n
if (collinear_n() > 0) {
Bitboard allPieces = connectPieces;
for (Direction d : var->connect_directions) {
Bitboard b = allPieces;
while (b) {
Square s = pop_lsb(b);

int total_count = 1; // Start with the current piece

// Check in both directions
for (int sign : {-1, 1}) {
Bitboard shifted = shift(sign * d, square_bb(s));
while (shifted) {
if (shifted & b) {
total_count++;
b &= ~shifted; // Remove this piece from further consideration
}
shifted = shift(sign * d, shifted);
}
}

if (total_count >= collinear_n()) {
result = convert_mate_value(-var->connectValue, ply);
return true;
}
}
}
}

// Check for bikjang rule (Janggi), double passing, or board running full
if ( (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
|| (var->adjudicateFullBoard && !(~pieces() & board_bb())))
{
result = var->materialCounting ? convert_mate_value(material_counting_result(), ply) : VALUE_DRAW;
return true;
}

// Tsume mode: Assume that side with king wins when not in check
if (tsumeMode && !count<KING>(~sideToMove) && count<KING>(sideToMove) && !checkers())
{
result = mate_in(ply);
return true;
}

// Failing to checkmate with virtual pieces is a loss
if (two_boards() && !checkers())
{
Expand Down
12 changes: 12 additions & 0 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,13 @@ class Position {
bool flag_reached(Color c) const;
bool check_counting() const;
int connect_n() const;
PieceSet connect_piece_types() const;
bool connect_horizontal() const;
bool connect_vertical() const;
bool connect_diagonal() const;
const std::vector<Direction>& getConnectDirections() const;
int connect_nxn() const;
int collinear_n() const;

CheckCount checks_remaining(Color c) const;
MaterialCounting material_counting() const;
Expand Down Expand Up @@ -1047,6 +1049,11 @@ inline int Position::connect_n() const {
return var->connectN;
}

inline PieceSet Position::connect_piece_types() const {
assert(var != nullptr);
return var->connectPieceTypes;
}

inline bool Position::connect_horizontal() const {
assert(var != nullptr);
return var->connectHorizontal;
Expand All @@ -1070,6 +1077,11 @@ inline int Position::connect_nxn() const {
return var->connectNxN;
}

inline int Position::collinear_n() const {
assert(var != nullptr);
return var->collinearN;
}

inline CheckCount Position::checks_remaining(Color c) const {
return st->checksRemaining[c];
}
Expand Down
Loading

0 comments on commit 57627c6

Please sign in to comment.