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
mtaktikos authored Apr 2, 2023
2 parents b9c763b + 950c0c7 commit 4f223e8
Show file tree
Hide file tree
Showing 25 changed files with 293 additions and 230 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ jobs:
- name: make largeboards
run: cd src && make clean && make -j build COMP=mingw ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }}.exe largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}.exe

- name: make all
if: ${{ matrix.arch == 'x86-64' }}
run: cd src && make clean && make -j build COMP=mingw ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }}.exe largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}.exe

- uses: actions/upload-artifact@v3
with:
name: fairy-stockfish
Expand All @@ -48,6 +52,10 @@ jobs:
- name: make largeboards
run: cd src && make clean && make -j build COMP=gcc ARCH=${{ matrix.arch }} EXE=fairy-stockfish-largeboards_${{ matrix.arch }} largeboards=yes && strip fairy-stockfish-largeboards_${{ matrix.arch }}

- name: make all
if: ${{ matrix.arch == 'x86-64' }}
run: cd src && make clean && make -j build COMP=gcc ARCH=${{ matrix.arch }} EXE=fairy-stockfish-all_${{ matrix.arch }} largeboards=yes all=yes && strip fairy-stockfish-all_${{ matrix.arch }}

- uses: actions/upload-artifact@v3
with:
name: fairy-stockfish
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ The games currently supported besides chess are listed below. Fairy-Stockfish ca
- [Clobber](https://en.wikipedia.org/wiki/Clobber)
- [Cfour](https://en.wikipedia.org/wiki/Connect_Four), [Tic-tac-toe](https://en.wikipedia.org/wiki/Tic-tac-toe)
- [Flipersi](https://en.wikipedia.org/wiki/Reversi), [Flipello](https://en.wikipedia.org/wiki/Reversi#Othello)
- [Isolation](https://boardgamegeek.com/boardgame/1875/isolation)
- [Joust](https://www.chessvariants.com/programs.dir/joust.html)
- [Snailtrail](https://boardgamegeek.com/boardgame/37135/snailtrail)


## Help

Expand Down
52 changes: 0 additions & 52 deletions appveyor_python.yml

This file was deleted.

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.77",
setup(name="pyffish", version="0.0.78",
description="Fairy-Stockfish Python wrapper",
long_description=long_description,
long_description_content_type="text/markdown",
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile_js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ help:
@echo ""

objclean:
@rm -f $(EXE) *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o
@rm -f $(EXE)

clean: objclean

Expand Down
15 changes: 15 additions & 0 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,21 @@ namespace {
score += bonus - PassedFile * edge_distance(file_of(s), pos.max_file());
}

// Passed custom pawns
for (PieceSet ps = pos.variant()->promotionPawnTypes[Us] & ~piece_set(PAWN); ps;)
{
PieceType pt = pop_lsb(ps);
Bitboard b2 = pos.pieces(Us, pt);
while (b2)
{
Square s = pop_lsb(b2);
if (pos.promotion_square(Us, s) == SQ_NONE || (pos.pieces(Them, pt) & forward_file_bb(Us, s)))
continue;
int r = std::max(RANK_8 - std::max(relative_rank(Us, pos.promotion_square(Us, s), pos.max_rank()) - relative_rank(Us, s, pos.max_rank()), 0), 0);
score += PassedRank[r];
}
}

// Scale by maximum promotion piece value
Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO;
for (PieceSet ps = pos.promotion_piece_types(Us); ps;)
Expand Down
3 changes: 2 additions & 1 deletion src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ namespace {

Bitboard b = pawns & pawn_attacks_bb(Them, epSquare);

assert(b);
// En passant square is already disabled for non-fairy variants if there is no attacker
assert(b || !pos.variant()->fastAttacks);

while (b)
moveList = make_move_and_gating<EN_PASSANT>(pos, moveList, Us, pop_lsb(b), epSquare);
Expand Down
6 changes: 3 additions & 3 deletions src/nnue/nnue_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ namespace Stockfish::Eval::NNUE {

// write_little_endian() is our utility to write an integer (signed or unsigned, any size)
// to a stream in little-endian order. We swap the byte order before the write if
// necessary to always write in little endian order, independantly of the byte
// necessary to always write in little endian order, independently of the byte
// ordering of the compiling machine.
template <typename IntType>
inline void write_little_endian(std::ostream& stream, IntType value) {
Expand Down Expand Up @@ -137,7 +137,7 @@ namespace Stockfish::Eval::NNUE {
}
}

// read_little_endian(s, out, N) : read integers in bulk from a little indian stream.
// read_little_endian(s, out, N) : read integers in bulk from a little endian stream.
// This reads N integers from stream s and put them in array out.
template <typename IntType>
inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
Expand All @@ -148,7 +148,7 @@ namespace Stockfish::Eval::NNUE {
out[i] = read_little_endian<IntType>(stream);
}

// write_little_endian(s, values, N) : write integers in bulk to a little indian stream.
// write_little_endian(s, values, N) : write integers in bulk to a little endian stream.
// This takes N integers from array values and writes them on stream s.
template <typename IntType>
inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) {
Expand Down
2 changes: 2 additions & 0 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("castlingKingPiece", v->castlingKingPiece[BLACK], v->pieceToChar);
parse_attribute("castlingKingPieceWhite", v->castlingKingPiece[WHITE], v->pieceToChar);
parse_attribute("castlingKingPieceBlack", v->castlingKingPiece[BLACK], v->pieceToChar);
parse_attribute("castlingRookKingsideFile", v->castlingRookKingsideFile);
parse_attribute("castlingRookQueensideFile", v->castlingRookQueensideFile);
parse_attribute("castlingRookPieces", v->castlingRookPieces[WHITE], v->pieceToChar);
parse_attribute("castlingRookPieces", v->castlingRookPieces[BLACK], v->pieceToChar);
parse_attribute("castlingRookPiecesWhite", v->castlingRookPieces[WHITE], v->pieceToChar);
Expand Down
2 changes: 1 addition & 1 deletion src/piece.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ namespace {
// Special multi-leg betza description for Janggi elephant
PieceInfo* janggi_elephant_piece() {
PieceInfo* p = from_betza("nZ", "janggiElephant");
p->betza = "mafsmafW"; // for compatiblity with XBoard/Winboard
p->betza = "mafsmafW"; // for compatibility with XBoard/Winboard
return p;
}
}
Expand Down
80 changes: 58 additions & 22 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ void Position::init() {
std::memset(cuckooMove, 0, sizeof(cuckooMove));
int count = 0;
for (Color c : {WHITE, BLACK})
for (PieceType pt = KNIGHT; pt <= QUEEN || pt == KING; pt != QUEEN ? ++pt : pt = KING)
for (PieceSet ps = CHESS_PIECES & ~piece_set(PAWN); ps;)
{
Piece pc = make_piece(c, pt);
Piece pc = make_piece(c, pop_lsb(ps));
for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
for (Square s2 = Square(s1 + 1); s2 <= SQ_MAX; ++s2)
if ((type_of(pc) != PAWN) && (attacks_bb(c, type_of(pc), s1, 0) & s2))
Expand Down Expand Up @@ -349,10 +349,10 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
token = char(toupper(token));

if (token == 'K')
for (rsq = make_square(FILE_MAX, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; --rsq) {}
for (rsq = make_square(var->castlingRookKingsideFile, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; --rsq) {}

else if (token == 'Q')
for (rsq = make_square(FILE_A, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; ++rsq) {}
for (rsq = make_square(var->castlingRookQueensideFile, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; ++rsq) {}

else if (token >= 'A' && token <= 'A' + max_file())
rsq = make_square(File(token - 'A'), castling_rank(c));
Expand Down Expand Up @@ -559,9 +559,10 @@ void Position::set_check_info(StateInfo* si) const {
for (PieceSet ps = piece_types(); ps;)
{
PieceType pt = pop_lsb(ps);
si->checkSquares[pt] = ksq != SQ_NONE ? attacks_bb(~sideToMove, pt, ksq, pieces()) : Bitboard(0);
PieceType movePt = pt == KING ? king_type() : pt;
si->checkSquares[pt] = ksq != SQ_NONE ? attacks_bb(~sideToMove, movePt, ksq, pieces()) : Bitboard(0);
// Collect special piece types that require slower check and evasion detection
if (AttackRiderTypes[pt] & NON_SLIDING_RIDERS)
if (AttackRiderTypes[movePt] & NON_SLIDING_RIDERS)
si->nonSlidingRiders |= pieces(pt);
}
si->shak = si->checkersBB & (byTypeBB[KNIGHT] | byTypeBB[ROOK] | byTypeBB[BERS]);
Expand Down Expand Up @@ -985,17 +986,37 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
/// Position::attackers_to_pseudo_royals computes a bitboard of all pieces
/// of a particular color attacking at least one opposing pseudo-royal piece
Bitboard Position::attackers_to_pseudo_royals(Color c) const {
assert(extinction_pseudo_royal());
Bitboard attackers = 0;
Bitboard pseudoRoyals = st->pseudoRoyals & pieces(~c);
Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(c);
while (pseudoRoyals) {
while (pseudoRoyals)
{
Square sr = pop_lsb(pseudoRoyals);
if (blast_on_capture()
if ( blast_on_capture()
&& pseudoRoyalsTheirs & attacks_bb<KING>(sr))
// skip if capturing this piece would blast all of the attacker's pseudo-royal pieces
continue;
attackers |= attackers_to(sr, c);
}
// Look for duple check
if (var->dupleCheck)
{
Bitboard b;
Bitboard allAttackers = 0;
Bitboard pseudoRoyalCandidates = st->pseudoRoyalCandidates & pieces(~c);
while (pseudoRoyalCandidates)
{
Square sr = pop_lsb(pseudoRoyalCandidates);
if (!(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb<KING>(sr)))
&& (b = attackers_to(sr, c)))
allAttackers |= b;
else
// If at least one isn't attacked, it is not a duple check
return attackers;
}
attackers |= allAttackers;
}
return attackers;
}

Expand Down Expand Up @@ -1357,30 +1378,35 @@ bool Position::gives_check(Move m) const {
if (!count<KING>(~sideToMove))
return false;

Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | to;
Bitboard janggiCannons = pieces(JANGGI_CANNON);
if (type_of(moved_piece(m)) == JANGGI_CANNON)
janggiCannons = (type_of(m) == DROP ? janggiCannons : janggiCannons ^ from) | to;
else if (janggiCannons & to)
janggiCannons ^= to;

// Is there a direct check?
if (type_of(m) != PROMOTION && type_of(m) != PIECE_PROMOTION && type_of(m) != PIECE_DEMOTION && type_of(m) != CASTLING
&& !(var->petrifyOnCapture && capture(m) && type_of(moved_piece(m)) != PAWN))
{
PieceType pt = type_of(moved_piece(m));
if (AttackRiderTypes[pt] & (HOPPING_RIDERS | ASYMMETRICAL_RIDERS))
if (pt == JANGGI_CANNON)
{
if (attacks_bb(sideToMove, pt, to, occupied) & attacks_bb(sideToMove, pt, to, occupied & ~janggiCannons) & square<KING>(~sideToMove))
return true;
}
else if (AttackRiderTypes[pt] & (HOPPING_RIDERS | ASYMMETRICAL_RIDERS))
{
Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | to;
if (attacks_bb(sideToMove, pt, to, occupied) & square<KING>(~sideToMove))
return true;
}
else if (check_squares(pt) & to)
return true;
}

Bitboard janggiCannons = pieces(JANGGI_CANNON);
if (type_of(moved_piece(m)) == JANGGI_CANNON)
janggiCannons = (type_of(m) == DROP ? janggiCannons : janggiCannons ^ from) | to;
else if (janggiCannons & to)
janggiCannons ^= to;

// Is there a discovered check?
if ( ((type_of(m) != DROP && (blockers_for_king(~sideToMove) & from)) || (non_sliding_riders() & pieces(sideToMove)))
&& attackers_to(square<KING>(~sideToMove), (type_of(m) == DROP ? pieces() : pieces() ^ from) | to, sideToMove, janggiCannons))
&& attackers_to(square<KING>(~sideToMove), occupied, sideToMove, janggiCannons) & occupied)
return true;

// Is there a check by gated pieces?
Expand All @@ -1397,7 +1423,6 @@ bool Position::gives_check(Move m) const {
{
PieceType pt = type_of(moved_piece(m));
PieceType diagType = pt == WAZIR ? FERS : pt == SOLDIER ? PAWN : pt == ROOK ? BISHOP : NO_PIECE_TYPE;
Bitboard occupied = type_of(m) == DROP ? pieces() : pieces() ^ from;
if (diagType && (attacks_bb(sideToMove, diagType, to, occupied) & square<KING>(~sideToMove)))
return true;
else if (pt == JANGGI_CANNON && ( rider_attacks_bb<RIDER_CANNON_DIAG>(to, occupied)
Expand Down Expand Up @@ -1594,10 +1619,24 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
k ^= Zobrist::psq[pc][to]
^ Zobrist::inHand[pc_hand][pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)] - 1]
^ Zobrist::inHand[pc_hand][pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]];

// Reset rule 50 counter for irreversible drops
st->rule50 = 0;
}
else
{
k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];

// Reset rule 50 draw counter for irreversible moves
// - irreversible pawn/piece promotions
// - irreversible pawn moves
if ( type_of(m) == PROMOTION
|| (type_of(m) == PIECE_PROMOTION && !piece_demotion())
|| ( (var->nMoveRuleTypes[us] & type_of(pc))
&& !(PseudoMoves[0][us][type_of(pc)][to] & from)))
st->rule50 = 0;
}

// Reset en passant squares
while (st->epSquares)
k ^= Zobrist::enpassant[file_of(pop_lsb(st->epSquares))];
Expand Down Expand Up @@ -1831,10 +1870,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
k ^= Zobrist::enpassant[file_of(pop_lsb(b))];
}

// Reset rule 50 draw counter
if (var->nMoveRuleTypes[us] & type_of(pc))
st->rule50 = 0;

// Set capture piece
st->capturedPiece = captured;

Expand Down Expand Up @@ -1979,6 +2014,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
st->key = k;
// Calculate checkers bitboard (if move gives check)
st->checkersBB = givesCheck ? attackers_to(square<KING>(them), us) & pieces(us) : Bitboard(0);
assert(givesCheck == bool(st->checkersBB));

sideToMove = ~sideToMove;

Expand Down
12 changes: 6 additions & 6 deletions src/psqt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,16 @@ constexpr Score PBonus[RANK_NB][FILE_NB] =
Value piece_value(Phase phase, PieceType pt)
{
const PieceInfo* pi = pieceMap.find(pt)->second;
int v0 = (phase == MG ? 55 : 60) * pi->steps[0][MODALITY_CAPTURE].size()
int v0 = (phase == MG ? 60 : 60) * pi->steps[0][MODALITY_CAPTURE].size()
+ (phase == MG ? 30 : 40) * pi->steps[0][MODALITY_QUIET].size()
+ (phase == MG ? 185 : 180) * pi->slider[0][MODALITY_CAPTURE].size()
+ (phase == MG ? 55 : 50) * pi->slider[0][MODALITY_QUIET].size()
+ (phase == MG ? 185 : 185) * pi->slider[0][MODALITY_CAPTURE].size()
+ (phase == MG ? 55 : 45) * pi->slider[0][MODALITY_QUIET].size()
// Hoppers are more useful with more pieces on the board
+ (phase == MG ? 100 : 80) * pi->hopper[0][MODALITY_CAPTURE].size()
+ (phase == MG ? 80 : 60) * pi->hopper[0][MODALITY_QUIET].size()
+ (phase == MG ? 85 : 60) * pi->hopper[0][MODALITY_QUIET].size()
// Rook sliding directions are more valuable, especially in endgame
+ (phase == MG ? 10 : 30) * std::count_if(pi->slider[0][MODALITY_CAPTURE].begin(), pi->slider[0][MODALITY_CAPTURE].end(), [](const std::pair<const Direction, int>& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; })
+ (phase == MG ? 30 : 45) * std::count_if(pi->slider[0][MODALITY_QUIET].begin(), pi->slider[0][MODALITY_QUIET].end(), [](const std::pair<const Direction, int>& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; });
+ (phase == MG ? 15 : 15) * std::count_if(pi->slider[0][MODALITY_CAPTURE].begin(), pi->slider[0][MODALITY_CAPTURE].end(), [](const std::pair<const Direction, int>& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; })
+ (phase == MG ? 30 : 50) * std::count_if(pi->slider[0][MODALITY_QUIET].begin(), pi->slider[0][MODALITY_QUIET].end(), [](const std::pair<const Direction, int>& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; });
return Value(v0 * exp(double(v0) / 10000));
}

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, 77);
return Py_BuildValue("(iii)", 0, 0, 78);
}

extern "C" PyObject* pyffish_info(PyObject* self) {
Expand Down
Loading

0 comments on commit 4f223e8

Please sign in to comment.