Skip to content

Commit

Permalink
Merge branch 'master' into musketeer-variant
Browse files Browse the repository at this point in the history
  • Loading branch information
alperatalayn committed Mar 5, 2024
2 parents 06a794f + 62577a4 commit d6ba9bd
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 25 deletions.
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.80",
setup(name="pyffish", version="0.0.81",
description="Fairy-Stockfish Python wrapper",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
5 changes: 4 additions & 1 deletion 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
10 changes: 10 additions & 0 deletions src/apiutil.h
Original file line number Diff line number Diff line change
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
3 changes: 3 additions & 0 deletions 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,6 +538,7 @@ 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);
Expand Down
59 changes: 50 additions & 9 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,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 @@ -1336,7 +1336,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 @@ -2091,7 +2092,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 @@ -2759,7 +2761,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 @@ -2845,14 +2847,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 @@ -2863,15 +2874,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 @@ -2891,7 +2902,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 @@ -2901,6 +2912,36 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
}
}

// 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())))
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
2 changes: 1 addition & 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, 80);
return Py_BuildValue("(iii)", 0, 0, 81);
}

extern "C" PyObject* pyffish_info(PyObject* self) {
Expand Down
11 changes: 11 additions & 0 deletions src/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,17 @@ Variant* Variant::conclude() {
connect_directions.push_back(SOUTH_EAST);
}

// If not a connect variant, set connectPieceTypes to no pieces.
if ( !(connectRegion1[WHITE] || connectRegion1[BLACK] || connectN || connectNxN || collinearN) )
{
connectPieceTypes = NO_PIECE_SET;
}
//Otherwise optimize to pieces actually in the game.
else
{
connectPieceTypes = connectPieceTypes & pieceTypes;
};

return this;
}

Expand Down
3 changes: 3 additions & 0 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct Variant {
bool gating = false;
WallingRule wallingRule = NO_WALLING;
Bitboard wallingRegion[COLOR_NB] = {AllSquares, AllSquares};
bool wallOrMove = false;
bool seirawanGating = false;
bool commitGates = false;
bool cambodianMoves = false;
Expand Down Expand Up @@ -150,12 +151,14 @@ struct Variant {
bool flagPieceSafe = false;
bool checkCounting = false;
int connectN = 0;
PieceSet connectPieceTypes = ~NO_PIECE_SET;
bool connectHorizontal = true;
bool connectVertical = true;
bool connectDiagonal = true;
Bitboard connectRegion1[COLOR_NB] = {};
Bitboard connectRegion2[COLOR_NB] = {};
int connectNxN = 0;
int collinearN = 0;
Value connectValue = VALUE_MATE;
MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
bool adjudicateFullBoard = false;
Expand Down
Loading

0 comments on commit d6ba9bd

Please sign in to comment.