add clang-format

This introduces clang-format to enforce a consistent code style for Stockfish.

Having a documented and consistent style across the code will make contributing easier
for new developers, and will make larger changes to the codebase easier to make.

To facilitate formatting, this PR includes a Makefile target (`make format`) to format the code,
this requires clang-format (version 17 currently) to be installed locally.

Installing clang-format is straightforward on most OS and distros
(e.g. with https://apt.llvm.org/, brew install clang-format, etc), as this is part of quite commonly
used suite of tools and compilers (llvm / clang).

Additionally, a CI action is present that will verify if the code requires formatting,
and comment on the PR as needed. Initially, correct formatting is not required, it will be
done by maintainers as part of the merge or in later commits, but obviously this is encouraged.

fixes https://github.com/official-stockfish/Stockfish/issues/3608
closes https://github.com/official-stockfish/Stockfish/pull/4790

Co-Authored-By: Joost VandeVondele <Joost.VandeVondele@gmail.com>
This commit is contained in:
Disservin
2023-10-21 11:40:56 +02:00
committed by Joost VandeVondele
parent 8366ec48ae
commit 2d0237db3f
49 changed files with 6403 additions and 6197 deletions

View File

@@ -30,29 +30,50 @@ namespace Stockfish {
namespace {
enum Stages {
MAIN_TT, CAPTURE_INIT, GOOD_CAPTURE, REFUTATION, QUIET_INIT, QUIET, BAD_CAPTURE,
EVASION_TT, EVASION_INIT, EVASION,
PROBCUT_TT, PROBCUT_INIT, PROBCUT,
QSEARCH_TT, QCAPTURE_INIT, QCAPTURE, QCHECK_INIT, QCHECK
};
enum Stages {
// generate main search moves
MAIN_TT,
CAPTURE_INIT,
GOOD_CAPTURE,
REFUTATION,
QUIET_INIT,
QUIET,
BAD_CAPTURE,
// partial_insertion_sort() sorts moves in descending order up to and including
// a given limit. The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
// generate evasion moves
EVASION_TT,
EVASION_INIT,
EVASION,
// generate probcut moves
PROBCUT_TT,
PROBCUT_INIT,
PROBCUT,
// generate qsearch moves
QSEARCH_TT,
QCAPTURE_INIT,
QCAPTURE,
QCHECK_INIT,
QCHECK
};
// partial_insertion_sort() sorts moves in descending order up to and including
// a given limit. The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
for (ExtMove *sortedEnd = begin, *p = begin + 1; p < end; ++p)
if (p->value >= limit)
{
ExtMove tmp = *p, *q;
*p = *++sortedEnd;
*p = *++sortedEnd;
for (q = sortedEnd; q != begin && *(q - 1) < tmp; --q)
*q = *(q - 1);
*q = tmp;
}
}
}
} // namespace
} // namespace
// Constructors of the MovePicker class. As arguments, we pass information
@@ -62,44 +83,57 @@ namespace {
// move ordering is at the current node.
// MovePicker constructor for the main search
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Move cm,
const Move* killers)
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch),
ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d)
{
assert(d > 0);
MovePicker::MovePicker(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Move cm,
const Move* killers) :
pos(p),
mainHistory(mh),
captureHistory(cph),
continuationHistory(ch),
ttMove(ttm),
refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}},
depth(d) {
assert(d > 0);
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) +
!(ttm && pos.pseudo_legal(ttm));
stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + !(ttm && pos.pseudo_legal(ttm));
}
// MovePicker constructor for quiescence search
MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Square rs)
: pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d)
{
assert(d <= 0);
MovePicker::MovePicker(const Position& p,
Move ttm,
Depth d,
const ButterflyHistory* mh,
const CapturePieceToHistory* cph,
const PieceToHistory** ch,
Square rs) :
pos(p),
mainHistory(mh),
captureHistory(cph),
continuationHistory(ch),
ttMove(ttm),
recaptureSquare(rs),
depth(d) {
assert(d <= 0);
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) +
!( ttm
&& pos.pseudo_legal(ttm));
stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));
}
// MovePicker constructor for ProbCut: we generate captures with SEE greater
// than or equal to the given threshold.
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph)
: pos(p), captureHistory(cph), ttMove(ttm), threshold(th)
{
assert(!pos.checkers());
MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) :
pos(p),
captureHistory(cph),
ttMove(ttm),
threshold(th) {
assert(!pos.checkers());
stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm)
&& pos.pseudo_legal(ttm)
&& pos.see_ge(ttm, threshold));
stage = PROBCUT_TT
+ !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold));
}
// MovePicker::score() assigns a numerical value to each move in a list, used
@@ -108,76 +142,78 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePiece
template<GenType Type>
void MovePicker::score() {
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type");
[[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook, threatenedPieces;
if constexpr (Type == QUIETS)
{
Color us = pos.side_to_move();
[[maybe_unused]] Bitboard threatenedByPawn, threatenedByMinor, threatenedByRook,
threatenedPieces;
if constexpr (Type == QUIETS)
{
Color us = pos.side_to_move();
threatenedByPawn = pos.attacks_by<PAWN>(~us);
threatenedByMinor = pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn;
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor;
threatenedByPawn = pos.attacks_by<PAWN>(~us);
threatenedByMinor =
pos.attacks_by<KNIGHT>(~us) | pos.attacks_by<BISHOP>(~us) | threatenedByPawn;
threatenedByRook = pos.attacks_by<ROOK>(~us) | threatenedByMinor;
// Pieces threatened by pieces of lesser material value
threatenedPieces = (pos.pieces(us, QUEEN) & threatenedByRook)
| (pos.pieces(us, ROOK) & threatenedByMinor)
| (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn);
}
// Pieces threatened by pieces of lesser material value
threatenedPieces = (pos.pieces(us, QUEEN) & threatenedByRook)
| (pos.pieces(us, ROOK) & threatenedByMinor)
| (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn);
}
for (auto& m : *this)
if constexpr (Type == CAPTURES)
m.value = (7 * int(PieceValue[pos.piece_on(to_sq(m))])
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]) / 16;
for (auto& m : *this)
if constexpr (Type == CAPTURES)
m.value =
(7 * int(PieceValue[pos.piece_on(to_sq(m))])
+ (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))])
/ 16;
else if constexpr (Type == QUIETS)
{
Piece pc = pos.moved_piece(m);
PieceType pt = type_of(pos.moved_piece(m));
Square from = from_sq(m);
Square to = to_sq(m);
else if constexpr (Type == QUIETS)
{
Piece pc = pos.moved_piece(m);
PieceType pt = type_of(pos.moved_piece(m));
Square from = from_sq(m);
Square to = to_sq(m);
// histories
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)];
m.value += 2 * (*continuationHistory[0])[pc][to];
m.value += (*continuationHistory[1])[pc][to];
m.value += (*continuationHistory[2])[pc][to] / 4;
m.value += (*continuationHistory[3])[pc][to];
m.value += (*continuationHistory[5])[pc][to];
// histories
m.value = 2 * (*mainHistory)[pos.side_to_move()][from_to(m)];
m.value += 2 * (*continuationHistory[0])[pc][to];
m.value += (*continuationHistory[1])[pc][to];
m.value += (*continuationHistory[2])[pc][to] / 4;
m.value += (*continuationHistory[3])[pc][to];
m.value += (*continuationHistory[5])[pc][to];
// bonus for checks
m.value += bool(pos.check_squares(pt) & to) * 16384;
// bonus for checks
m.value += bool(pos.check_squares(pt) & to) * 16384;
// bonus for escaping from capture
m.value += threatenedPieces & from ?
(pt == QUEEN && !(to & threatenedByRook) ? 50000
: pt == ROOK && !(to & threatenedByMinor) ? 25000
: !(to & threatenedByPawn) ? 15000
: 0 )
: 0 ;
// bonus for escaping from capture
m.value += threatenedPieces & from ? (pt == QUEEN && !(to & threatenedByRook) ? 50000
: pt == ROOK && !(to & threatenedByMinor) ? 25000
: !(to & threatenedByPawn) ? 15000
: 0)
: 0;
// malus for putting piece en prise
m.value -= !(threatenedPieces & from) ?
(pt == QUEEN ? bool(to & threatenedByRook) * 50000
+ bool(to & threatenedByMinor) * 10000
+ bool(to & threatenedByPawn) * 20000
: pt == ROOK ? bool(to & threatenedByMinor) * 25000
+ bool(to & threatenedByPawn) * 10000
: pt != PAWN ? bool(to & threatenedByPawn) * 15000
: 0 )
: 0 ;
}
// malus for putting piece en prise
m.value -= !(threatenedPieces & from)
? (pt == QUEEN ? bool(to & threatenedByRook) * 50000
+ bool(to & threatenedByMinor) * 10000
+ bool(to & threatenedByPawn) * 20000
: pt == ROOK ? bool(to & threatenedByMinor) * 25000
+ bool(to & threatenedByPawn) * 10000
: pt != PAWN ? bool(to & threatenedByPawn) * 15000
: 0)
: 0;
}
else // Type == EVASIONS
{
if (pos.capture_stage(m))
m.value = PieceValue[pos.piece_on(to_sq(m))]
- Value(type_of(pos.moved_piece(m)))
+ (1 << 28);
else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)];
}
else // Type == EVASIONS
{
if (pos.capture_stage(m))
m.value = PieceValue[pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m)))
+ (1 << 28);
else
m.value = (*mainHistory)[pos.side_to_move()][from_to(m)]
+ (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)];
}
}
// MovePicker::select() returns the next move satisfying a predicate function.
@@ -185,17 +221,17 @@ void MovePicker::score() {
template<MovePicker::PickType T, typename Pred>
Move MovePicker::select(Pred filter) {
while (cur < endMoves)
{
if constexpr (T == Best)
std::swap(*cur, *std::max_element(cur, endMoves));
while (cur < endMoves)
{
if constexpr (T == Best)
std::swap(*cur, *std::max_element(cur, endMoves));
if (*cur != ttMove && filter())
return *cur++;
if (*cur != ttMove && filter())
return *cur++;
cur++;
}
return MOVE_NONE;
cur++;
}
return MOVE_NONE;
}
// MovePicker::next_move() is the most important method of the MovePicker class. It
@@ -204,122 +240,126 @@ Move MovePicker::select(Pred filter) {
Move MovePicker::next_move(bool skipQuiets) {
top:
switch (stage) {
switch (stage)
{
case MAIN_TT:
case EVASION_TT:
case QSEARCH_TT:
case PROBCUT_TT:
++stage;
return ttMove;
case MAIN_TT :
case EVASION_TT :
case QSEARCH_TT :
case PROBCUT_TT :
++stage;
return ttMove;
case CAPTURE_INIT:
case PROBCUT_INIT:
case QCAPTURE_INIT:
cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur);
case CAPTURE_INIT :
case PROBCUT_INIT :
case QCAPTURE_INIT :
cur = endBadCaptures = moves;
endMoves = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage;
goto top;
score<CAPTURES>();
partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
++stage;
goto top;
case GOOD_CAPTURE:
if (select<Next>([&](){
return pos.see_ge(*cur, Value(-cur->value)) ?
// Move losing capture to endBadCaptures to be tried later
true : (*endBadCaptures++ = *cur, false); }))
return *(cur - 1);
case GOOD_CAPTURE :
if (select<Next>([&]() {
return pos.see_ge(*cur, Value(-cur->value))
?
// Move losing capture to endBadCaptures to be tried later
true
: (*endBadCaptures++ = *cur, false);
}))
return *(cur - 1);
// Prepare the pointers to loop over the refutations array
cur = std::begin(refutations);
endMoves = std::end(refutations);
// Prepare the pointers to loop over the refutations array
cur = std::begin(refutations);
endMoves = std::end(refutations);
// If the countermove is the same as a killer, skip it
if ( refutations[0].move == refutations[2].move
|| refutations[1].move == refutations[2].move)
--endMoves;
// If the countermove is the same as a killer, skip it
if (refutations[0].move == refutations[2].move
|| refutations[1].move == refutations[2].move)
--endMoves;
++stage;
[[fallthrough]];
++stage;
[[fallthrough]];
case REFUTATION:
if (select<Next>([&](){ return *cur != MOVE_NONE
&& !pos.capture_stage(*cur)
&& pos.pseudo_legal(*cur); }))
return *(cur - 1);
++stage;
[[fallthrough]];
case REFUTATION :
if (select<Next>([&]() {
return *cur != MOVE_NONE && !pos.capture_stage(*cur) && pos.pseudo_legal(*cur);
}))
return *(cur - 1);
++stage;
[[fallthrough]];
case QUIET_INIT:
if (!skipQuiets)
{
cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur);
case QUIET_INIT :
if (!skipQuiets)
{
cur = endBadCaptures;
endMoves = generate<QUIETS>(pos, cur);
score<QUIETS>();
partial_insertion_sort(cur, endMoves, -3000 * depth);
}
score<QUIETS>();
partial_insertion_sort(cur, endMoves, -3000 * depth);
}
++stage;
[[fallthrough]];
++stage;
[[fallthrough]];
case QUIET:
if ( !skipQuiets
&& select<Next>([&](){return *cur != refutations[0].move
&& *cur != refutations[1].move
&& *cur != refutations[2].move;}))
return *(cur - 1);
case QUIET :
if (!skipQuiets && select<Next>([&]() {
return *cur != refutations[0].move && *cur != refutations[1].move
&& *cur != refutations[2].move;
}))
return *(cur - 1);
// Prepare the pointers to loop over the bad captures
cur = moves;
endMoves = endBadCaptures;
// Prepare the pointers to loop over the bad captures
cur = moves;
endMoves = endBadCaptures;
++stage;
[[fallthrough]];
++stage;
[[fallthrough]];
case BAD_CAPTURE:
return select<Next>([](){ return true; });
case BAD_CAPTURE :
return select<Next>([]() { return true; });
case EVASION_INIT:
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
case EVASION_INIT :
cur = moves;
endMoves = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
++stage;
[[fallthrough]];
score<EVASIONS>();
++stage;
[[fallthrough]];
case EVASION:
return select<Best>([](){ return true; });
case EVASION :
return select<Best>([]() { return true; });
case PROBCUT:
return select<Next>([&](){ return pos.see_ge(*cur, threshold); });
case PROBCUT :
return select<Next>([&]() { return pos.see_ge(*cur, threshold); });
case QCAPTURE:
if (select<Next>([&](){ return depth > DEPTH_QS_RECAPTURES
|| to_sq(*cur) == recaptureSquare; }))
return *(cur - 1);
case QCAPTURE :
if (select<Next>(
[&]() { return depth > DEPTH_QS_RECAPTURES || to_sq(*cur) == recaptureSquare; }))
return *(cur - 1);
// If we did not find any move and we do not try checks, we have finished
if (depth != DEPTH_QS_CHECKS)
return MOVE_NONE;
// If we did not find any move and we do not try checks, we have finished
if (depth != DEPTH_QS_CHECKS)
return MOVE_NONE;
++stage;
[[fallthrough]];
++stage;
[[fallthrough]];
case QCHECK_INIT:
cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur);
case QCHECK_INIT :
cur = moves;
endMoves = generate<QUIET_CHECKS>(pos, cur);
++stage;
[[fallthrough]];
++stage;
[[fallthrough]];
case QCHECK:
return select<Next>([](){ return true; });
}
case QCHECK :
return select<Next>([]() { return true; });
}
assert(false);
return MOVE_NONE; // Silence warning
assert(false);
return MOVE_NONE; // Silence warning
}
} // namespace Stockfish
} // namespace Stockfish