From bcf9282844f17dbb451231d8ae0a957d1b7be43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 23 Jan 2020 17:17:26 +0100 Subject: [PATCH 001/142] Restore development version No functional change --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 95862ebb..053ee67e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -56,7 +56,7 @@ namespace { /// Version number. If Version is left empty, then compile date in the format /// DD-MM-YY and show in engine_info. -const string Version = "11"; +const string Version = ""; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We From 7a7bcd6359b38651e1bfecf78aa07e633abed5b2 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sat, 21 Dec 2019 15:36:29 -0700 Subject: [PATCH 002/142] Simplify signature of remove_piece() This is a non-functional simplification. Instead of passing the piece type for remove_piece, we can rely on the board. The only exception is en-passant which must be explicitly set because the destination square for the capture is not the same as the piece to remove. Verified also in the Chess960 castling case by running a couple of perft, see the pull request discussion: https://github.com/official-stockfish/Stockfish/pull/2460 STC LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 18624 W: 4147 L: 4070 D: 10407 Ptnml(0-2): 223, 1933, 4945, 1938, 260 http://tests.stockfishchess.org/tests/view/5dfeaa93e70446e17e451163 No functional change --- src/position.cpp | 21 +++++++++++---------- src/position.h | 10 ++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 53d9b64e..de9722ff 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -743,8 +743,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { assert(relative_rank(us, to) == RANK_6); assert(piece_on(to) == NO_PIECE); assert(piece_on(capsq) == make_piece(them, PAWN)); - - board[capsq] = NO_PIECE; // Not done by remove_piece() } st->pawnKey ^= Zobrist::psq[captured][capsq]; @@ -753,7 +751,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { st->nonPawnMaterial[them] -= PieceValue[MG][captured]; // Update board and piece lists - remove_piece(captured, capsq); + remove_piece(capsq); + + if (type_of(m) == ENPASSANT) + board[capsq] = NO_PIECE; // Update material hash key and prefetch access to materialTable k ^= Zobrist::psq[captured][capsq]; @@ -784,7 +785,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // Move the piece. The tricky Chess960 castling is handled earlier if (type_of(m) != CASTLING) - move_piece(pc, from, to); + move_piece(from, to); // If the moving piece is a pawn do some special extra work if (type_of(pc) == PAWN) @@ -804,7 +805,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { assert(relative_rank(us, to) == RANK_8); assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN); - remove_piece(pc, to); + remove_piece(to); put_piece(promotion, to); // Update hash keys @@ -884,7 +885,7 @@ void Position::undo_move(Move m) { assert(type_of(pc) == promotion_type(m)); assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN); - remove_piece(pc, to); + remove_piece(to); pc = make_piece(us, PAWN); put_piece(pc, to); } @@ -896,7 +897,7 @@ void Position::undo_move(Move m) { } else { - move_piece(pc, to, from); // Put the piece back at the source square + move_piece(to, from); // Put the piece back at the source square if (st->capturedPiece) { @@ -936,9 +937,9 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); // Remove both pieces first since squares could overlap in Chess960 - remove_piece(make_piece(us, KING), Do ? from : to); - remove_piece(make_piece(us, ROOK), Do ? rfrom : rto); - board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us + remove_piece(Do ? from : to); + remove_piece(Do ? rfrom : rto); + board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do this for us put_piece(make_piece(us, KING), Do ? to : from); put_piece(make_piece(us, ROOK), Do ? rto : rfrom); } diff --git a/src/position.h b/src/position.h index 6791455f..e5071d53 100644 --- a/src/position.h +++ b/src/position.h @@ -174,8 +174,8 @@ private: // Other helpers void put_piece(Piece pc, Square s); - void remove_piece(Piece pc, Square s); - void move_piece(Piece pc, Square from, Square to); + void remove_piece(Square s); + void move_piece(Square from, Square to); template void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto); @@ -412,12 +412,13 @@ inline void Position::put_piece(Piece pc, Square s) { psq += PSQT::psq[pc][s]; } -inline void Position::remove_piece(Piece pc, Square s) { +inline void Position::remove_piece(Square s) { // WARNING: This is not a reversible operation. If we remove a piece in // do_move() and then replace it in undo_move() we will put it at the end of // the list and not in its original place, it means index[] and pieceList[] // are not invariant to a do_move() + undo_move() sequence. + Piece pc = board[s]; byTypeBB[ALL_PIECES] ^= s; byTypeBB[type_of(pc)] ^= s; byColorBB[color_of(pc)] ^= s; @@ -430,10 +431,11 @@ inline void Position::remove_piece(Piece pc, Square s) { psq -= PSQT::psq[pc][s]; } -inline void Position::move_piece(Piece pc, Square from, Square to) { +inline void Position::move_piece(Square from, Square to) { // index[from] is not updated and becomes stale. This works as long as index[] // is accessed just by known occupied squares. + Piece pc = board[from]; Bitboard fromTo = from | to; byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; From 75dfdeac119d0ce71c36ba5ab4f33318f589b158 Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 10 Jan 2020 15:08:47 -0700 Subject: [PATCH 003/142] Simplify KPK classify This is a non-functional simplification. If we use the "side to move" of the entry instead of the template, one of the classify methods goes away. Furthermore, I've resolved the colors in some of the statements (we're already assuming direction using NORTH), and used stm (side to move) instead of "us," since this is much clearer to me. This is not tested because it is non-functional, only applies building the bitbase and there are no changes to the binary (on my machine). Closes https://github.com/official-stockfish/Stockfish/pull/2485 No functional change --- src/bitbase.cpp | 56 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 78614fa2..7bc4a65c 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -43,8 +43,8 @@ namespace { // bit 12: side to move (WHITE or BLACK) // bit 13-14: white pawn file (from FILE_A to FILE_D) // bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2) - unsigned index(Color us, Square bksq, Square wksq, Square psq) { - return int(wksq) | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); + unsigned index(Color stm, Square bksq, Square wksq, Square psq) { + return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); } enum Result { @@ -60,12 +60,9 @@ namespace { KPKPosition() = default; explicit KPKPosition(unsigned idx); operator Result() const { return result; } - Result classify(const std::vector& db) - { return us == WHITE ? classify(db) : classify(db); } + Result classify(const std::vector& db); - template Result classify(const std::vector& db); - - Color us; + Color stm; Square ksq[COLOR_NB], psq; Result result; }; @@ -73,11 +70,11 @@ namespace { } // namespace -bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color us) { +bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { assert(file_of(wpsq) <= FILE_D); - unsigned idx = index(us, bksq, wksq, wpsq); + unsigned idx = index(stm, bksq, wksq, wpsq); return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); } @@ -110,28 +107,28 @@ namespace { ksq[WHITE] = Square((idx >> 0) & 0x3F); ksq[BLACK] = Square((idx >> 6) & 0x3F); - us = Color ((idx >> 12) & 0x01); + stm = Color ((idx >> 12) & 0x01); psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7))); // Check if two pieces are on the same square or if a king can be captured if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 || ksq[WHITE] == psq || ksq[BLACK] == psq - || (us == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) + || (stm == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) result = INVALID; // Immediate win if a pawn can be promoted without getting captured - else if ( us == WHITE + else if ( stm == WHITE && rank_of(psq) == RANK_7 - && ksq[us] != psq + NORTH - && ( distance(ksq[~us], psq + NORTH) > 1 - || (PseudoAttacks[KING][ksq[us]] & (psq + NORTH)))) + && ksq[stm] != psq + NORTH + && ( distance(ksq[~stm], psq + NORTH) > 1 + || (PseudoAttacks[KING][ksq[stm]] & (psq + NORTH)))) result = WIN; // Immediate draw if it is a stalemate or a king captures undefended pawn - else if ( us == BLACK - && ( !(PseudoAttacks[KING][ksq[us]] & ~(PseudoAttacks[KING][ksq[~us]] | PawnAttacks[~us][psq])) - || (PseudoAttacks[KING][ksq[us]] & psq & ~PseudoAttacks[KING][ksq[~us]]))) + else if ( stm == BLACK + && ( !(PseudoAttacks[KING][ksq[stm]] & ~(PseudoAttacks[KING][ksq[~stm]] | PawnAttacks[~stm][psq])) + || (PseudoAttacks[KING][ksq[stm]] & psq & ~PseudoAttacks[KING][ksq[~stm]]))) result = DRAW; // Position will be classified later @@ -139,7 +136,6 @@ namespace { result = UNKNOWN; } - template Result KPKPosition::classify(const std::vector& db) { // White to move: If one move leads to a position classified as WIN, the result @@ -151,27 +147,25 @@ namespace { // of the current position is DRAW. If all moves lead to positions classified // as WIN, the position is classified as WIN, otherwise the current position is // classified as UNKNOWN. - - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Result Good = (Us == WHITE ? WIN : DRAW); - constexpr Result Bad = (Us == WHITE ? DRAW : WIN); + const Result Good = (stm == WHITE ? WIN : DRAW); + const Result Bad = (stm == WHITE ? DRAW : WIN); Result r = INVALID; - Bitboard b = PseudoAttacks[KING][ksq[Us]]; + Bitboard b = PseudoAttacks[KING][ksq[stm]]; while (b) - r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)] - : db[index(Them, pop_lsb(&b), ksq[Them] , psq)]; + r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)] + : db[index(WHITE, pop_lsb(&b), ksq[WHITE], psq)]; - if (Us == WHITE) + if (stm == WHITE) { if (rank_of(psq) < RANK_7) // Single push - r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)]; + r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)]; if ( rank_of(psq) == RANK_2 // Double push - && psq + NORTH != ksq[Us] - && psq + NORTH != ksq[Them]) - r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)]; + && psq + NORTH != ksq[WHITE] + && psq + NORTH != ksq[BLACK]) + r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)]; } return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad; From f3c83ed46cdc2062c30551f457ac53ad635794ea Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 23 Dec 2019 10:58:30 -0700 Subject: [PATCH 004/142] Determine opposite colors mathematically This is a non-functional speed-up: master has to access SquareBB twice while this patch determines opposite_colors just using the values of the squares. It doesn't seem to change the overall speed of bench, but calling opposite_colors(...) 10 Million times: master: 39.4 seconds patch: 11.4 seconds. The only data point I have (other than my own tests), is a quite old failed STC test: LLR: -2.93 (-2.94,2.94) [-1.50,4.50] Total: 24308 W: 5331 L: 5330 D: 13647 Ptnml(0-2): 315, 2577, 6326, 2623, 289 http://tests.stockfishchess.org/tests/view/5e010256c13ac2425c4a9a67 Closes https://github.com/official-stockfish/Stockfish/pull/2498 No functional change --- src/bitboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 440de1ea..d11b7e73 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -129,8 +129,8 @@ constexpr bool more_than_one(Bitboard b) { return b & (b - 1); } -inline bool opposite_colors(Square s1, Square s2) { - return bool(DarkSquares & s1) != bool(DarkSquares & s2); +constexpr bool opposite_colors(Square s1, Square s2) { + return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1; } From 6f1013794cecc179e7432004b8555e64ddca75a5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 23 Jan 2020 18:18:58 +0100 Subject: [PATCH 005/142] Use a std::bitset for KPKBitbase This is a non-functional simplification. Looks like std::bitset works good for the KPKBitbase. Thanks for Jorg Oster for helping get the speed up (the [] accessor is faster than test()). Speed testing: 10k calls to probe: master 9.8 sec patch 9.8 sec. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 100154 W: 19025 L: 18992 D: 62137 Ptnml(0-2): 1397, 11376, 24572, 11254, 1473 http://tests.stockfishchess.org/tests/view/5e21e601346e35ac603b7d2b Closes https://github.com/official-stockfish/Stockfish/pull/2502 No functional change --- src/bitbase.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 7bc4a65c..ed6ed208 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "bitboard.h" #include "types.h" @@ -31,8 +32,7 @@ namespace { // Positions with the pawn on files E to H will be mirrored before probing. constexpr unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608 - // Each uint32_t stores results of 32 positions, one per bit - uint32_t KPKBitbase[MAX_INDEX / 32]; + std::bitset KPKBitbase; // A KPK bitbase index is an integer in [0, IndexMax] range // @@ -74,8 +74,7 @@ bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { assert(file_of(wpsq) <= FILE_D); - unsigned idx = index(stm, bksq, wksq, wpsq); - return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); + return KPKBitbase[index(stm, bksq, wksq, wpsq)]; } @@ -94,10 +93,10 @@ void Bitbases::init() { for (repeat = idx = 0; idx < MAX_INDEX; ++idx) repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN); - // Map 32 results into one KPKBitbase[] entry + // Fill the bitbase with the decisive results for (idx = 0; idx < MAX_INDEX; ++idx) if (db[idx] == WIN) - KPKBitbase[idx / 32] |= 1 << (idx & 0x1F); + KPKBitbase.set(idx); } From 7ed817d7e4847196a5ba0a3aded0519000074be7 Mon Sep 17 00:00:00 2001 From: Chess13234 <37609326+Chess13234@users.noreply.github.com> Date: Tue, 21 Jan 2020 18:20:00 +0200 Subject: [PATCH 006/142] Minor fixes for misc.cpp Fixes conflict with tune.h STRINGIFY macro. No functional change --- src/misc.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 053ee67e..484d0b21 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -155,9 +155,9 @@ const string engine_info(bool to_uci) { const std::string compiler_info() { - #define STRINGIFY2(x) #x - #define STRINGIFY(x) STRINGIFY2(x) - #define VER_STRING(major, minor, patch) STRINGIFY(major) "." STRINGIFY(minor) "." STRINGIFY(patch) + #define stringify2(x) #x + #define stringify(x) stringify2(x) + #define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch) /// Predefined macros hell: /// @@ -171,20 +171,20 @@ const std::string compiler_info() { #ifdef __clang__ compiler += "clang++ "; - compiler += VER_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__); + compiler += make_version_string(__clang_major__, __clang_minor__, __clang_patchlevel__); #elif __INTEL_COMPILER compiler += "Intel compiler "; compiler += "(version "; - compiler += STRINGIFY(__INTEL_COMPILER) " update " STRINGIFY(__INTEL_COMPILER_UPDATE); + compiler += stringify(__INTEL_COMPILER) " update " stringify(__INTEL_COMPILER_UPDATE); compiler += ")"; #elif _MSC_VER compiler += "MSVC "; compiler += "(version "; - compiler += STRINGIFY(_MSC_FULL_VER) "." STRINGIFY(_MSC_BUILD); + compiler += stringify(_MSC_FULL_VER) "." stringify(_MSC_BUILD); compiler += ")"; #elif __GNUC__ compiler += "g++ (GNUC) "; - compiler += VER_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); + compiler += make_version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); #else compiler += "Unknown compiler "; compiler += "(unknown version)"; From f63d112c710fcd38c9d4946f38603b9c2b4689a4 Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Thu, 16 Jan 2020 08:39:20 +0100 Subject: [PATCH 007/142] Use (strict) greater-than-operator for 'improving' Currently on a normal bench run in ~0,7% of cases 'improving' is set to true although the static eval isn't improving at all, just keeping equal. It looks like the strict gt-operator is more appropriate here, since it returns to 'improving' its literal meaning without sideffects. STC {-1.00,3.00} failed yellow: https://tests.stockfishchess.org/tests/view/5e1ec38c8fd5f550e4ae1c28 LLR: -2.93 (-2.94,2.94) {-1.00,3.00} Total: 53155 W: 10170 L: 10109 D: 32876 Ptnml(0-2): 863, 6282, 12251, 6283, 892 non-regression LTC passed: https://tests.stockfishchess.org/tests/view/5e1f1c0d8fd5f550e4ae1c41 LLR: 2.98 (-2.94,2.94) {-1.50,0.50} Total: 23961 W: 3114 L: 3018 D: 17829 Ptnml(0-2): 163, 2220, 7114, 2298, 170 CLoses https://github.com/official-stockfish/Stockfish/pull/2496 bench: 4561386 --- src/search.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 0eea4127..21df156c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -625,7 +625,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving , didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -825,8 +825,9 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); - improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval >= (ss-4)->staticEval - || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval >= (ss-2)->staticEval; + // (~13 Elo) + improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval > (ss-4)->staticEval + || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval > (ss-2)->staticEval; // Step 8. Futility pruning: child node (~50 Elo) if ( !PvNode From 56e698ef8382cc837507c8910bf2409ebb4aec77 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 21 Jan 2020 09:28:58 +0100 Subject: [PATCH 008/142] Less reduction for escape moves at ttPv nodes At expected PV nodes or nodes which marked as PV node in the hash table, reduce escape moves even one ply less. STC: LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 31795 W: 6140 L: 5953 D: 19702 Ptnml(0-2): 525, 3625, 7455, 3695, 583 http://tests.stockfishchess.org/tests/view/5e25d77fc3b97aa0d75bc013 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 43975 W: 5708 L: 5454 D: 32813 Ptnml(0-2): 314, 4012, 13070, 4242, 325 http://tests.stockfishchess.org/tests/view/5e2618c1c3b97aa0d75bc03c Closes https://github.com/official-stockfish/Stockfish/pull/2505 Bench: 4475583 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 21df156c..3bd1a92d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -625,7 +625,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving , didLMR, priorCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -825,7 +825,6 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); - // (~13 Elo) improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval > (ss-2)->staticEval; @@ -1161,7 +1160,7 @@ moves_loop: // When in check, search starts from here // hence break make_move(). (~2 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) - r -= 2; + r -= 2 + ttPv; ss->statScore = thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] From 18fc21eba0368fd5e3c4c4b8ee1000c9ac445425 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 22 Jan 2020 03:54:44 +0300 Subject: [PATCH 009/142] Tweak trapped rook penalty This patch greatly increases the endgame penalty for having a trapped rook. Idea was a result of witnessing Stockfish losing some games at CCCC exchanging pieces in the position with a trapped rook which directly lead to a lost endgame. This patch should partially fix such behavior making this penalty high even in deep endgames. Passed STC http://tests.stockfishchess.org/tests/view/5e279d7cc3b97aa0d75bc1c4 LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 8528 W: 1706 L: 1588 D: 5234 Ptnml(0-2): 133, 957, 1985, 1024, 159 Passed LTC http://tests.stockfishchess.org/tests/view/5e27aee4c3b97aa0d75bc1e1 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 88713 W: 11520 L: 11130 D: 66063 Ptnml(0-2): 646, 8170, 26342, 8492, 676 Closes https://github.com/official-stockfish/Stockfish/pull/2510 Bench: 4964462 ---------------------- Comment by Malcolm Campbell: Congrats! I think this might be a common pattern - scores that seem to mainly apply to the midgame are often better with a similar (or at least fairly big) endgame value as well. Maybe there are others eval parameters we can tweak like this... --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7c7ce95c..fad0771d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -145,7 +145,7 @@ namespace { constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); + constexpr Score TrappedRook = S( 52, 30); constexpr Score WeakQueen = S( 49, 15); #undef S From 01b6088af39902001d2d6844561b6a2faa549282 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 23 Jan 2020 15:41:03 +0100 Subject: [PATCH 010/142] History update for pruned captures Use a SEE pruned capture move for history updates: this patch collects pruned capture moves also in the failed captures list, so that they get an update in capture history. STC: LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 11124 W: 2222 L: 2089 D: 6813 Ptnml(0-2): 186, 1280, 2506, 1381, 200 http://tests.stockfishchess.org/tests/view/5e28995fc3b97aa0d75bc294 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 25552 W: 3418 L: 3211 D: 18923 Ptnml(0-2): 168, 2354, 7538, 2490, 200 http://tests.stockfishchess.org/tests/view/5e2943734744cfa4d6af415b Closes https://github.com/official-stockfish/Stockfish/pull/2511 Bench: 4810202 --- src/search.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3bd1a92d..1490a266 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1028,7 +1028,11 @@ moves_loop: // When in check, search starts from here continue; } else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - continue; + { + if (captureOrPromotion && captureCount < 32) + capturesSearched[captureCount++] = move; + continue; + } } // Step 14. Extensions (~75 Elo) From 0ae00454ba6928d181b46103e5c83e6d58fcebe5 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Fri, 24 Jan 2020 23:04:35 +0100 Subject: [PATCH 011/142] Tweak RestrictedPiece bonus Double the "RestrictedPiece" bonus for restricted moves targeting occupied squares. STC LLR: 3.58 (-2.94,2.94) {-1.00,3.00} Total: 25504 W: 4887 L: 4697 D: 15920 Ptnml(0-2): 387, 2935, 5947, 3051, 422 https://tests.stockfishchess.org/tests/view/5e2aa15dab2d69d58394f94d LTC LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 28572 W: 3826 L: 3621 D: 21125 Ptnml(0-2): 224, 2609, 8403, 2791, 239 https://tests.stockfishchess.org/tests/view/5e2ae7f4ab2d69d58394f9a6 Bench: 4719086 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fad0771d..a1a3b4ed 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -520,11 +520,11 @@ namespace { } // Bonus for restricting their piece moves + // Greater bonus when landing square is occupied b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - - score += RestrictedPiece * popcount(b); + score += RestrictedPiece * (popcount(b) + popcount(b & pos.pieces())); // Protected or unattacked squares safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; From 6d0eabd5fe2961551477820ab7619e2c31e01ffd Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 25 Jan 2020 07:59:42 -0500 Subject: [PATCH 012/142] Dynamic complexity Instead of computing the initiative bonus on the material score + dynamic score compute it on (material score/2) + dynamic score, Passed STC http://tests.stockfishchess.org/tests/view/5e2c4945ab2d69d58394fa8f LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 39387 W: 7594 L: 7386 D: 24407 Ptnml(0-2): 658, 4519, 9165, 4649, 697 Passed LTC http://tests.stockfishchess.org/tests/view/5e2c85ccab2d69d58394faa7 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 32588 W: 4206 L: 3986 D: 24396 Ptnml(0-2): 244, 2909, 9738, 3111, 253 closes https://github.com/official-stockfish/Stockfish/pull/2516 Bench: 4765486 --- src/evaluate.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a1a3b4ed..be39f8a7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -168,7 +168,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score) const; + Score initiative(Score score, Score materialScore) const; const Position& pos; Material::Entry* me; @@ -696,10 +696,7 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Score score) const { - - Value mg = mg_value(score); - Value eg = eg_value(score); + Score Evaluation::initiative(Score score, Score materialScore) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -724,6 +721,11 @@ namespace { - 43 * almostUnwinnable - 100 ; + // Give more importance to non-material score + score = (score * 2 - materialScore) / 2; + Value mg = mg_value(score); + Value eg = eg_value(score); + // Now apply the bonus: note that we find the attacking side by extracting the // sign of the midgame or endgame values, and that we carefully cap the bonus // so that the midgame and endgame scores do not change sign after the bonus. @@ -792,6 +794,9 @@ namespace { if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; + // Remember this score + Score materialScore = score; + // Main evaluation begins here initialize(); @@ -810,7 +815,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(score); + score += initiative(score, materialScore); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); From 39437f4e55aaa26ef9f0d5a1c762e560e9ffde32 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Sat, 21 Dec 2019 21:41:42 +0200 Subject: [PATCH 013/142] Advise the kernel to use huge pages (Linux) Align the TT allocation by 2M to make it huge page friendly and advise the kernel to use huge pages. Benchmarks on my i7-8700K (6C/12T) box: (3 runs per bench per config) vanilla (nps) hugepages (nps) avg ================================================================================== bench | 3012490 3024364 3036331 3071052 3067544 3071052 +1.5% bench 16 12 20 | 19237932 19050166 19085315 19266346 19207025 19548758 +1.1% bench 16384 12 20 | 18182313 18371581 18336838 19381275 19738012 19620225 +7.0% On my box, huge pages have a significant perf impact when using a big hash size. They also speed up TT initialization big time: vanilla (s) huge pages (s) speed-up ======================================================================= time stockfish bench 16384 1 1 | 5.37 1.48 3.6x In practice, huge pages with auto-defrag may always be enabled in the system, in which case this patch has no effect. This depends on the values in /sys/kernel/mm/transparent_hugepage/enabled and /sys/kernel/mm/transparent_hugepage/defrag. closes https://github.com/official-stockfish/Stockfish/pull/2463 No functional change --- src/misc.cpp | 36 +++++++++++++++++++++++++++++++++++- src/misc.h | 1 + src/tt.cpp | 6 ++---- src/tt.h | 16 +++++++--------- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 484d0b21..0bae9f1e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -47,6 +47,11 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); #include #include +#ifdef __linux__ +#include +#include +#endif + #include "misc.h" #include "thread.h" @@ -190,7 +195,7 @@ const std::string compiler_info() { compiler += "(unknown version)"; #endif - #if defined(__APPLE__) + #if defined(__APPLE__) compiler += " on Apple"; #elif defined(__CYGWIN__) compiler += " on Cygwin"; @@ -288,6 +293,35 @@ void prefetch(void* addr) { #endif + +/// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages. +/// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free. +/// With c++17 some of this functionality can be simplified. +#ifdef __linux__ + +void* aligned_ttmem_alloc(size_t allocSize, void** mem) { + + constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes + size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment + *mem = aligned_alloc(alignment, size); + madvise(*mem, allocSize, MADV_HUGEPAGE); + return *mem; +} + +#else + +void* aligned_ttmem_alloc(size_t allocSize, void** mem) { + + constexpr size_t alignment = 64; // assumed cache line size + size_t size = allocSize + alignment - 1; // allocate some extra space + *mem = malloc(size); + void* ret = reinterpret_cast((uintptr_t(*mem) + alignment - 1) & ~uintptr_t(alignment - 1)); + return ret; +} + +#endif + + namespace WinProcGroup { #ifndef _WIN32 diff --git a/src/misc.h b/src/misc.h index b11c5aa8..45d9951a 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,6 +33,7 @@ const std::string engine_info(bool to_uci = false); const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); +void* aligned_ttmem_alloc(size_t size, void** mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 0b4a59de..080d3a6b 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,11 +63,10 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); - free(mem); - mem = malloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1); + clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); + table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), &mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize @@ -75,7 +74,6 @@ void TranspositionTable::resize(size_t mbSize) { exit(EXIT_FAILURE); } - table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1)); clear(); } diff --git a/src/tt.h b/src/tt.h index 98b054d3..142afd90 100644 --- a/src/tt.h +++ b/src/tt.h @@ -57,24 +57,22 @@ private: }; -/// A TranspositionTable consists of a power of 2 number of clusters and each -/// cluster consists of ClusterSize number of TTEntry. Each non-empty entry -/// contains information of exactly one position. The size of a cluster should -/// divide the size of a cache line size, to ensure that clusters never cross -/// cache lines. This ensures best cache performance, as the cacheline is -/// prefetched, as soon as possible. +/// A TranspositionTable is an array of Cluster, of size clusterCount. Each +/// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry +/// contains information on exactly one position. The size of a Cluster should +/// divide the size of a cache line for best performance, +/// as the cacheline is prefetched when possible. class TranspositionTable { - static constexpr int CacheLineSize = 64; static constexpr int ClusterSize = 3; struct Cluster { TTEntry entry[ClusterSize]; - char padding[2]; // Align to a divisor of the cache line size + char padding[2]; // Pad to 32 bytes }; - static_assert(CacheLineSize % sizeof(Cluster) == 0, "Cluster size incorrect"); + static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); public: ~TranspositionTable() { free(mem); } From 1d3efff47274bd03d4deced8d7ba0360bd1dba8a Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Mon, 27 Jan 2020 09:25:41 -0500 Subject: [PATCH 014/142] Dynamic Complexity based on psqt Adjust initiative score by psqt/2 instead of materialScore/2 which simplifies #2516 Passed STC http://tests.stockfishchess.org/tests/view/5e2e667dab2d69d58394fc73 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 23198 W: 4506 L: 4353 D: 14339 Ptnml(0-2): 396, 2615, 5380, 2728, 418 Passed LTC http://tests.stockfishchess.org/tests/view/5e2ed75cab2d69d58394fcbf LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 8519 W: 1179 L: 1062 D: 6278 Ptnml(0-2): 50, 775, 2472, 843, 74 closes https://github.com/official-stockfish/Stockfish/pull/2522 Bench: 4684459 --- src/evaluate.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index be39f8a7..8d7976d5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -168,7 +168,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score, Score materialScore) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@ -696,7 +696,7 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Score score, Score materialScore) const { + Score Evaluation::initiative(Score score) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -722,7 +722,7 @@ namespace { - 100 ; // Give more importance to non-material score - score = (score * 2 - materialScore) / 2; + score = score - pos.psq_score() / 2; Value mg = mg_value(score); Value eg = eg_value(score); @@ -794,9 +794,6 @@ namespace { if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; - // Remember this score - Score materialScore = score; - // Main evaluation begins here initialize(); @@ -815,7 +812,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(score, materialScore); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); From d878bc8cda47044f4db37a954f25e6122dc0d0ca Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Mon, 27 Jan 2020 20:48:01 -0500 Subject: [PATCH 015/142] Less NMP if the position was previously in PV. The intention of the patch is to avoid aggressive null move pruning (NMP) in positions that have previously been found to be important (PV nodes). If we already do not apply NMP for current PV nodes, it makes sense to apply it less often for positions that have previously been PV nodes too. STC: LLR: 2.96 (-2.94,2.94) {-1.00,3.00} Total: 14959 W: 2921 L: 2782 D: 9256 Ptnml(0-2): 254, 1679, 3493, 1762, 282 http://tests.stockfishchess.org/tests/view/5e2f6637ab2d69d58394fcfd LTC: LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 6442 W: 899 L: 753 D: 4790 Ptnml(0-2): 42, 549, 1885, 659, 61 http://tests.stockfishchess.org/tests/view/5e2f767bab2d69d58394fd04 closes https://github.com/official-stockfish/Stockfish/pull/2525 Bench: 4725546 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 1490a266..044187e5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -841,7 +841,7 @@ namespace { && (ss-1)->statScore < 23397 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 32 * depth + 292 - improving * 30 + && ss->staticEval >= beta - 32 * depth - 30 * improving + 120 * ttPv + 292 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) From 71e0b5385e2717679a57c6b77d8c7ac5fff3b89f Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Tue, 28 Jan 2020 13:38:03 +0100 Subject: [PATCH 016/142] More bonus for bestMoves on past PV nodes It looks like it is important to keep past PV (ttPv) nodes as close as possible to current PV nodes. Credits to Mark Tenzer (31m059) & Stefan Geschwentner who first tried ideas on ttPv nodes. STC: https://tests.stockfishchess.org/tests/view/5e2ff5efab2d69d58394fd52 LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 13302 W: 2647 L: 2507 D: 8148 Ptnml(0-2): 237, 1540, 2956, 1632, 260 LTC: https://tests.stockfishchess.org/tests/view/5e2fff38ab2d69d58394fd55 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 15797 W: 2137 L: 1960 D: 11700 Ptnml(0-2): 96, 1443, 4628, 1547, 130 closes https://github.com/official-stockfish/Stockfish/pull/2529 bench: 5545845 --- src/search.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 044187e5..84f9bb23 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -158,7 +158,7 @@ namespace { void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV); // perft() is our utility to verify move generation. All the leaf nodes up // to the given depth are generated and counted, and the sum is returned. @@ -713,7 +713,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth + (!PvNode && ttPv))); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -722,7 +722,7 @@ namespace { // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) { - int penalty = -stat_bonus(depth); + int penalty = -stat_bonus(depth + (!PvNode && ttPv)); thisThread->mainHistory[us][from_to(ttMove)] << penalty; update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } @@ -1326,7 +1326,7 @@ moves_loop: // When in check, search starts from here else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, - quietsSearched, quietCount, capturesSearched, captureCount, depth); + quietsSearched, quietCount, capturesSearched, captureCount, depth, (!PvNode && ttPv)); // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) @@ -1602,7 +1602,7 @@ moves_loop: // When in check, search starts from here // update_all_stats() updates stats at the end of search() when a bestMove is found void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV) { int bonus1, bonus2; Color us = pos.side_to_move(); @@ -1612,8 +1612,8 @@ moves_loop: // When in check, search starts from here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : stat_bonus(depth); // smaller bonus + bonus2 = pastPV || bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus if (!pos.capture_or_promotion(bestMove)) { From a910ba71eedde4f67805f05b29215cbeff4fe5f1 Mon Sep 17 00:00:00 2001 From: joergoster Date: Mon, 27 Jan 2020 18:53:25 +0100 Subject: [PATCH 017/142] Simplify hashfull calculation. We can simplify the calculation of the hashfull info by looping over exact 1,000 entries, and then divide the result by ClusterSize. Somewhat memory accesses, somewhat more accurate. Passed non-regression LTC https://tests.stockfishchess.org/tests/view/5e30079dab2d69d58394fd5d LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 30125 W: 3987 L: 3926 D: 22212 Ptnml(0-2): 177, 2504, 9558, 2642, 141 closes https://github.com/official-stockfish/Stockfish/pull/2523 No functional change. --- src/tt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tt.cpp b/src/tt.cpp index 080d3a6b..46860fe9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -148,9 +148,9 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { int TranspositionTable::hashfull() const { int cnt = 0; - for (int i = 0; i < 1000 / ClusterSize; ++i) + for (int i = 0; i < 1000; ++i) for (int j = 0; j < ClusterSize; ++j) cnt += (table[i].entry[j].genBound8 & 0xF8) == generation8; - return cnt * 1000 / (ClusterSize * (1000 / ClusterSize)); + return cnt / ClusterSize; } From 3b70932b0dee0cf1817baf0daa43ac92e18003c4 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 28 Jan 2020 16:17:52 +0100 Subject: [PATCH 018/142] Fix compilation on android Fall back to the default implementation of aligned_ttmem_alloc, which was introduced as part of 39437f4e55aaa26ef9f0d5a1c762e560e9ffde32 Fixes #2524 No functional change. --- src/misc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 0bae9f1e..cf18d2e2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -47,7 +47,7 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); #include #include -#ifdef __linux__ +#if defined(__linux__) && !defined(__ANDROID__) #include #include #endif @@ -297,7 +297,7 @@ void prefetch(void* addr) { /// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages. /// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free. /// With c++17 some of this functionality can be simplified. -#ifdef __linux__ +#if defined(__linux__) && !defined(__ANDROID__) void* aligned_ttmem_alloc(size_t allocSize, void** mem) { From 6ccb1cac5aaaf7337da8b1738448793be63fdfdb Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 30 Jan 2020 21:44:04 +0100 Subject: [PATCH 019/142] Revert 5 recent patches Revert 5 patches which were merged, but lead to a regression test that showed negative Elo gain: http://tests.stockfishchess.org/tests/view/5e307251ab2d69d58394fdb9 This was discussed in depth in: https://github.com/official-stockfish/Stockfish/issues/2531 Each patch was removed and tested as a simplification, full list below, and the whole combo as well. After the revert the regression test showed a neutral result: http://tests.stockfishchess.org/tests/view/5e334851708b13464ceea33c As a result of this experience, the SPRT testing bounds will be made more strict. Reverted patches: 1 Dynamic Complexity 6d0eabd5fe2961551477820ab7619e2c31e01ffd : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fcacec661e2e6a340d08 : LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 38130 W: 7326 L: 7189 D: 23615 Ptnml(0-2): 677, 4346, 8843, 4545, 646 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c18fec661e2e6a340d73 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 38675 W: 4941 L: 4866 D: 28868 Ptnml(0-2): 270, 3556, 11429, 3584, 291 3 More bonus for bestMoves on past PV nodes 71e0b5385e2717679a57c6b77d8c7ac5fff3b89f : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fe93ec661e2e6a340d10 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 46100 W: 8853 L: 8727 D: 28520 Ptnml(0-2): 796, 5297, 10749, 5387, 813 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c187ec661e2e6a340d71 : LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 16920 W: 2161 L: 2055 D: 12704 Ptnml(0-2): 115, 1498, 5006, 1569, 130 4 Tweak Restricted Piece Bonus 0ae00454ba6928d181b46103e5c83e6d58fcebe5 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fefaec661e2e6a340d15 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 88328 W: 17060 L: 16997 D: 54271 Ptnml(0-2): 1536, 10446, 20169, 10422, 1581 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c17aec661e2e6a340d6f : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 34784 W: 4551 L: 4466 D: 25767 Ptnml(0-2): 255, 3279, 10061, 3345, 262 5 History update for pruned captures 01b6088af39902001d2d6844561b6a2faa549282 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31ff5eec661e2e6a340d1a : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 29541 W: 5735 L: 5588 D: 18218 Ptnml(0-2): 483, 3445, 6820, 3469, 545 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c196ec661e2e6a340d75 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 22177 W: 2854 L: 2757 D: 16566 Ptnml(0-2): 143, 2005, 6555, 2055, 164 6 Tweak trapped rook penalty 18fc21eba0368fd5e3c4c4b8ee1000c9ac445425 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31ffb1ec661e2e6a340d1c : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 24476 W: 4727 L: 4569 D: 15180 Ptnml(0-2): 390, 2834, 5659, 2933, 417 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c19eec661e2e6a340d77 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 97332 W: 12492 L: 12466 D: 72374 Ptnml(0-2): 690, 9107, 28738, 9034, 720 All 5 as one simplification : LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e334098708b13464ceea330 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 7829 W: 1079 L: 964 D: 5786 Ptnml(0-2): 52, 690, 2281, 781, 65 Bench: 5153165 --- src/evaluate.cpp | 5 ++--- src/search.cpp | 18 +++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8d7976d5..bf1eee9b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -145,7 +145,7 @@ namespace { constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 30); + constexpr Score TrappedRook = S( 52, 10); constexpr Score WeakQueen = S( 49, 15); #undef S @@ -524,7 +524,7 @@ namespace { b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - score += RestrictedPiece * (popcount(b) + popcount(b & pos.pieces())); + score += RestrictedPiece * popcount(b); // Protected or unattacked squares safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; @@ -722,7 +722,6 @@ namespace { - 100 ; // Give more importance to non-material score - score = score - pos.psq_score() / 2; Value mg = mg_value(score); Value eg = eg_value(score); diff --git a/src/search.cpp b/src/search.cpp index 84f9bb23..985af7bc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -158,7 +158,7 @@ namespace { void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV); + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); // perft() is our utility to verify move generation. All the leaf nodes up // to the given depth are generated and counted, and the sum is returned. @@ -713,7 +713,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth + (!PvNode && ttPv))); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -722,7 +722,7 @@ namespace { // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) { - int penalty = -stat_bonus(depth + (!PvNode && ttPv)); + int penalty = -stat_bonus(depth); thisThread->mainHistory[us][from_to(ttMove)] << penalty; update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } @@ -1028,11 +1028,7 @@ moves_loop: // When in check, search starts from here continue; } else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - { - if (captureOrPromotion && captureCount < 32) - capturesSearched[captureCount++] = move; continue; - } } // Step 14. Extensions (~75 Elo) @@ -1326,7 +1322,7 @@ moves_loop: // When in check, search starts from here else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, - quietsSearched, quietCount, capturesSearched, captureCount, depth, (!PvNode && ttPv)); + quietsSearched, quietCount, capturesSearched, captureCount, depth); // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) @@ -1602,7 +1598,7 @@ moves_loop: // When in check, search starts from here // update_all_stats() updates stats at the end of search() when a bestMove is found void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV) { + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { int bonus1, bonus2; Color us = pos.side_to_move(); @@ -1612,8 +1608,8 @@ moves_loop: // When in check, search starts from here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = pastPV || bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : stat_bonus(depth); // smaller bonus + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus if (!pos.capture_or_promotion(bestMove)) { From c390b734c451b3d976b331244e281d261b26ac3a Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 30 Jan 2020 20:42:58 +0000 Subject: [PATCH 020/142] Simplify Tweak late move reductions at root. Revert change from Jan 15. STC 10+0.1 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 65135 W: 12543 L: 12436 D: 40156 Ptnml(0-2): 1090, 7618, 14947, 7623, 1136 https://tests.stockfishchess.org/tests/view/5e334016708b13464ceea32e LTC 60+0.6 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 17768 W: 2286 L: 2191 D: 13291 Ptnml(0-2): 128, 1602, 5273, 1679, 140 https://tests.stockfishchess.org/tests/view/5e34011e57e1ecae66ec2aab closes https://github.com/official-stockfish/Stockfish/pull/2537 Bench: 4914050 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 985af7bc..9562bf86 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1115,7 +1115,7 @@ moves_loop: // When in check, search starts from here // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 - && moveCount > 1 + rootNode + (rootNode && bestValue < alpha) + && moveCount > 1 + 2 * rootNode && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion || moveCountPruning From 0f37da0e34e02efaaca907878d1a3e0d916f447c Mon Sep 17 00:00:00 2001 From: xoto10 Date: Fri, 31 Jan 2020 15:55:29 +0000 Subject: [PATCH 021/142] Simplify away king infiltration. STC : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 91438 W: 17496 L: 17438 D: 56504 Ptnml(0-2): 1573, 10711, 21067, 10790, 1563 https://tests.stockfishchess.org/tests/view/5e34812630ae32da08941d65 LTC : LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 40485 W: 5246 L: 5177 D: 30062 Ptnml(0-2): 289, 3818, 11976, 3812, 327 https://tests.stockfishchess.org/tests/view/5e354daee70d848499f6380c closes https://github.com/official-stockfish/Stockfish/pull/2542 Bench: 5047825 --- src/evaluate.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index bf1eee9b..17597648 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -701,9 +701,6 @@ namespace { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); - bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 - || rank_of(pos.square(BLACK)) < RANK_5; - bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); @@ -715,11 +712,10 @@ namespace { int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking - + 12 * infiltration + 21 * pawnsOnBothFlanks + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 100 ; + - 95 ; // Give more importance to non-material score Value mg = mg_value(score); From ddd4224640e04463c62b5896660f6f6abe4cc1a5 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 4 Feb 2020 20:41:58 +0300 Subject: [PATCH 022/142] Reintroduce king infiltration This patch reintroduces the recently simplified king infiltration bonus in initiative calculation, doubling its effect, and compensating more. passed STC http://tests.stockfishchess.org/tests/view/5e3476f630ae32da08941d5c LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 75323 W: 14434 L: 14140 D: 46749 Ptnml(0-2): 1231, 8729, 17528, 8826, 1331 passed LTC http://tests.stockfishchess.org/tests/view/5e377353e70d848499f638c1 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 171466 W: 22223 L: 21561 D: 127682 Ptnml(0-2): 1204, 15951, 50831, 16397, 1312 closes https://github.com/official-stockfish/Stockfish/pull/2545 Brench: 4869669 --- src/evaluate.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 17597648..df7ff5ea 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -708,14 +708,18 @@ namespace { && outflanking < 0 && !pawnsOnBothFlanks; + bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 + || rank_of(pos.square(BLACK)) < RANK_5; + // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking + 21 * pawnsOnBothFlanks + + 24 * infiltration + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 95 ; + -110 ; // Give more importance to non-material score Value mg = mg_value(score); From 0c878adb36c1013944231083d6a7b3b53aa1ad7e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 5 Feb 2020 15:18:24 +0100 Subject: [PATCH 023/142] Small cleanups. closes https://github.com/official-stockfish/Stockfish/pull/2532 Bench: 4869669 --- src/bitbase.cpp | 1 - src/endgame.h | 2 +- src/evaluate.cpp | 2 -- src/main.cpp | 2 +- src/misc.cpp | 14 +++++++------- src/misc.h | 2 +- src/movegen.cpp | 1 - src/position.cpp | 4 ++-- src/thread.cpp | 17 ++++++++--------- src/thread.h | 2 +- src/tt.cpp | 2 +- 11 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index ed6ed208..bef2dc49 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -19,7 +19,6 @@ */ #include -#include #include #include diff --git a/src/endgame.h b/src/endgame.h index 4642e448..f6135354 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -21,10 +21,10 @@ #ifndef ENDGAME_H_INCLUDED #define ENDGAME_H_INCLUDED -#include #include #include #include +#include #include #include "position.h" diff --git a/src/evaluate.cpp b/src/evaluate.cpp index df7ff5ea..ceba2588 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -520,7 +520,6 @@ namespace { } // Bonus for restricting their piece moves - // Greater bonus when landing square is occupied b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; @@ -721,7 +720,6 @@ namespace { - 43 * almostUnwinnable -110 ; - // Give more importance to non-material score Value mg = mg_value(score); Value eg = eg_value(score); diff --git a/src/main.cpp b/src/main.cpp index 148bf248..182cf105 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,12 +21,12 @@ #include #include "bitboard.h" +#include "endgame.h" #include "position.h" #include "search.h" #include "thread.h" #include "tt.h" #include "uci.h" -#include "endgame.h" #include "syzygy/tbprobe.h" namespace PSQT { diff --git a/src/misc.cpp b/src/misc.cpp index cf18d2e2..4d6483e7 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -299,23 +299,23 @@ void prefetch(void* addr) { /// With c++17 some of this functionality can be simplified. #if defined(__linux__) && !defined(__ANDROID__) -void* aligned_ttmem_alloc(size_t allocSize, void** mem) { +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment - *mem = aligned_alloc(alignment, size); - madvise(*mem, allocSize, MADV_HUGEPAGE); - return *mem; + mem = aligned_alloc(alignment, size); + madvise(mem, allocSize, MADV_HUGEPAGE); + return mem; } #else -void* aligned_ttmem_alloc(size_t allocSize, void** mem) { +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 64; // assumed cache line size size_t size = allocSize + alignment - 1; // allocate some extra space - *mem = malloc(size); - void* ret = reinterpret_cast((uintptr_t(*mem) + alignment - 1) & ~uintptr_t(alignment - 1)); + mem = malloc(size); + void* ret = reinterpret_cast((uintptr_t(mem) + alignment - 1) & ~uintptr_t(alignment - 1)); return ret; } diff --git a/src/misc.h b/src/misc.h index 45d9951a..a3780ba5 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,7 +33,7 @@ const std::string engine_info(bool to_uci = false); const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); -void* aligned_ttmem_alloc(size_t size, void** mem); +void* aligned_ttmem_alloc(size_t size, void*& mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/movegen.cpp b/src/movegen.cpp index 8f6edffb..7e8961ae 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -52,7 +52,6 @@ namespace { template ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { - // Compute some compile time parameters relative to the white side constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); diff --git a/src/position.cpp b/src/position.cpp index de9722ff..5efd9c42 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -633,11 +633,11 @@ bool Position::gives_check(Move m) const { Square to = to_sq(m); // Is there a direct check? - if (st->checkSquares[type_of(piece_on(from))] & to) + if (check_squares(type_of(piece_on(from))) & to) return true; // Is there a discovered check? - if ( (st->blockersForKing[~sideToMove] & from) + if ( (blockers_for_king(~sideToMove) & from) && !aligned(from, to, square(~sideToMove))) return true; diff --git a/src/thread.cpp b/src/thread.cpp index 615d482c..10ec96dd 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -54,7 +54,7 @@ Thread::~Thread() { /// Thread::bestMoveCount(Move move) return best move counter for the given root move -int Thread::best_move_count(Move move) { +int Thread::best_move_count(Move move) const { auto rm = std::find(rootMoves.begin() + pvIdx, rootMoves.begin() + pvLast, move); @@ -71,14 +71,13 @@ void Thread::clear() { captureHistory.fill(0); for (bool inCheck : { false, true }) - for (StatsType c : { NoCaptures, Captures }) - for (auto& to : continuationHistory[inCheck][c]) - for (auto& h : to) - h->fill(0); - - for (bool inCheck : { false, true }) - for (StatsType c : { NoCaptures, Captures }) - continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + for (StatsType c : { NoCaptures, Captures }) + { + for (auto& to : continuationHistory[inCheck][c]) + for (auto& h : to) + h->fill(0); + continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + } } /// Thread::start_searching() wakes up the thread that will start the search diff --git a/src/thread.h b/src/thread.h index aea86fd5..63629e33 100644 --- a/src/thread.h +++ b/src/thread.h @@ -56,7 +56,7 @@ public: void idle_loop(); void start_searching(); void wait_for_search_finished(); - int best_move_count(Move move); + int best_move_count(Move move) const; Pawns::Table pawnsTable; Material::Table materialTable; diff --git a/src/tt.cpp b/src/tt.cpp index 46860fe9..7e95a2a4 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -66,7 +66,7 @@ void TranspositionTable::resize(size_t mbSize) { free(mem); clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); - table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), &mem)); + table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize From 0aee1ec4ab3f7891c6a59d9d9e0113655300ce64 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 7 Feb 2020 10:42:10 +0100 Subject: [PATCH 024/142] Fix wrong assert. can trigger an abort when compiling with debug=yes, and using 7men TB. The assert should check that less than 8 pieces are in the key for each side, matching the assumption that underlies the FEN string construction. Also take explicitly care of a 'v' character in material strings. Fixes an issue reported in the forum: https://groups.google.com/d/msg/fishcooking/yoVC7etIpz0/7mS7ntZMBAAJ closes https://github.com/official-stockfish/Stockfish/pull/2547 No functional change. --- src/position.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 5efd9c42..0ac45057 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -375,11 +375,13 @@ void Position::set_state(StateInfo* si) const { Position& Position::set(const string& code, Color c, StateInfo* si) { - assert(code.length() > 0 && code.length() < 8); assert(code[0] == 'K'); string sides[] = { code.substr(code.find('K', 1)), // Weak - code.substr(0, code.find('K', 1)) }; // Strong + code.substr(0, std::min(code.find('v'), code.find('K', 1))) }; // Strong + + assert(sides[0].length() > 0 && sides[0].length() < 8); + assert(sides[1].length() > 0 && sides[1].length() < 8); std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); From 4e8986483a83296e37433da7b07b64de53613f6f Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 7 Feb 2020 20:04:43 +0300 Subject: [PATCH 025/142] Modify singular beta for ttPv positions. This patch lowers singular beta for positions that have been in pv and are not pv nodes. The idea of using ttpv && !PvNode improved scaling with TC and could be useful for other search heuristics. passed STC http://tests.stockfishchess.org/tests/view/5e3f6d7ce70d848499f63bbc LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 154953 W: 29688 L: 29272 D: 95993 Ptnml(0-2): 2616, 17912, 36037, 18210, 2673 passed LTC http://tests.stockfishchess.org/tests/view/5e405561e70d848499f63bfa LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 70974 W: 9305 L: 8932 D: 52737 Ptnml(0-2): 466, 6658, 20920, 6826, 569 closes https://github.com/official-stockfish/Stockfish/pull/2550 Bench: 4932981 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 9562bf86..c8a35a36 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1048,7 +1048,7 @@ moves_loop: // When in check, search starts from here && tte->depth() >= depth - 3 && pos.legal(move)) { - Value singularBeta = ttValue - 2 * depth; + Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; Depth halfDepth = depth / 2; ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); From be5a2f015e45886e32867b4559ef51dd694a3cec Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 11 Feb 2020 20:42:32 +0100 Subject: [PATCH 026/142] Fix for incorrect VALUE_MATE_IN_MAX_PLY usage. Fixes #2533, fixes #2543, fixes #2423. the code that prevents false mate announcements depending on the TT state (GHI), incorrectly used VALUE_MATE_IN_MAX_PLY. The latter constant, however, also includes, counterintuitively, the TB win range. This patch fixes that, by restoring the behavior for TB win scores, while retaining the false mate correctness, and improving the mate finding ability. In particular no alse mates are announced with the poisened hash testcase ``` position fen 8/8/8/3k4/8/8/6K1/7R w - - 0 1 go depth 40 position fen 8/8/8/3k4/8/8/6K1/7R w - - 76 1 go depth 20 ucinewgame ``` mates are found with the testcases reported in #2543 ``` position fen 4k3/3pp3/8/8/8/8/2PPP3/4K3 w - - 0 1 setoption name Hash value 1024 go depth 55 ucinewgame ``` and ``` position fen 4k3/4p3/8/8/8/8/3PP3/4K3 w - - 0 1 setoption name Hash value 1024 go depth 45 ucinewgame ``` furthermore, on the mate finding benchmark (ChestUCI_23102018.epd), performance improves over master, roughly reaching performance with the false mate protection reverted ``` Analyzing 6566 mate positions for best and found mates: ----------------best ---------------found nodes master revert fixed master revert fixed 16000000 4233 4236 4235 5200 5201 5199 32000000 4583 4585 4585 5417 5424 5418 64000000 4852 4853 4855 5575 5584 5579 128000000 5071 5068 5066 5710 5720 5716 256000000 5280 5282 5279 5819 5827 5826 512000000 5471 5468 5468 5919 5935 5932 ``` On a testcase with TB enabled, progress is made consistently, contrary to master ``` setoption name SyzygyPath value ../../../syzygy/3-4-5/ setoption name Hash value 2048 position fen 1R6/3k4/8/K2p4/4n3/2P5/8/8 w - - 0 1 go depth 58 ucinewgame ``` The PR (prior to a rewrite for clarity) passed STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 65405 W: 12454 L: 12384 D: 40567 Ptnml(0-2): 920, 7256, 16285, 7286, 944 http://tests.stockfishchess.org/tests/view/5e441a3be70d848499f63d15 passed LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 27096 W: 3477 L: 3413 D: 20206 Ptnml(0-2): 128, 2215, 8776, 2292, 122 http://tests.stockfishchess.org/tests/view/5e44e277e70d848499f63d63 The incorrectly named VALUE_MATE_IN_MAX_PLY and VALUE_MATED_IN_MAX_PLY were renamed into VALUE_TB_WIN_IN_MAX_PLY and VALUE_TB_LOSS_IN_MAX_PLY, and correclty defined VALUE_MATE_IN_MAX_PLY and VALUE_MATED_IN_MAX_PLY were introduced. One further (corner case) mistake using these constants was fixed (go mate X), which could lead to a premature return if X > MAX_PLY / 2, but TB were present. Thanks to @svivanov72 for one of the reports and help fixing the issue. closes https://github.com/official-stockfish/Stockfish/pull/2552 Bench: 4932981 --- src/endgame.cpp | 4 ++-- src/search.cpp | 58 +++++++++++++++++++++++++++++++++---------------- src/types.h | 6 +++-- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 2ed6ebc2..6745ee26 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -137,7 +137,7 @@ Value Endgame::operator()(const Position& pos) const { ||(pos.count(strongSide) && pos.count(strongSide)) || ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares) && (pos.pieces(strongSide, BISHOP) & DarkSquares))) - result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1); + result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1); return strongSide == pos.side_to_move() ? result : -result; } @@ -162,7 +162,7 @@ Value Endgame::operator()(const Position& pos) const { + PushClose[distance(winnerKSq, loserKSq)] + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; - assert(abs(result) < VALUE_MATE_IN_MAX_PLY); + assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; } diff --git a/src/search.cpp b/src/search.cpp index c8a35a36..f1416a74 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -290,13 +290,13 @@ void MainThread::search() { votes[th->rootMoves[0].pv[0]] += (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (bestThread->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY) + if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) { // Make sure we pick the shortest mate if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } - else if ( th->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY + else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY || votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) bestThread = th; } @@ -755,9 +755,10 @@ namespace { int drawScore = TB::UseRule50 ? 1 : 0; - value = wdl < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1 - : wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1 - : VALUE_DRAW + 2 * wdl * drawScore; + // use the range VALUE_MATE_IN_MAX_PLY to VALUE_TB_WIN_IN_MAX_PLY to score + value = wdl < -drawScore ? VALUE_MATED_IN_MAX_PLY + ss->ply + 1 + : wdl > drawScore ? VALUE_MATE_IN_MAX_PLY - ss->ply - 1 + : VALUE_DRAW + 2 * wdl * drawScore; Bound b = wdl < -drawScore ? BOUND_UPPER : wdl > drawScore ? BOUND_LOWER : BOUND_EXACT; @@ -863,7 +864,7 @@ namespace { if (nullValue >= beta) { // Do not return unproven mate scores - if (nullValue >= VALUE_MATE_IN_MAX_PLY) + if (nullValue >= VALUE_TB_WIN_IN_MAX_PLY) nullValue = beta; if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13)) @@ -890,7 +891,7 @@ namespace { // much above beta, we can (almost) safely prune the previous move. if ( !PvNode && depth >= 5 - && abs(beta) < VALUE_MATE_IN_MAX_PLY) + && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); @@ -996,7 +997,7 @@ moves_loop: // When in check, search starts from here // Step 13. Pruning at shallow depth (~200 Elo) if ( !rootNode && pos.non_pawn_material(us) - && bestValue > VALUE_MATED_IN_MAX_PLY) + && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold moveCountPruning = moveCount >= futility_move_count(improving, depth); @@ -1494,7 +1495,7 @@ moves_loop: // When in check, search starts from here // Detect non-capture evasions that are candidates to be pruned evasionPrunable = inCheck && (depth != 0 || moveCount > 2) - && bestValue > VALUE_MATED_IN_MAX_PLY + && bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !pos.capture(move); // Don't search moves with negative SEE values @@ -1560,28 +1561,47 @@ moves_loop: // When in check, search starts from here } - // value_to_tt() adjusts a mate score from "plies to mate from the root" to - // "plies to mate from the current position". Non-mate scores are unchanged. + // value_to_tt() adjusts a mate or TB score from "plies to mate from the root" to + // "plies to mate from the current position". standard scores are unchanged. // The function is called before storing a value in the transposition table. Value value_to_tt(Value v, int ply) { assert(v != VALUE_NONE); - return v >= VALUE_MATE_IN_MAX_PLY ? v + ply - : v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v; + return v >= VALUE_TB_WIN_IN_MAX_PLY ? v + ply + : v <= VALUE_TB_LOSS_IN_MAX_PLY ? v - ply : v; } - // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score + // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate or TB score // from the transposition table (which refers to the plies to mate/be mated - // from current position) to "plies to mate/be mated from the root". + // from current position) to "plies to mate/be mated (TB win/loss) from the root". + // However, for mate scores, to avoid potentially false mate scores related to the 50 moves rule, + // and the graph history interaction, return an optimal TB score instead. Value value_from_tt(Value v, int ply, int r50c) { - return v == VALUE_NONE ? VALUE_NONE - : v >= VALUE_MATE_IN_MAX_PLY ? VALUE_MATE - v > 99 - r50c ? VALUE_MATE_IN_MAX_PLY : v - ply - : v <= VALUE_MATED_IN_MAX_PLY ? VALUE_MATE + v > 99 - r50c ? VALUE_MATED_IN_MAX_PLY : v + ply : v; + if (v == VALUE_NONE) + return VALUE_NONE; + + if (v >= VALUE_TB_WIN_IN_MAX_PLY) // TB win or better + { + if (v >= VALUE_MATE_IN_MAX_PLY && VALUE_MATE - v > 99 - r50c) + return VALUE_MATE_IN_MAX_PLY - 1; // do not return a potentially false mate score + + return v - ply; + } + + if (v <= VALUE_TB_LOSS_IN_MAX_PLY) // TB loss or worse + { + if (v <= VALUE_MATED_IN_MAX_PLY && VALUE_MATE + v > 99 - r50c) + return VALUE_MATED_IN_MAX_PLY + 1; // do not return a potentially false mate score + + return v + ply; + } + + return v; } @@ -1767,7 +1787,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { Depth d = updated ? depth : depth - 1; Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; - bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; + bool tb = TB::RootInTB && abs(v) < VALUE_MATE_IN_MAX_PLY; v = tb ? rootMoves[i].tbScore : v; if (ss.rdbuf()->in_avail()) // Not at first line diff --git a/src/types.h b/src/types.h index 902c2cfc..7ab7560a 100644 --- a/src/types.h +++ b/src/types.h @@ -176,8 +176,10 @@ enum Value : int { VALUE_INFINITE = 32001, VALUE_NONE = 32002, - VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, - VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, + VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, + VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, KnightValueMg = 781, KnightValueEg = 854, From 10ead8a724671132df60ca2e23ddcad7eff7b3e5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 10 Feb 2020 15:18:16 -0700 Subject: [PATCH 027/142] Simplify Futility Move Count remove two constants STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 62050 W: 11903 L: 11802 D: 38345 Ptnml(0-2): 1002, 7346, 14283, 7320, 1065 http://tests.stockfishchess.org/tests/view/5e41d73be70d848499f63c6d LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 12850 W: 1679 L: 1572 D: 9599 Ptnml(0-2): 82, 1171, 3818, 1249, 96 http://tests.stockfishchess.org/tests/view/5e42bf07e70d848499f63cc0 Bench: 4762351 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f1416a74..c3ebf9ab 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -79,7 +79,7 @@ namespace { } constexpr int futility_move_count(bool improving, Depth depth) { - return (5 + depth * depth) * (1 + improving) / 2 - 1; + return (4 + depth * depth) / (2 - improving); } // History and stats update bonus, based on depth From ab930f8d3f4a657f493305559756e85534c88911 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 18 Feb 2020 09:10:58 -0700 Subject: [PATCH 028/142] Updated KNNKP endgame. This is a patch that significantly improves playing KNNKP endgames: ``` Score of 2553 vs master: 132 - 38 - 830 [0.547] 1000 Elo difference: 32.8 +/- 8.7, LOS: 100.0 %, DrawRatio: 83.0 % ``` At the same time it reduces the evaluation of this mostly draw engame from ~7.5 to ~1.5 This patch does not regress against master in normal games: STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 96616 W: 18459 L: 18424 D: 59733 Ptnml(0-2): 1409, 10812, 23802, 10905, 1380 http://tests.stockfishchess.org/tests/view/5e49dfe6f8d1d52b40cd31bc LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 49726 W: 6340 L: 6304 D: 37082 Ptnml(0-2): 239, 4227, 15906, 4241, 250 http://tests.stockfishchess.org/tests/view/5e4ab9ee16fb3df8c4cc01d0 Theory: KNNK is a dead draw, however the presence of the additional weakSide pawn opens up some mate opportunities. The idea is to block the pawn (preferably behind the Troitsky line) with one of the knights and press the weakSide king into a corner. If we can stalemate the king, we release the pawn with the knight (to avoid actual stalemate), and use the knight to complete the mate before the pawn promotes. This is also why there is an additional penalty for advancement of the pawn. closes https://github.com/official-stockfish/Stockfish/pull/2553 Bench: 4981770 --- src/endgame.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 6745ee26..74e16fa6 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -310,16 +310,17 @@ Value Endgame::operator()(const Position& pos) const { } -/// KNN vs KP. Simply push the opposing king to the corner +/// KNN vs KP. Very drawish, but there are some mate opportunities if we can +// press the weakSide King to a corner before the pawn advances too much. template<> Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Value result = 2 * KnightValueEg - - PawnValueEg - + PushToEdges[pos.square(weakSide)]; + Value result = PawnValueEg + + 2 * PushToEdges[pos.square(weakSide)] + - 10 * relative_rank(weakSide, pos.square(weakSide)); return strongSide == pos.side_to_move() ? result : -result; } From b8c00efa2767ebf74545d2ba4bd344ef7c963319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Demetz?= Date: Fri, 21 Feb 2020 14:01:59 +0100 Subject: [PATCH 029/142] Improve move order near the root Current move histories are known to work well near the leaves, whilst at higher depths they aren't very helpful. To address this problem this patch introduces a table dedicated for what's happening at plies 0-3. It's structured like mainHistory with ply index instead of color. It get cleared with each new search and is filled during iterative deepening at higher depths when recording successful quiet moves near the root or traversing nodes which were in the principal variation (ttPv). Medium TC (20+0.2): https://tests.stockfishchess.org/tests/view/5e4d358790a0a02810d096dc LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 100910 W: 16682 L: 16376 D: 67852 Ptnml(0-2): 1177, 10983, 25883, 11181, 1231 LTC: https://tests.stockfishchess.org/tests/view/5e4e2cb790a0a02810d09714 LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 80444 W: 10495 L: 10095 D: 59854 Ptnml(0-2): 551, 7479, 23803, 7797, 592 closes https://github.com/official-stockfish/Stockfish/pull/2557 Bench: 4705960 --- src/movepick.cpp | 11 ++++++----- src/movepick.h | 12 +++++++++++- src/search.cpp | 19 ++++++++++++++----- src/thread.cpp | 2 ++ src/thread.h | 1 + 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 025f5b82..575c9022 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -56,10 +56,10 @@ namespace { /// 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, Move* killers) - : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) { +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, + const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) + : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), + refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) , ply(pl) { assert(d > 0); @@ -115,7 +115,8 @@ void MovePicker::score() { + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; + + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + + (ply < MAX_LPH ? 4 * (*lowPlyHistory)[ply][from_to(m)] : 0); else // Type == EVASIONS { diff --git a/src/movepick.h b/src/movepick.h index cdedc9b6..33c4b086 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -88,6 +88,12 @@ enum StatsType { NoCaptures, Captures }; /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards typedef Stats ButterflyHistory; +/// LowPlyHistory at higher depths records successful quiet moves on plies 0 to 3 +/// and quiet moves which are/were in the PV (ttPv) +/// It get cleared with each new search and get filled during iterative deepening +constexpr int MAX_LPH = 4; +typedef Stats LowPlyHistory; + /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// move, see www.chessprogramming.org/Countermove_Heuristic typedef Stats CounterMoveHistory; @@ -123,10 +129,12 @@ public: const PieceToHistory**, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, + const LowPlyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, - Move*); + Move*, + int); Move next_move(bool skipQuiets = false); private: @@ -137,6 +145,7 @@ private: const Position& pos; const ButterflyHistory* mainHistory; + const LowPlyHistory* lowPlyHistory; const CapturePieceToHistory* captureHistory; const PieceToHistory** continuationHistory; Move ttMove; @@ -145,6 +154,7 @@ private: Square recaptureSquare; Value threshold; Depth depth; + int ply; ExtMove moves[MAX_MOVES]; }; diff --git a/src/search.cpp b/src/search.cpp index c3ebf9ab..3f860ac5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -156,7 +156,7 @@ namespace { Value value_from_tt(Value v, int ply, int r50c); void update_pv(Move* pv, Move move, Move* childPv); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); @@ -695,6 +695,10 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + + if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove)) + thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); + // thisThread->ttHitAverage can be used to approximate the running average of ttHit thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow + ttHitAverageResolution * ttHit; @@ -713,7 +717,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth), depth); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -948,10 +952,12 @@ moves_loop: // When in check, search starts from here Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, + &thisThread->lowPlyHistory, &thisThread->captureHistory, contHist, countermove, - ss->killers); + ss->killers, + depth > 12 && ttPv ? ss->ply : MAX_PLY); value = bestValue; singularLMR = moveCountPruning = false; @@ -1633,7 +1639,7 @@ moves_loop: // When in check, search starts from here if (!pos.capture_or_promotion(bestMove)) { - update_quiet_stats(pos, ss, bestMove, bonus2); + update_quiet_stats(pos, ss, bestMove, bonus2, depth); // Decrease all the non-best quiet moves for (int i = 0; i < quietCount; ++i) @@ -1673,7 +1679,7 @@ moves_loop: // When in check, search starts from here // update_quiet_stats() updates move sorting heuristics - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) { + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth) { if (ss->killers[0] != move) { @@ -1694,6 +1700,9 @@ moves_loop: // When in check, search starts from here Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } + + if (depth > 12 && ss->ply < MAX_LPH) + thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7); } // When playing with strength handicap, choose best move among a set of RootMoves diff --git a/src/thread.cpp b/src/thread.cpp index 10ec96dd..b5cb87d9 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -68,6 +68,7 @@ void Thread::clear() { counterMoves.fill(MOVE_NONE); mainHistory.fill(0); + lowPlyHistory.fill(0); captureHistory.fill(0); for (bool inCheck : { false, true }) @@ -211,6 +212,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); + th->lowPlyHistory.fill(0); } setupStates->back() = tmp; diff --git a/src/thread.h b/src/thread.h index 63629e33..41d2b8f6 100644 --- a/src/thread.h +++ b/src/thread.h @@ -71,6 +71,7 @@ public: Depth rootDepth, completedDepth; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; + LowPlyHistory lowPlyHistory; CapturePieceToHistory captureHistory; ContinuationHistory continuationHistory[2][2]; Score contempt; From 8352977b91d9246618c7273d59400a4a05a32e2a Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sat, 22 Feb 2020 21:27:32 -0500 Subject: [PATCH 030/142] Use single param for Outpost and ReachableOutpost. In November 2019, as a result of the simplification of rank-based outposts by 37698b0, separate bonuses were introduced for outposts that are currently occupied and outposts that are reachable on the next move. However, the values of these two bonuses are quite similar, and they have remained that way for three months of development. It appears that we can safely retire the separate ReachableOutpost parameter and use the same Outpost bonus in both cases, restoring the basic principles of Stockfish outpost evaluation to their pre-November state, while also reducing the size of the parameter space. STC: LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 47680 W: 9213 L: 9092 D: 29375 Ptnml(0-2): 776, 5573, 11071, 5594, 826 https://tests.stockfishchess.org/tests/view/5e51e33190a0a02810d09802 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 14690 W: 1960 L: 1854 D: 10876 Ptnml(0-2): 93, 1381, 4317, 1435, 119 https://tests.stockfishchess.org/tests/view/5e52197990a0a02810d0980f closes https://github.com/official-stockfish/Stockfish/pull/2559 Bench: 4697493 --- src/evaluate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ceba2588..25aba644 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -139,7 +139,6 @@ namespace { constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score ReachableOutpost = S( 32, 10); constexpr Score RookOnQueenFile = S( 7, 6); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); @@ -296,7 +295,7 @@ namespace { score += Outpost * (Pt == KNIGHT ? 2 : 1); else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) - score += ReachableOutpost; + score += Outpost; // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) From 2e1369d0302a87d570e509af7041a1be22b836a0 Mon Sep 17 00:00:00 2001 From: AndyGrant Date: Mon, 24 Feb 2020 23:32:17 +0100 Subject: [PATCH 031/142] Fix TT write in MultiPV case. fixes an error reported earlier as https://github.com/official-stockfish/Stockfish/issues/2404 by @AndyGrant. MultiPV at root shouldn't write to the TT for later lines, as that is neither the eval nor the bestmove for that position. Fixing this error doesn't matter for playing games (http://tests.stockfishchess.org/tests/view/5dcdbd810ebc590256324a11). However, it can lead to wrong mate announcements as reported by @uriblass. In particular the following testcase gives wrong results for the second search, prior to this patch: ``` setoption name MultiPV value 2 position fen 5R2/2kB2p1/p2bR3/8/3p1B2/8/PPP5/2K5 b - - 0 49 go depth 40 position fen 2B2R2/3r2p1/p1kbR3/8/3p1B2/8/PPP5/2K5 b - - 8 48 go depth 40 ``` fixes https://github.com/official-stockfish/Stockfish/issues/2561 closes https://github.com/official-stockfish/Stockfish/pull/2562 Only affects MultiPV search. Bench: 4697493 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3f860ac5..a32ff4b6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1339,7 +1339,7 @@ moves_loop: // When in check, search starts from here if (PvNode) bestValue = std::min(bestValue, maxValue); - if (!excludedMove) + if (!excludedMove && !(rootNode && thisThread->pvIdx)) tte->save(posKey, value_to_tt(bestValue, ss->ply), ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, From 09f53dbfa5b55e761ca8070960345ab140baad04 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sat, 22 Feb 2020 14:57:01 +0100 Subject: [PATCH 032/142] Weak queen protection Extra penalty if weak piece is only protected by a queen. STC: http://tests.stockfishchess.org/tests/view/5e53c6ab84a82b4acd4148fa LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 44630 W: 8615 L: 8359 D: 27656 Ptnml(0-2): 746, 5156, 10323, 5276, 814 LTC: http://tests.stockfishchess.org/tests/view/5e54e05d84a82b4acd414947 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 175480 W: 23085 L: 22409 D: 129986 Ptnml(0-2): 1264, 16494, 51678, 16910, 1394 closes https://github.com/official-stockfish/Stockfish/pull/2564 Bench: 4923286 --- src/evaluate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 25aba644..06366e09 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -114,11 +114,11 @@ namespace { // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) + S(0, 0), S(5, 32), S(57, 41), S(77, 56), S(88, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(2, 44), S(36, 71), S(36, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -516,6 +516,9 @@ namespace { b = ~attackedBy[Them][ALL_PIECES] | (nonPawnEnemies & attackedBy2[Us]); score += Hanging * popcount(weak & b); + + // Additional bonus if weak piece is only protected by a queen + score += make_score(14, 0) * popcount(weak & attackedBy[Them][QUEEN]); } // Bonus for restricting their piece moves From f27339d35b6c8ccd1f83914b334c89111e62f320 Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Thu, 27 Feb 2020 15:58:22 +0100 Subject: [PATCH 033/142] Simplify lowply-history logic Don't restrict usage to ttPv nodes exclusively STC: http://tests.stockfishchess.org/tests/view/5e5634f284a82b4acd41499a LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 152796 W: 29146 L: 29178 D: 94472 Ptnml(0-2): 2590, 17792, 35628, 17836, 2552 LTC: http://tests.stockfishchess.org/tests/view/5e575d4984a82b4acd4149e8 LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 20078 W: 2688 L: 2587 D: 14803 Ptnml(0-2): 139, 1914, 5853, 1973, 160 closes https://github.com/official-stockfish/Stockfish/pull/2565 bench: 4923286 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index a32ff4b6..544c3ee5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -957,7 +957,7 @@ moves_loop: // When in check, search starts from here contHist, countermove, ss->killers, - depth > 12 && ttPv ? ss->ply : MAX_PLY); + depth > 12 ? ss->ply : MAX_PLY); value = bestValue; singularLMR = moveCountPruning = false; From c6839a26155c18dbb7700175971fe01c5a67b01c Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 1 Mar 2020 09:31:17 +0100 Subject: [PATCH 034/142] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2546 No functional change. --- src/Makefile | 2 +- src/bitboard.h | 2 +- src/endgame.cpp | 2 +- src/evaluate.cpp | 44 ++++++++++++++++++++++---------------------- src/evaluate.h | 2 -- src/psqt.cpp | 8 -------- src/search.cpp | 10 +++++----- src/types.h | 8 +++++++- 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/Makefile b/src/Makefile index 679eb8d9..15ad6353 100644 --- a/src/Makefile +++ b/src/Makefile @@ -409,7 +409,7 @@ help: @echo "" -.PHONY: help build profile-build strip install clean objclean profileclean help \ +.PHONY: help build profile-build strip install clean objclean profileclean \ config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \ clang-profile-use clang-profile-make diff --git a/src/bitboard.h b/src/bitboard.h index d11b7e73..ca161481 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -154,7 +154,7 @@ inline Bitboard file_bb(Square s) { } -/// shift() moves a bitboard one step along direction D +/// shift() moves a bitboard one or two steps as specified by the direction D template constexpr Bitboard shift(Bitboard b) { diff --git a/src/endgame.cpp b/src/endgame.cpp index 74e16fa6..5fdd307e 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -281,7 +281,7 @@ Value Endgame::operator()(const Position& pos) const { if ( relative_rank(weakSide, pawnSq) != RANK_7 || distance(loserKSq, pawnSq) != 1 - || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq)) + || ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq)) result += QueenValueEg - PawnValueEg; return strongSide == pos.side_to_move() ? result : -result; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 06366e09..31272f2c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -127,25 +127,26 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); - constexpr Score CorneredBishop = S( 50, 50); - constexpr Score FlankAttacks = S( 8, 0); - constexpr Score Hanging = S( 69, 36); - constexpr Score KingProtector = S( 7, 8); - constexpr Score KnightOnQueen = S( 16, 12); - constexpr Score LongDiagonalBishop = S( 45, 0); - constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 30, 21); - constexpr Score PassedFile = S( 11, 8); - constexpr Score PawnlessFlank = S( 17, 95); - constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnQueenFile = S( 7, 6); - constexpr Score SliderOnQueen = S( 59, 18); - constexpr Score ThreatByKing = S( 24, 89); - constexpr Score ThreatByPawnPush = S( 48, 39); - constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); - constexpr Score WeakQueen = S( 49, 15); + constexpr Score BishopPawns = S( 3, 7); + constexpr Score CorneredBishop = S( 50, 50); + constexpr Score FlankAttacks = S( 8, 0); + constexpr Score Hanging = S( 69, 36); + constexpr Score KingProtector = S( 7, 8); + constexpr Score KnightOnQueen = S( 16, 12); + constexpr Score LongDiagonalBishop = S( 45, 0); + constexpr Score MinorBehindPawn = S( 18, 3); + constexpr Score Outpost = S( 30, 21); + constexpr Score PassedFile = S( 11, 8); + constexpr Score PawnlessFlank = S( 17, 95); + constexpr Score RestrictedPiece = S( 7, 7); + constexpr Score RookOnQueenFile = S( 7, 6); + constexpr Score SliderOnQueen = S( 59, 18); + constexpr Score ThreatByKing = S( 24, 89); + constexpr Score ThreatByPawnPush = S( 48, 39); + constexpr Score ThreatBySafePawn = S(173, 94); + constexpr Score TrappedRook = S( 52, 10); + constexpr Score WeakQueen = S( 49, 15); + constexpr Score WeakQueenProtection = S( 14, 0); #undef S @@ -518,7 +519,7 @@ namespace { score += Hanging * popcount(weak & b); // Additional bonus if weak piece is only protected by a queen - score += make_score(14, 0) * popcount(weak & attackedBy[Them][QUEEN]); + score += WeakQueenProtection * popcount(weak & attackedBy[Them][QUEEN]); } // Bonus for restricting their piece moves @@ -830,8 +831,7 @@ namespace { Trace::add(TOTAL, score); } - return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view - + Eval::Tempo; + return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view } } // namespace diff --git a/src/evaluate.h b/src/evaluate.h index 077de70c..7c8a2a6f 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,8 +29,6 @@ class Position; namespace Eval { -constexpr Value Tempo = Value(28); // Must be visible to search - std::string trace(const Position& pos); Value evaluate(const Position& pos); diff --git a/src/psqt.cpp b/src/psqt.cpp index 647bd864..8bad7ed4 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -22,11 +22,6 @@ #include "types.h" -Value PieceValue[PHASE_NB][PIECE_NB] = { - { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg }, - { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } -}; - namespace PSQT { #define S(mg, eg) make_score(mg, eg) @@ -112,9 +107,6 @@ void init() { for (Piece pc = W_PAWN; pc <= W_KING; ++pc) { - PieceValue[MG][~pc] = PieceValue[MG][pc]; - PieceValue[EG][~pc] = PieceValue[EG][pc]; - Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); for (Square s = SQ_A1; s <= SQ_H8; ++s) diff --git a/src/search.cpp b/src/search.cpp index 544c3ee5..7f6abf15 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -819,14 +819,14 @@ namespace { ss->staticEval = eval = evaluate(pos) + bonus; } else - ss->staticEval = eval = -(ss-1)->staticEval + 2 * Eval::Tempo; + ss->staticEval = eval = -(ss-1)->staticEval + 2 * Tempo; tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } // Step 7. Razoring (~1 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch - && depth < 2 + && depth == 1 && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); @@ -1434,13 +1434,13 @@ moves_loop: // When in check, search starts from here else ss->staticEval = bestValue = (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) - : -(ss-1)->staticEval + 2 * Eval::Tempo; + : -(ss-1)->staticEval + 2 * Tempo; // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { if (!ttHit) - tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, BOUND_LOWER, + tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->staticEval); return bestValue; @@ -1667,7 +1667,7 @@ moves_loop: // When in check, search starts from here // update_continuation_histories() updates histories of the move pairs formed - // by moves at ply -1, -2, and -4 with current move. + // by moves at ply -1, -2, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { diff --git a/src/types.h b/src/types.h index 7ab7560a..58d05d2c 100644 --- a/src/types.h +++ b/src/types.h @@ -186,6 +186,7 @@ enum Value : int { BishopValueMg = 825, BishopValueEg = 915, RookValueMg = 1276, RookValueEg = 1380, QueenValueMg = 2538, QueenValueEg = 2682, + Tempo = 28, MidgameLimit = 15258, EndgameLimit = 3915 }; @@ -203,7 +204,12 @@ enum Piece { PIECE_NB = 16 }; -extern Value PieceValue[PHASE_NB][PIECE_NB]; +constexpr Value PieceValue[PHASE_NB][PIECE_NB] = { + { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO, + VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO }, + { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO, + VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO } +}; typedef int Depth; From 960d59d54143d84aab26deae65279a611fc989f4 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 1 Mar 2020 02:03:36 -0700 Subject: [PATCH 035/142] Consolidate Square Flipping Add a flip_rank() and flip_file() so that all of the square flipping can be consolidated. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 57234 W: 11064 L: 10969 D: 35201 Ptnml(0-2): 822, 6562, 13801, 6563, 869 http://tests.stockfishchess.org/tests/view/5e5d2f2aafe6254521f2ffaa closes https://github.com/official-stockfish/Stockfish/pull/2568 No functional change. --- src/endgame.cpp | 4 ++-- src/psqt.cpp | 2 +- src/syzygy/tbprobe.cpp | 7 +++---- src/types.h | 8 ++++++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 5fdd307e..16c072be 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -74,9 +74,9 @@ namespace { assert(pos.count(strongSide) == 1); if (file_of(pos.square(strongSide)) >= FILE_E) - sq = Square(int(sq) ^ 7); // Mirror SQ_H1 -> SQ_A1 + sq = flip_file(sq); - return strongSide == WHITE ? sq : ~sq; + return strongSide == WHITE ? sq : flip_rank(sq); } } // namespace diff --git a/src/psqt.cpp b/src/psqt.cpp index 8bad7ed4..f6f5933c 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -114,7 +114,7 @@ void init() { File f = map_to_queenside(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); - psq[~pc][~s] = -psq[pc][s]; + psq[~pc][flip_rank(s)] = -psq[pc][s]; } } } diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 721a0ef5..6f369455 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -66,7 +66,6 @@ enum TBType { KEY, WDL, DTZ }; // Used as template parameter enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 }; inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); } -inline Square operator^=(Square& s, int i) { return s = Square(int(s) ^ i); } inline Square operator^(Square s, int i) { return Square(int(s) ^ i); } const std::string PieceToChar = " PNBRQK pnbrqk"; @@ -743,7 +742,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // the triangle A1-D1-D4. if (file_of(squares[0]) > FILE_D) for (int i = 0; i < size; ++i) - squares[i] ^= 7; // Horizontal flip: SQ_H1 -> SQ_A1 + squares[i] = flip_file(squares[i]); // Encode leading pawns starting with the one with minimum MapPawns[] and // proceeding in ascending order. @@ -762,7 +761,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // piece is below RANK_5. if (rank_of(squares[0]) > RANK_4) for (int i = 0; i < size; ++i) - squares[i] ^= SQ_A8; // Vertical flip: SQ_A8 -> SQ_A1 + squares[i] = flip_rank(squares[i]); // Look for the first piece of the leading group not on the A1-D4 diagonal // and ensure it is mapped below the diagonal. @@ -1344,7 +1343,7 @@ void Tablebases::init(const std::string& paths) { if (leadPawnsCnt == 1) { MapPawns[sq] = availableSquares--; - MapPawns[sq ^ 7] = availableSquares--; // Horizontal flip + MapPawns[flip_file(sq)] = availableSquares--; } LeadPawnIdx[leadPawnsCnt][sq] = idx; idx += Binomial[leadPawnsCnt - 1][MapPawns[sq]]; diff --git a/src/types.h b/src/types.h index 58d05d2c..d4937fd6 100644 --- a/src/types.h +++ b/src/types.h @@ -358,8 +358,12 @@ constexpr Color operator~(Color c) { return Color(c ^ BLACK); // Toggle color } -constexpr Square operator~(Square s) { - return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 +constexpr Square flip_rank(Square s) { + return Square(s ^ SQ_A8); +} + +constexpr Square flip_file(Square s) { + return Square(s ^ SQ_H1); } constexpr Piece operator~(Piece pc) { From 5a7b45eac9dedbf7ebc61d9deb4dd934058d1ca1 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 2 Mar 2020 17:32:02 -0700 Subject: [PATCH 036/142] Use equations for PushAway and PushClose A functional simplification replacing the corresponding arrays. Tested in two variants, also the simpler one performs well, even though differences to master should be minimal. STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 57864 W: 11092 L: 11001 D: 35771 Ptnml(0-2): 826, 6458, 14320, 6455, 873 http://tests.stockfishchess.org/tests/view/5e5da5b6e42a5c3b3ca2e05c LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 7198 W: 982 L: 883 D: 5333 Ptnml(0-2): 33, 575, 2296, 650, 45 http://tests.stockfishchess.org/tests/view/5e5df13ae42a5c3b3ca2e077 LTC (This exact version. . . more simplified) LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 5392 W: 729 L: 631 D: 4032 Ptnml(0-2): 23, 405, 1751, 485, 32 http://tests.stockfishchess.org/tests/view/5e5ead99e42a5c3b3ca2e0e4 closes https://github.com/official-stockfish/Stockfish/pull/2570 Bench 5123316 --- src/endgame.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 16c072be..73a44633 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -54,9 +54,9 @@ namespace { 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 }; - // Tables used to drive a piece towards or away from another piece - constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; - constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; + // Drive a piece close to or away from another piece + inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } + inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); } // Pawn Rank based scaling factors used in KRPPKRP endgame constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; @@ -130,7 +130,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg + PushToEdges[loserKSq] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) || pos.count(strongSide) @@ -159,7 +159,7 @@ Value Endgame::operator()(const Position& pos) const { // to drive to opposite corners (A8/H1). Value result = VALUE_KNOWN_WIN - + PushClose[distance(winnerKSq, loserKSq)] + + push_close(winnerKSq, loserKSq) + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); @@ -258,7 +258,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]); + Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -277,7 +277,7 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.square(weakSide); Square pawnSq = pos.square(weakSide); - Value result = Value(PushClose[distance(winnerKSq, loserKSq)]); + Value result = Value(push_close(winnerKSq, loserKSq)); if ( relative_rank(weakSide, pawnSq) != RANK_7 || distance(loserKSq, pawnSq) != 1 @@ -304,7 +304,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg + PushToEdges[loserKSq] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; } From 0424273d0b20ae7ad65143b530b2db8b94de0338 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 3 Mar 2020 16:35:45 -0700 Subject: [PATCH 037/142] Small speed-up in BetweenBB A speed-up removing some comparisons. closes https://github.com/official-stockfish/Stockfish/pull/2571 No functional change. --- src/bitboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index ca161481..b0e27233 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -199,8 +199,8 @@ inline Bitboard adjacent_files_bb(Square s) { /// If the given squares are not on a same file/rank/diagonal, return 0. inline Bitboard between_bb(Square s1, Square s2) { - return LineBB[s1][s2] & ( (AllSquares << (s1 + (s1 < s2))) - ^(AllSquares << (s2 + !(s1 < s2)))); + Bitboard b = LineBB[s1][s2] & ((AllSquares << s1) ^ (AllSquares << s2)); + return b & (b - 1); //exclude lsb } From e7c1c8c1abd85a71fd8190e0c1af49214625904b Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 5 Mar 2020 12:07:48 -0700 Subject: [PATCH 038/142] Cleanup KBPsK endgame * Clarify distinction between strong side pawns and all pawns. * Simplify and speed-up determination of pawns on the same file. * Clarify comments. * more_than_one() is probably faster than pos.count. Passed STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 40696 W: 7856 L: 7740 D: 25100 Ptnml(0-2): 584, 4519, 10054, 4579, 612 http://tests.stockfishchess.org/tests/view/5e6153b1e42a5c3b3ca2e1a9 closes https://github.com/official-stockfish/Stockfish/pull/2574 No functional change. --- src/endgame.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 73a44633..748b05ff 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -343,29 +343,27 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // No assertions about the material of weakSide, because we want draws to // be detected even when the weaker side has some pawns. - Bitboard pawns = pos.pieces(strongSide, PAWN); - File pawnsFile = file_of(lsb(pawns)); + Bitboard strongpawns = pos.pieces(strongSide, PAWN); + Bitboard allpawns = pos.pieces(PAWN); - // All pawns are on a single rook file? - if ( (pawnsFile == FILE_A || pawnsFile == FILE_H) - && !(pawns & ~file_bb(pawnsFile))) + // All strongSide pawns are on a single rook file? + if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB)) { Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(pawnsFile, RANK_8)); - Square kingSq = pos.square(weakSide); + Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8)); + Square weakkingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, kingSq) <= 1) + && distance(queeningSq, weakkingSq) <= 1) return SCALE_FACTOR_DRAW; } // If all the pawns are on the same B or G file, then it's potentially a draw - if ( (pawnsFile == FILE_B || pawnsFile == FILE_G) - && !(pos.pieces(PAWN) & ~file_bb(pawnsFile)) + if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { - // Get weakSide pawn that is closest to the home rank + // Get the least advanced weakSide pawn Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); Square strongKingSq = pos.square(strongSide); @@ -375,8 +373,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left if ( relative_rank(strongSide, weakPawnSq) == RANK_7 - && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || pos.count(strongSide) == 1)) + && (strongpawns & (weakPawnSq + pawn_push(weakSide))) + && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns))) { int strongKingDist = distance(weakPawnSq, strongKingSq); int weakKingDist = distance(weakPawnSq, weakKingSq); From 9690cd6295fbed93ee434e7b2e16181e475755ac Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 4 Mar 2020 11:32:17 -0700 Subject: [PATCH 039/142] Remove KRPPKRPScaleFactors array Fucntional simplification that removes the KRPPKRPScaleFactors array. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 47374 W: 9159 L: 9049 D: 29166 Ptnml(0-2): 707, 5325, 11560, 5341, 754 http://tests.stockfishchess.org/tests/view/5e5ff464e42a5c3b3ca2e156 LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 31268 W: 4064 L: 3995 D: 23209 Ptnml(0-2): 173, 2734, 9764, 2777, 186 http://tests.stockfishchess.org/tests/view/5e61be6ce42a5c3b3ca2e1c1 closes https://github.com/official-stockfish/Stockfish/pull/2575 Bench 5123316 --- src/endgame.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 748b05ff..53c9ec83 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -58,9 +58,6 @@ namespace { inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); } - // Pawn Rank based scaling factors used in KRPPKRP endgame - constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; - #ifndef NDEBUG bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) { return pos.non_pawn_material(c) == npm && pos.count(c) == pawnsCnt; @@ -587,7 +584,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && relative_rank(strongSide, bksq) > r) { assert(r > RANK_1 && r < RANK_7); - return ScaleFactor(KRPPKRPScaleFactors[r]); + return ScaleFactor(7 * r); } return SCALE_FACTOR_NONE; } From 37e38639279bf58558b92932739da57e7c2e3bdc Mon Sep 17 00:00:00 2001 From: Gary Heckman Date: Thu, 5 Mar 2020 12:37:08 -0500 Subject: [PATCH 040/142] Fix ambiguity between clamp implementations There is an ambiguity between global and std clamp implementations when compiling in c++17, and on certain toolchains that are not strictly conforming to c++11. This is solved by putting our clamp implementation in a namespace. closes https://github.com/official-stockfish/Stockfish/pull/2572 No functional change. --- AUTHORS | 1 + src/bitboard.h | 3 --- src/evaluate.cpp | 4 ++-- src/material.cpp | 2 +- src/misc.h | 8 ++++++++ src/pawns.cpp | 2 +- src/search.cpp | 6 +++--- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index a9f141f9..7657acee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,7 @@ fanon Fauzi Akram Dabat (FauziAkram) Felix Wittmann gamander +Gary Heckman (gheckman) gguliash Gian-Carlo Pascutto (gcp) Gontran Lemaire (gonlem) diff --git a/src/bitboard.h b/src/bitboard.h index b0e27233..3ea18dd8 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -255,9 +255,6 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } -template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { - return v < lo ? lo : v > hi ? hi : v; -} /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 31272f2c..5d073b15 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -236,8 +236,8 @@ namespace { attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); // Init our king safety tables - Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G), - clamp(rank_of(ksq), RANK_2, RANK_7)); + Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G), + Utility::clamp(rank_of(ksq), RANK_2, RANK_7)); kingRing[Us] = PseudoAttacks[KING][s] | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); diff --git a/src/material.cpp b/src/material.cpp index 0e130878..7e212461 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -129,7 +129,7 @@ Entry* probe(const Position& pos) { Value npm_w = pos.non_pawn_material(WHITE); Value npm_b = pos.non_pawn_material(BLACK); - Value npm = clamp(npm_w + npm_b, EndgameLimit, MidgameLimit); + Value npm = Utility::clamp(npm_w + npm_b, EndgameLimit, MidgameLimit); // Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME] e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit)); diff --git a/src/misc.h b/src/misc.h index a3780ba5..e0e0e98b 100644 --- a/src/misc.h +++ b/src/misc.h @@ -64,6 +64,14 @@ std::ostream& operator<<(std::ostream&, SyncCout); #define sync_cout std::cout << IO_LOCK #define sync_endl std::endl << IO_UNLOCK +namespace Utility { + +/// Clamp a value between lo and hi. Available in c++17. +template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { + return v < lo ? lo : v > hi ? hi : v; +} + +} /// xorshift64star Pseudo-Random Number Generator /// This class is based on original code written and dedicated diff --git a/src/pawns.cpp b/src/pawns.cpp index c3f7872f..9981ac01 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -193,7 +193,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { Score bonus = make_score(5, 5); - File center = clamp(file_of(ksq), FILE_B, FILE_G); + File center = Utility::clamp(file_of(ksq), FILE_B, FILE_G); for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); diff --git a/src/search.cpp b/src/search.cpp index 7f6abf15..3d130efc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -365,7 +365,7 @@ void Thread::search() { // for match (TC 60+0.6) results spanning a wide range of k values. PRNG rng(now()); double floatLevel = Options["UCI_LimitStrength"] ? - clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : + Utility::clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : double(Options["Skill Level"]); int intLevel = int(floatLevel) + ((floatLevel - int(floatLevel)) * 1024 > rng.rand() % 1024 ? 1 : 0); @@ -538,7 +538,7 @@ void Thread::search() { { double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue) + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; - fallingEval = clamp(fallingEval, 0.5, 1.5); + fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.94 : 0.91; @@ -1197,7 +1197,7 @@ moves_loop: // When in check, search starts from here else if (depth < 8 && moveCount > 2) r++; - Depth d = clamp(newDepth - r, 1, newDepth); + Depth d = Utility::clamp(newDepth - r, 1, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); From 47be966d3028ca9b5c4d095f266663eb205c0c07 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 9 Mar 2020 22:11:08 +0100 Subject: [PATCH 041/142] Equations for edges and corners. This is a functional simplification that removes the large arrays in endgames.cpp. It also fixes a recently introduced bug (960d59d54143d84aab26deae65279a611fc989f4) in KNBvK, now using flip_file() instead of ~. One fen added to bench to increase endgame coverage. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 174724 W: 33325 L: 33404 D: 107995 Ptnml(0-2): 2503, 19607, 43181, 19608, 2463 http://tests.stockfishchess.org/tests/view/5e6448ffe42a5c3b3ca2e287 LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 35640 W: 4679 L: 4621 D: 26340 Ptnml(0-2): 189, 2991, 11424, 3005, 211 http://tests.stockfishchess.org/tests/view/5e650b24e42a5c3b3ca2e2d8 closes https://github.com/official-stockfish/Stockfish/pull/2577 Bench: 5527957 --- src/benchmark.cpp | 1 + src/bitboard.h | 2 ++ src/endgame.cpp | 46 +++++++++++++++--------------------------- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- src/psqt.cpp | 3 ++- src/syzygy/tbprobe.cpp | 2 +- src/types.h | 4 ---- 8 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index f906e731..f338cdda 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -65,6 +65,7 @@ const vector Defaults = { "4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21", "r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16", "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40", + "4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1", // 5-man positions "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate diff --git a/src/bitboard.h b/src/bitboard.h index 3ea18dd8..f1d14603 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -255,6 +255,8 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } +inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); } +inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/endgame.cpp b/src/endgame.cpp index 53c9ec83..0a2b02ad 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -28,31 +28,17 @@ using std::string; namespace { - // Table used to drive the king towards the edge of the board + // Used to drive the king towards the edge of the board // in KX vs K and KQ vs KR endgames. - constexpr int PushToEdges[SQUARE_NB] = { - 100, 90, 80, 70, 70, 80, 90, 100, - 90, 70, 60, 50, 50, 60, 70, 90, - 80, 60, 40, 30, 30, 40, 60, 80, - 70, 50, 30, 20, 20, 30, 50, 70, - 70, 50, 30, 20, 20, 30, 50, 70, - 80, 60, 40, 30, 30, 40, 60, 80, - 90, 70, 60, 50, 50, 60, 70, 90, - 100, 90, 80, 70, 70, 80, 90, 100 - }; + inline int push_to_edge(Square s) { + int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s)); + return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2); + } - // Table used to drive the king towards a corner square of the - // right color in KBN vs K endgames. - constexpr int PushToCorners[SQUARE_NB] = { - 6400, 6080, 5760, 5440, 5120, 4800, 4480, 4160, - 6080, 5760, 5440, 5120, 4800, 4480, 4160, 4480, - 5760, 5440, 4960, 4480, 4480, 4000, 4480, 4800, - 5440, 5120, 4480, 3840, 3520, 4480, 4800, 5120, - 5120, 4800, 4480, 3520, 3840, 4480, 5120, 5440, - 4800, 4480, 4000, 4480, 4480, 4960, 5440, 5760, - 4480, 4160, 4480, 4800, 5120, 5440, 5760, 6080, - 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 - }; + // Used to drive the king towards A1H8 corners in KBN vs K endgames. + inline int push_to_corner(Square s) { + return abs(7 - rank_of(s) - file_of(s)); + } // Drive a piece close to or away from another piece inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } @@ -126,7 +112,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) @@ -155,9 +141,9 @@ Value Endgame::operator()(const Position& pos) const { // If our bishop does not attack A1/H8, we flip the enemy king square // to drive to opposite corners (A8/H1). - Value result = VALUE_KNOWN_WIN + Value result = (VALUE_KNOWN_WIN + 3520) + push_close(winnerKSq, loserKSq) - + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; + + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq); assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; @@ -240,7 +226,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Value result = Value(PushToEdges[pos.square(weakSide)]); + Value result = Value(push_to_edge(pos.square(weakSide))); return strongSide == pos.side_to_move() ? result : -result; } @@ -255,7 +241,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); + Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -300,7 +286,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; @@ -316,7 +302,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); Value result = PawnValueEg - + 2 * PushToEdges[pos.square(weakSide)] + + 2 * push_to_edge(pos.square(weakSide)) - 10 * relative_rank(weakSide, pos.square(weakSide)); return strongSide == pos.side_to_move() ? result : -result; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 5d073b15..40630d22 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -643,7 +643,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * map_to_queenside(file_of(s)); + score += bonus - PassedFile * edge_distance(file_of(s)); } if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index 9981ac01..560fd76b 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -202,7 +202,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = map_to_queenside(f); + File d = edge_distance(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index f6f5933c..d86e98e4 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -21,6 +21,7 @@ #include #include "types.h" +#include "bitboard.h" namespace PSQT { @@ -111,7 +112,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = map_to_queenside(file_of(s)); + File f = edge_distance(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][flip_rank(s)] = -psq[pc][s]; diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 6f369455..2532bbd3 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -705,7 +705,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp)); - tbFile = map_to_queenside(file_of(squares[0])); + tbFile = edge_distance(file_of(squares[0])); } // DTZ tables are one-sided, i.e. they store positions only for white to diff --git a/src/types.h b/src/types.h index d4937fd6..71893c0f 100644 --- a/src/types.h +++ b/src/types.h @@ -370,10 +370,6 @@ constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } -inline File map_to_queenside(File f) { - return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA -} - constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } From c077bfb413fbed8d6fa94459135ca81f9977c2f2 Mon Sep 17 00:00:00 2001 From: silversolver1 <61594747+silversolver1@users.noreply.github.com> Date: Sun, 8 Mar 2020 14:52:05 -0500 Subject: [PATCH 042/142] Remove set statScore to zero Simplification. Removes setting statScore to zero if negative. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 84820 W: 16100 L: 16033 D: 52687 Ptnml(0-2): 1442, 9865, 19723, 9944, 1436 https://tests.stockfishchess.org/tests/view/5e654fdae42a5c3b3ca2e2f8 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 57658 W: 7435 L: 7391 D: 42832 Ptnml(0-2): 441, 5397, 17104, 5451, 436 https://tests.stockfishchess.org/tests/view/5e657ce9e42a5c3b3ca2e307 closes https://github.com/official-stockfish/Stockfish/pull/2578 Bench: 5168890 --- AUTHORS | 5 +---- src/search.cpp | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7657acee..4826d1c4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -123,6 +123,7 @@ Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) pellanda Peter Zsifkovits (CoffeeOne) +Rahul Dsilva (silversolver1) Ralph Stößer (Ralph Stoesser) Raminder Singh renouve @@ -158,7 +159,3 @@ Vince Negri (cuddlestmonkey) # an amazing and essential framework for the development of Stockfish! # # https://github.com/glinscott/fishtest/blob/master/AUTHORS - - - - diff --git a/src/search.cpp b/src/search.cpp index 3d130efc..f9910fb7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1175,13 +1175,6 @@ moves_loop: // When in check, search starts from here + (*contHist[3])[movedPiece][to_sq(move)] - 4926; - // Reset statScore to zero if negative and most stats shows >= 0 - if ( ss->statScore < 0 - && (*contHist[0])[movedPiece][to_sq(move)] >= 0 - && (*contHist[1])[movedPiece][to_sq(move)] >= 0 - && thisThread->mainHistory[us][from_to(move)] >= 0) - ss->statScore = 0; - // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) if (ss->statScore >= -102 && (ss-1)->statScore < -114) r--; From 442e1e0f9348226986e568bd52e1b909ec347218 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 11 Mar 2020 16:27:51 -0600 Subject: [PATCH 043/142] simplify castling part of generate_all. somewhat more compact, generates same code. close https://github.com/official-stockfish/Stockfish/pull/2580 No functional change. --- src/movegen.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 7e8961ae..9964ad34 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -214,9 +214,6 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { - - constexpr CastlingRights OO = Us & KING_SIDE; - constexpr CastlingRights OOO = Us & QUEEN_SIDE; constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); @@ -232,14 +229,10 @@ namespace { while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); - if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) - { - if (!pos.castling_impeded(OO) && pos.can_castle(OO)) - *moveList++ = make(ksq, pos.castling_rook_square(OO)); - - if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) - *moveList++ = make(ksq, pos.castling_rook_square(OOO)); - } + if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) + for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) + if (!pos.castling_impeded(cr) && pos.can_castle(cr)) + *moveList++ = make(ksq, pos.castling_rook_square(cr)); } return moveList; From ec2002c594cce22dfbbdc7b6b8df2828a00d18cf Mon Sep 17 00:00:00 2001 From: pb00067 Date: Fri, 13 Mar 2020 19:29:36 +0100 Subject: [PATCH 044/142] Simplify futility pruning parent node only continuation histories seem needed for this purpose. STC: http://tests.stockfishchess.org/tests/view/5e6b88dfe42a5c3b3ca2e4ab LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 113356 W: 21725 L: 21696 D: 69935 Ptnml(0-2): 1999, 13255, 26163, 13240, 2021 LTC: http://tests.stockfishchess.org/tests/view/5e6babbfe42a5c3b3ca2e4c2 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 22164 W: 2917 L: 2821 D: 16426 Ptnml(0-2): 173, 2040, 6548, 2160, 161 closes https://github.com/official-stockfish/Stockfish/pull/2583 bench: 4839496 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f9910fb7..70520ac9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1024,10 +1024,9 @@ moves_loop: // When in check, search starts from here if ( lmrDepth < 6 && !inCheck && ss->staticEval + 235 + 172 * lmrDepth <= alpha - && thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] + && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < 25000) + + (*contHist[3])[movedPiece][to_sq(move)] < 27400) continue; // Prune moves with negative SEE (~20 Elo) From ddcbacd04d1c860e808202ce8c1206c8acdca627 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 14 Mar 2020 17:04:50 +0100 Subject: [PATCH 045/142] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2567 No functional change. --- src/bitboard.h | 5 ++++- src/endgame.cpp | 31 +++++++++++++------------------ src/position.cpp | 5 +---- src/search.cpp | 10 ++++++++-- src/syzygy/tbprobe.cpp | 2 +- src/tt.h | 2 +- src/types.h | 2 +- src/uci.cpp | 2 +- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index f1d14603..529e3dfe 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -375,14 +375,17 @@ inline Square msb(Bitboard b) { /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard inline Square pop_lsb(Bitboard* b) { + assert(*b); const Square s = lsb(*b); *b &= *b - 1; return s; } -/// frontmost_sq() returns the most advanced square for the given color +/// frontmost_sq() returns the most advanced square for the given color, +/// requires a non-zero bitboard. inline Square frontmost_sq(Color c, Bitboard b) { + assert(b); return c == WHITE ? msb(b) : lsb(b); } diff --git a/src/endgame.cpp b/src/endgame.cpp index 0a2b02ad..56583c58 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -24,8 +24,6 @@ #include "endgame.h" #include "movegen.h" -using std::string; - namespace { // Used to drive the king towards the edge of the board @@ -326,23 +324,23 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // No assertions about the material of weakSide, because we want draws to // be detected even when the weaker side has some pawns. - Bitboard strongpawns = pos.pieces(strongSide, PAWN); - Bitboard allpawns = pos.pieces(PAWN); + Bitboard strongPawns = pos.pieces(strongSide, PAWN); + Bitboard allPawns = pos.pieces(PAWN); // All strongSide pawns are on a single rook file? - if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB)) + if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB)) { Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8)); - Square weakkingSq = pos.square(weakSide); + Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8)); + Square weakKingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, weakkingSq) <= 1) + && distance(queeningSq, weakKingSq) <= 1) return SCALE_FACTOR_DRAW; } // If all the pawns are on the same B or G file, then it's potentially a draw - if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB)) + if ((!(allPawns & ~FileBBB) || !(allPawns & ~FileGBB)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { @@ -356,8 +354,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left if ( relative_rank(strongSide, weakPawnSq) == RANK_7 - && (strongpawns & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns))) + && (strongPawns & (weakPawnSq + pawn_push(weakSide))) + && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongPawns))) { int strongKingDist = distance(weakPawnSq, strongKingSq); int weakKingDist = distance(weakPawnSq, weakKingSq); @@ -588,11 +586,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square ksq = pos.square(weakSide); Bitboard pawns = pos.pieces(strongSide, PAWN); - // If all pawns are ahead of the king, on a single rook file and - // the king is within one file of the pawns, it's a draw. - if ( !(pawns & ~forward_ranks_bb(weakSide, ksq)) - && !((pawns & ~FileABB) && (pawns & ~FileHBB)) - && distance(ksq, lsb(pawns)) <= 1) + // If all pawns are ahead of the king on a single rook file, it's a draw. + if (!((pawns & ~FileABB) || (pawns & ~FileHBB)) && + !(pawns & ~passed_pawn_span(weakSide, ksq))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -615,8 +611,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square weakKingSq = pos.square(weakSide); // Case 1: Defending king blocks the pawn, and cannot be driven away - if ( file_of(weakKingSq) == file_of(pawnSq) - && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq) + if ( (forward_file_bb(strongSide, pawnSq) & weakKingSq) && ( opposite_colors(weakKingSq, strongBishopSq) || relative_rank(strongSide, weakKingSq) <= RANK_6)) return SCALE_FACTOR_DRAW; diff --git a/src/position.cpp b/src/position.cpp index 0ac45057..fefce56e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1121,10 +1121,7 @@ bool Position::is_draw(int ply) const { // Return a draw score if a position repeats once earlier but strictly // after the root, or repeats twice before or at the root. - if (st->repetition && st->repetition < ply) - return true; - - return false; + return st->repetition && st->repetition < ply; } diff --git a/src/search.cpp b/src/search.cpp index 70520ac9..a54e181a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1193,10 +1193,16 @@ moves_loop: // When in check, search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && d != newDepth), didLMR = true; + doFullDepthSearch = value > alpha && d != newDepth; + + didLMR = true; } else - doFullDepthSearch = !PvNode || moveCount > 1, didLMR = false; + { + doFullDepthSearch = !PvNode || moveCount > 1; + + didLMR = false; + } // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 2532bbd3..34e4331d 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -769,7 +769,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu if (!off_A1H8(squares[i])) continue; - if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C3 + if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C1 for (int j = i; j < size; ++j) squares[j] = Square(((squares[j] >> 3) | (squares[j] << 3)) & 63); break; diff --git a/src/tt.h b/src/tt.h index 142afd90..8b70f797 100644 --- a/src/tt.h +++ b/src/tt.h @@ -41,7 +41,7 @@ struct TTEntry { Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; } - bool is_pv() const { return (bool)(genBound8 & 0x4); } + bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --git a/src/types.h b/src/types.h index 71893c0f..bfcd3f23 100644 --- a/src/types.h +++ b/src/types.h @@ -220,7 +220,7 @@ enum : int { DEPTH_QS_RECAPTURES = -5, DEPTH_NONE = -6, - DEPTH_OFFSET = DEPTH_NONE, + DEPTH_OFFSET = DEPTH_NONE }; enum Square : int { diff --git a/src/uci.cpp b/src/uci.cpp index 8b35e6fd..33577a4e 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -260,7 +260,7 @@ string UCI::value(Value v) { stringstream ss; - if (abs(v) < VALUE_MATE - MAX_PLY) + if (abs(v) < VALUE_MATE_IN_MAX_PLY) ss << "cp " << v * 100 / PawnValueEg; else ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; From 07caca2587d3090921b99f37fa8c9bf6a29a89af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 17 Mar 2020 08:26:27 +0100 Subject: [PATCH 046/142] Anchored bishops Reduce the "bad bishop" penalty when the bishop is protected by one of our pawns, as it may indicate that the bishop has found a safe spot outside the pawn chain. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 176942 W: 34142 L: 33696 D: 109104 Ptnml(0-2): 3129, 20422, 40919, 20876, 3125 http://tests.stockfishchess.org/tests/view/5e6f61aae42a5c3b3ca2e62d LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 42252 W: 5615 L: 5322 D: 31315 Ptnml(0-2): 308, 3881, 12500, 4084, 353 http://tests.stockfishchess.org/tests/view/5e701382e42a5c3b3ca2e661 closes https://github.com/official-stockfish/Stockfish/pull/2587 Bench: 4963440 --- src/evaluate.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 40630d22..fad2a785 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -308,11 +308,12 @@ namespace { if (Pt == BISHOP) { // Penalty according to number of pawns on the same color square as the - // bishop, bigger when the center files are blocked with pawns. + // bishop, bigger when the center files are blocked with pawns and smaller + // when the bishop is outside the pawn chain. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) - * (1 + popcount(blocked & CenterFiles)); + * (!bool(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) From ff271093139de92ebf4f4f8b8c67474e07d6a8bf Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 17 Mar 2020 19:38:21 +0300 Subject: [PATCH 047/142] Adjust singular LMR for positions seen in PV This patch continues work on altering search for ttPv nodes, using recent idea to alter it more in not PvNodes. Previous tweak based on this idea adjusted singularBeta - this one adjusts value of singularLMR, so they are both related to singular extension search. passed STC http://tests.stockfishchess.org/tests/view/5e700737e42a5c3b3ca2e659 LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 140608 W: 27053 L: 26659 D: 86896 Ptnml(0-2): 2425, 16337, 32439, 16625, 2478 passed LTC http://tests.stockfishchess.org/tests/view/5e7068eae42a5c3b3ca2e687 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 79318 W: 10463 L: 10064 D: 58791 Ptnml(0-2): 567, 7416, 23359, 7685, 632 closes https://github.com/official-stockfish/Stockfish/pull/2588 Bench: 4952322 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index a54e181a..fe57806c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1149,7 +1149,7 @@ moves_loop: // When in check, search starts from here // Decrease reduction if ttMove has been singularly extended (~3 Elo) if (singularLMR) - r -= 2; + r -= 1 + (ttPv && !PvNode); if (!captureOrPromotion) { From 6ecab03dee15fe30bc0237919180a2e51e0ce4b1 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 20 Mar 2020 12:12:56 +0300 Subject: [PATCH 048/142] Adjust singular extension search depth This patch applies a different singular extension search logic in case the position is ttPv && !PvNode. It changes the depth of this search, higher for this types of nodes, and lower for other nodes. passed STC http://tests.stockfishchess.org/tests/view/5e72bbaae42a5c3b3ca2e75e LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 12692 W: 2608 L: 2389 D: 7695 Ptnml(0-2): 238, 1414, 2839, 1601, 254 passed LTC http://tests.stockfishchess.org/tests/view/5e731c07e42a5c3b3ca2e770 LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 145716 W: 19218 L: 18626 D: 107872 Ptnml(0-2): 1100, 13605, 42899, 14111, 1143 closes https://github.com/official-stockfish/Stockfish/pull/2590 Bench: 5398277 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index fe57806c..abc6874e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1055,9 +1055,9 @@ moves_loop: // When in check, search starts from here && pos.legal(move)) { Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; - Depth halfDepth = depth / 2; + Depth singularDepth = (depth - 1 + 3 * (ttPv && !PvNode)) / 2; ss->excludedMove = move; - value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); + value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); ss->excludedMove = MOVE_NONE; if (value < singularBeta) From 8b229381daa9c2537dc9a8cf5080a3a282265d0a Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 22 Mar 2020 22:21:49 -0600 Subject: [PATCH 049/142] Remove KNPKB endgame. This is a functional simplification that removes the KNPKB endgame. Testing on only KNPKB positions suggests that this removal actually gains Elo: Score of patch vs master: 3380 - 3035 - 33585 [0.504] 40000 Elo difference: 3.0 +/- 1.4, LOS: 100.0 %, DrawRatio: 84.0 % Score of patch vs master: 290 - 36 - 39674 [0.503] 40000 Elo difference: 2.2 +/- 0.3, LOS: 100.0 %, DrawRatio: 99.2 % removal also doesn't cause a regression with the standard book: STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 71376 W: 13794 L: 13719 D: 43863 Ptnml(0-2): 1066, 8092, 17290, 8181, 1059 https://tests.stockfishchess.org/tests/view/5e76c3d5e42a5c3b3ca2e8be LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 28394 W: 3731 L: 3662 D: 21001 Ptnml(0-2): 167, 2339, 9116, 2408, 167 https://tests.stockfishchess.org/tests/view/5e76e5eae42a5c3b3ca2e8d3 closes https://github.com/official-stockfish/Stockfish/pull/2594 Bench 5480811 --- src/endgame.cpp | 22 ---------------------- src/endgame.h | 1 - 2 files changed, 23 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 56583c58..1a5959e5 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -80,7 +80,6 @@ namespace Endgames { add("KNNKP"); add("KNPK"); - add("KNPKB"); add("KRPKR"); add("KRPKB"); add("KBPKB"); @@ -733,27 +732,6 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// KNP vs KB. If knight can block bishop from taking pawn, it's a win. -/// Otherwise the position is drawn. -template<> -ScaleFactor Endgame::operator()(const Position& pos) const { - - assert(verify_material(pos, strongSide, KnightValueMg, 1)); - assert(verify_material(pos, weakSide, BishopValueMg, 0)); - - Square pawnSq = pos.square(strongSide); - Square bishopSq = pos.square(weakSide); - Square weakKingSq = pos.square(weakSide); - - // King needs to get close to promoting pawn to prevent knight from blocking. - // Rules for this are very tricky, so just approximate. - if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from(bishopSq)) - return ScaleFactor(distance(weakKingSq, pawnSq)); - - return SCALE_FACTOR_NONE; -} - - /// KP vs KP. This is done by removing the weakest side's pawn and probing the /// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably /// has at least a draw with the pawn as well. The exception is when the stronger diff --git a/src/endgame.h b/src/endgame.h index f6135354..49ebb603 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -58,7 +58,6 @@ enum EndgameCode { KBPPKB, // KBPP vs KB KBPKN, // KBP vs KN KNPK, // KNP vs K - KNPKB, // KNP vs KB KPKP // KP vs KP }; From c8e8e48b144bcc50c5423b771eb668eafb13af99 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 25 Mar 2020 16:06:25 +0000 Subject: [PATCH 050/142] Remove passed_count from almostUnwinnable. This simplification allows the almostUnwinnable flag to match endgames where the pawns are all on the same flank but are not symmetrical. STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 23356 W: 4543 L: 4395 D: 14418 Ptnml(0-2): 346, 2651, 5582, 2707, 392 https://tests.stockfishchess.org/tests/view/5e7b8f57e42a5c3b3ca2eb09 LTC: LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 31778 W: 4097 L: 4023 D: 23658 Ptnml(0-2): 199, 2853, 9729, 2891, 217 https://tests.stockfishchess.org/tests/view/5e7ba5ade42a5c3b3ca2eb16 closes https://github.com/official-stockfish/Stockfish/pull/2596 Bench 4777139 --- src/evaluate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fad2a785..d51325f0 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -707,8 +707,7 @@ namespace { bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); - bool almostUnwinnable = !pe->passed_count() - && outflanking < 0 + bool almostUnwinnable = outflanking < 0 && !pawnsOnBothFlanks; bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 From 58746d9fb8bab4e9617cd7c809c6a0afd809c35e Mon Sep 17 00:00:00 2001 From: Lyudmil Antonov Date: Mon, 17 Feb 2020 11:13:03 +0200 Subject: [PATCH 051/142] Tuned history reduction Value after a long Bayesian tuning, using a home-made classification approach. STC https://tests.stockfishchess.org/tests/view/5e7c7b16e42a5c3b3ca2eb66 LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 45472 W: 8992 L: 8732 D: 27748 Ptnml(0-2): 795, 5276, 10352, 5500, 813 LTC https://tests.stockfishchess.org/tests/view/5e7c8be7e42a5c3b3ca2eb75 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 22744 W: 3085 L: 2849 D: 16810 Ptnml(0-2): 156, 2090, 6658, 2298, 170 closes https://github.com/official-stockfish/Stockfish/pull/2597 Bench 5030855 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index abc6874e..c5a7582c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1182,7 +1182,7 @@ moves_loop: // When in check, search starts from here r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 16384; + r -= ss->statScore / 16434; } // Increase reduction for captures/promotions if late move and at low depth From 8c73339a3639f1753b2270b569532daffa7d93f5 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 26 Mar 2020 19:47:48 +0000 Subject: [PATCH 052/142] Remove previousScore adjustment of delta. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 14580 W: 2904 L: 2731 D: 8945 Ptnml(0-2): 243, 1665, 3339, 1762, 281 https://tests.stockfishchess.org/tests/view/5e7d080ae42a5c3b3ca2ebc6 LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 60338 W: 7870 L: 7831 D: 44637 Ptnml(0-2): 451, 5596, 18018, 5671, 433 https://tests.stockfishchess.org/tests/view/5e7d11b3e42a5c3b3ca2ebd3 closes https://github.com/official-stockfish/Stockfish/pull/2598 Bench 5247262 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index c5a7582c..f866afe5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -433,7 +433,7 @@ void Thread::search() { if (rootDepth >= 4) { Value previousScore = rootMoves[pvIdx].previousScore; - delta = Value(21 + abs(previousScore) / 256); + delta = Value(21); alpha = std::max(previousScore - delta,-VALUE_INFINITE); beta = std::min(previousScore + delta, VALUE_INFINITE); From f2430bf034cc31258c870797501bce0605bce3d0 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 29 Mar 2020 20:04:20 +0300 Subject: [PATCH 053/142] Count only the most advanced passed pawn for each file. This patch adjusts definition of passed pawns - if there is a pawn of our color in the same file in front of a current pawn it's no longer counts as passed. passed STC https://tests.stockfishchess.org/tests/view/5e802037e42a5c3b3ca2ed07 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 215296 W: 41843 L: 41341 D: 132112 Ptnml(0-2): 3688, 25313, 49304, 25495, 3848 passed LTC https://tests.stockfishchess.org/tests/view/5e806441e42a5c3b3ca2ed2b LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 74050 W: 9761 L: 9379 D: 54910 Ptnml(0-2): 510, 6838, 22025, 7064, 588 closes https://github.com/official-stockfish/Stockfish/pull/2602 bench: 4902237 --- src/pawns.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pawns.cpp b/src/pawns.cpp index 560fd76b..3023021d 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -124,6 +124,8 @@ namespace { || ( stoppers == blocked && r >= RANK_5 && (shift(support) & ~(theirPawns | doubleAttackThem))); + passed &= !(forward_file_bb(Us, s) & ourPawns); + // Passed pawns will be properly scored later in evaluation when we have // full attack info. if (passed) From b7ecdaada7e2690dd286c41d3a73463f06fb088f Mon Sep 17 00:00:00 2001 From: Praveen tummala Date: Mon, 30 Mar 2020 10:22:42 +0530 Subject: [PATCH 054/142] Movecount pruning reduction logic This patch refines search reduction logic in case the position is not a former PV node and is pruned based on move count. passed STC https://tests.stockfishchess.org/tests/view/5e8092bde42a5c3b3ca2ed35 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 78848 W: 15480 L: 15170 D: 48198 Ptnml(0-2): 1406, 9310, 17773, 9438, 1497 passed LTC https://tests.stockfishchess.org/tests/view/5e80bb13e42a5c3b3ca2ed4b LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 86596 W: 11451 L: 11033 D: 64112 Ptnml(0-2): 624, 7993, 25687, 8329, 665 closes https://github.com/official-stockfish/Stockfish/pull/2605 Bench: 5138771 --- AUTHORS | 3 ++- src/search.cpp | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4826d1c4..79eb98a0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# List of authors for Stockfish, as of January 7, 2020 +# List of authors for Stockfish, as of March 30, 2020 Tord Romstad (romstad) Marco Costalba (mcostalba) @@ -123,6 +123,7 @@ Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) pellanda Peter Zsifkovits (CoffeeOne) +Praveen Kumar Tummala (praveentml) Rahul Dsilva (silversolver1) Ralph Stößer (Ralph Stoesser) Raminder Singh diff --git a/src/search.cpp b/src/search.cpp index f866afe5..993fa853 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -962,6 +962,7 @@ moves_loop: // When in check, search starts from here value = bestValue; singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); + bool formerPv = ttPv && !PvNode; // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); @@ -1054,8 +1055,8 @@ moves_loop: // When in check, search starts from here && tte->depth() >= depth - 3 && pos.legal(move)) { - Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; - Depth singularDepth = (depth - 1 + 3 * (ttPv && !PvNode)) / 2; + Value singularBeta = ttValue - ((formerPv + 4) * depth) / 2; + Depth singularDepth = (depth - 1 + 3 * formerPv) / 2; ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); ss->excludedMove = MOVE_NONE; @@ -1143,13 +1144,16 @@ moves_loop: // When in check, search starts from here if (ttPv) r -= 2; + if (moveCountPruning && !formerPv) + r++; + // Decrease reduction if opponent's move count is high (~5 Elo) if ((ss-1)->moveCount > 14) r--; // Decrease reduction if ttMove has been singularly extended (~3 Elo) if (singularLMR) - r -= 1 + (ttPv && !PvNode); + r -= 1 + formerPv; if (!captureOrPromotion) { From 209e94203f8c4d0a48405192d1e71c80f28f3159 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 30 Mar 2020 22:45:35 +0200 Subject: [PATCH 055/142] Small cleanups https://github.com/official-stockfish/Stockfish/pull/2584 No functional change. --- src/bitboard.cpp | 34 ++++++++++++++-------------------- src/evaluate.cpp | 26 +++++++++++++------------- src/material.cpp | 2 +- src/movegen.cpp | 4 ++-- src/movepick.cpp | 2 +- src/pawns.cpp | 4 ++-- src/position.cpp | 2 +- src/search.cpp | 4 ++-- src/uci.cpp | 2 +- 9 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 70114f20..bb03dfeb 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -78,11 +78,11 @@ void Bitboards::init() { for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - PawnAttacks[WHITE][s] = pawn_attacks_bb(square_bb(s)); - PawnAttacks[BLACK][s] = pawn_attacks_bb(square_bb(s)); - } + Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; + Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; + + init_magics(RookTable, RookMagics, RookDirections); + init_magics(BishopTable, BishopMagics, BishopDirections); // Helper returning the target bitboard of a step from a square auto landing_square_bb = [&](Square s, int step) @@ -91,23 +91,17 @@ void Bitboards::init() { return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); }; - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) - PseudoAttacks[KING][s] |= landing_square_bb(s, step); - - for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) - PseudoAttacks[KNIGHT][s] |= landing_square_bb(s, step); - } - - Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; - Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; - - init_magics(RookTable, RookMagics, RookDirections); - init_magics(BishopTable, BishopMagics, BishopDirections); - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) { + PawnAttacks[WHITE][s1] = pawn_attacks_bb(square_bb(s1)); + PawnAttacks[BLACK][s1] = pawn_attacks_bb(square_bb(s1)); + + for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) + PseudoAttacks[KING][s1] |= landing_square_bb(s1, step); + + for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) + PseudoAttacks[KNIGHT][s1] |= landing_square_bb(s1, step); + PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d51325f0..63541c2a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -91,15 +91,15 @@ namespace { // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. constexpr Score MobilityBonus[][32] = { - { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knights + { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knight S( 22, 23), S( 28, 27), S( 33, 33) }, - { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops + { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, - { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rooks + { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rook S( 9,112), S( 16,118), S( 30,132), S( 29,142), S( 32,155), S( 38,165), S( 46,166), S( 48,169), S( 58,171) }, - { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queens + { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queen S( 28, 61), S( 41, 73), S( 43, 79), S( 48, 92), S( 56, 94), S( 60,104), S( 60,113), S( 66,120), S( 67,123), S( 70,126), S( 71,133), S( 73,136), S( 79,140), S( 88,143), S( 88,148), S( 99,166), S(102,170), S(102,175), @@ -213,7 +213,7 @@ namespace { template template void Evaluation::initialize() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); constexpr Direction Down = -Up; constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); @@ -252,7 +252,7 @@ namespace { template template Score Evaluation::pieces() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); @@ -298,12 +298,12 @@ namespace { else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) score += Outpost; - // Knight and Bishop bonus for being right behind a pawn + // Bonus for a knight or bishop shielded by pawn if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; // Penalty if the piece is far from the king - score -= KingProtector * distance(s, pos.square(Us)); + score -= KingProtector * distance(pos.square(Us), s); if (Pt == BISHOP) { @@ -313,7 +313,7 @@ namespace { Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) - * (!bool(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); + * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) @@ -372,7 +372,7 @@ namespace { template template Score Evaluation::king() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); @@ -480,7 +480,7 @@ namespace { template template Score Evaluation::threats() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); @@ -576,7 +576,7 @@ namespace { template template Score Evaluation::passed() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); auto king_proximity = [&](Color c, Square s) { @@ -667,7 +667,7 @@ namespace { if (pos.non_pawn_material() < SpaceThreshold) return SCORE_ZERO; - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Down = -pawn_push(Us); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) diff --git a/src/material.cpp b/src/material.cpp index 7e212461..93699f5f 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -84,7 +84,7 @@ namespace { template int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; int bonus = 0; diff --git a/src/movegen.cpp b/src/movegen.cpp index 9964ad34..804ef87b 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -52,7 +52,7 @@ namespace { template ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); constexpr Direction Up = pawn_push(Us); @@ -319,7 +319,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { while (sliders) { Square checksq = pop_lsb(&sliders); - sliderAttacks |= LineBB[checksq][ksq] ^ checksq; + sliderAttacks |= LineBB[ksq][checksq] ^ checksq; } // Generate evasions for king, capture and non capture moves diff --git a/src/movepick.cpp b/src/movepick.cpp index 575c9022..580c6d75 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -59,7 +59,7 @@ namespace { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) , ply(pl) { + refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); diff --git a/src/pawns.cpp b/src/pawns.cpp index 3023021d..8759631a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -68,7 +68,7 @@ namespace { template Score evaluate(const Position& pos, Pawns::Entry* e) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); Bitboard neighbours, stoppers, support, phalanx, opposed; @@ -187,7 +187,7 @@ Entry* probe(const Position& pos) { template Score Entry::evaluate_shelter(const Position& pos, Square ksq) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us); diff --git a/src/position.cpp b/src/position.cpp index fefce56e..6bbb7914 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -666,7 +666,7 @@ bool Position::gives_check(Move m) const { case CASTLING: { Square kfrom = from; - Square rfrom = to; // Castling is encoded as 'King captures the rook' + Square rfrom = to; // Castling is encoded as 'king captures the rook' Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); diff --git a/src/search.cpp b/src/search.cpp index 993fa853..38d3204c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -292,7 +292,7 @@ void MainThread::search() { if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) { - // Make sure we pick the shortest mate + // Make sure we pick the shortest mate / TB conversion if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } @@ -867,7 +867,7 @@ namespace { if (nullValue >= beta) { - // Do not return unproven mate scores + // Do not return unproven mate or TB scores if (nullValue >= VALUE_TB_WIN_IN_MAX_PLY) nullValue = beta; diff --git a/src/uci.cpp b/src/uci.cpp index 33577a4e..11d5adc6 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -115,7 +115,7 @@ namespace { limits.startTime = now(); // As early as possible! while (is >> token) - if (token == "searchmoves") + if (token == "searchmoves") // Needs to be the last command on the line while (is >> token) limits.searchmoves.push_back(UCI::to_move(pos, token)); From 0b8ce4b3037c0efcb2c8bf10598ec3f4fd919e1a Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 25 Mar 2020 19:57:36 -0600 Subject: [PATCH 056/142] Limit array access in Position This is a non-functional code style change that routes all position array accesses to single methods, and adds an assert to check correctness. Passed STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 37312 W: 7378 L: 7246 D: 22688 Ptnml(0-2): 606, 4280, 8762, 4392, 616 https://tests.stockfishchess.org/tests/view/5e7c0c69e42a5c3b3ca2eb3d closes https://github.com/official-stockfish/Stockfish/pull/2595 No functional change. --- src/position.h | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/position.h b/src/position.h index e5071d53..f79c5463 100644 --- a/src/position.h +++ b/src/position.h @@ -83,7 +83,6 @@ public: const std::string fen() const; // Position representation - Bitboard pieces() const; Bitboard pieces(PieceType pt) const; Bitboard pieces(PieceType pt1, PieceType pt2) const; Bitboard pieces(Color c) const; @@ -207,28 +206,25 @@ inline Color Position::side_to_move() const { return sideToMove; } -inline bool Position::empty(Square s) const { - return board[s] == NO_PIECE; -} - inline Piece Position::piece_on(Square s) const { + assert(is_ok(s)); return board[s]; } +inline bool Position::empty(Square s) const { + return piece_on(s) == NO_PIECE; +} + inline Piece Position::moved_piece(Move m) const { - return board[from_sq(m)]; + return piece_on(from_sq(m)); } -inline Bitboard Position::pieces() const { - return byTypeBB[ALL_PIECES]; -} - -inline Bitboard Position::pieces(PieceType pt) const { +inline Bitboard Position::pieces(PieceType pt = ALL_PIECES) const { return byTypeBB[pt]; } inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const { - return byTypeBB[pt1] | byTypeBB[pt2]; + return pieces(pt1) | pieces(pt2); } inline Bitboard Position::pieces(Color c) const { @@ -236,11 +232,11 @@ inline Bitboard Position::pieces(Color c) const { } inline Bitboard Position::pieces(Color c, PieceType pt) const { - return byColorBB[c] & byTypeBB[pt]; + return pieces(c) & pieces(pt); } inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const { - return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]); + return pieces(c) & (pieces(pt1) | pieces(pt2)); } template inline int Position::count(Color c) const { @@ -248,7 +244,7 @@ template inline int Position::count(Color c) const { } template inline int Position::count() const { - return pieceCount[make_piece(WHITE, Pt)] + pieceCount[make_piece(BLACK, Pt)]; + return count(WHITE) + count(BLACK); } template inline const Square* Position::squares(Color c) const { @@ -257,7 +253,7 @@ template inline const Square* Position::squares(Color c) const { template inline Square Position::square(Color c) const { assert(pieceCount[make_piece(c, Pt)] == 1); - return pieceList[make_piece(c, Pt)][0]; + return squares(c)[0]; } inline Square Position::ep_square() const { @@ -279,7 +275,7 @@ inline int Position::castling_rights(Color c) const { inline bool Position::castling_impeded(CastlingRights cr) const { assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); - return byTypeBB[ALL_PIECES] & castlingPath[cr]; + return pieces() & castlingPath[cr]; } inline Square Position::castling_rook_square(CastlingRights cr) const { @@ -292,7 +288,7 @@ template inline Bitboard Position::attacks_from(Square s) const { static_assert(Pt != PAWN, "Pawn attacks need color"); - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, byTypeBB[ALL_PIECES]) + return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, pieces()) : Pt == QUEEN ? attacks_from(s) | attacks_from(s) : PseudoAttacks[Pt][s]; } @@ -303,11 +299,11 @@ inline Bitboard Position::attacks_from(Square s, Color c) const { } inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, byTypeBB[ALL_PIECES]); + return attacks_bb(pt, s, pieces()); } inline Bitboard Position::attackers_to(Square s) const { - return attackers_to(s, byTypeBB[ALL_PIECES]); + return attackers_to(s, pieces()); } inline Bitboard Position::checkers() const { @@ -360,7 +356,7 @@ inline Value Position::non_pawn_material(Color c) const { } inline Value Position::non_pawn_material() const { - return st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK]; + return non_pawn_material(WHITE) + non_pawn_material(BLACK); } inline int Position::game_ply() const { @@ -372,8 +368,8 @@ inline int Position::rule50_count() const { } inline bool Position::opposite_bishops() const { - return pieceCount[W_BISHOP] == 1 - && pieceCount[B_BISHOP] == 1 + return count(WHITE) == 1 + && count(BLACK) == 1 && opposite_colors(square(WHITE), square(BLACK)); } From 84f3bf594d323ac4fcaac0b6681edcdf2f9da70f Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 29 Mar 2020 14:09:19 -0700 Subject: [PATCH 057/142] No voting for TB loss / mate. Just as we pick the shortest mate also make sure we stave off mate as long as possible. https://github.com/official-stockfish/Stockfish/pull/2603 bench: 5138771 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 38d3204c..ad5b364d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -280,7 +280,7 @@ void MainThread::search() { std::map votes; Value minScore = this->rootMoves[0].score; - // Find out minimum score + // Find minimum score for (Thread* th: Threads) minScore = std::min(minScore, th->rootMoves[0].score); @@ -290,14 +290,15 @@ void MainThread::search() { votes[th->rootMoves[0].pv[0]] += (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) + if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) { - // Make sure we pick the shortest mate / TB conversion + // Make sure we pick the shortest mate / TB conversion or stave off mate the longest if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY - || votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) + || ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY + && votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) bestThread = th; } } From 375e4eeaf5e739c176c38ff05ae954bb60a98987 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:53:02 -0400 Subject: [PATCH 058/142] Simplify a candidate passer condition. STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 31528 W: 6208 L: 6061 D: 19259 Ptnml(0-2): 541, 3673, 7205, 3788, 557 https://tests.stockfishchess.org/tests/view/5e825db0e42a5c3b3ca2ee21 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 38546 W: 5083 L: 5009 D: 28454 Ptnml(0-2): 299, 3628, 11362, 3668, 316 https://tests.stockfishchess.org/tests/view/5e826ec7e42a5c3b3ca2ee2a closes https://github.com/official-stockfish/Stockfish/pull/2607 Bench: 5139561 --- src/evaluate.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 63541c2a..57491f34 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -639,9 +639,8 @@ namespace { } // r > RANK_3 // Scale down bonus for candidate passers which need more than one - // pawn push to become passed, or have a pawn in front of them. - if ( !pos.pawn_passed(Us, s + Up) - || (pos.pieces(PAWN) & (s + Up))) + // pawn push to become passed. + if (!pos.pawn_passed(Us, s + Up)) bonus = bonus / 2; score += bonus - PassedFile * edge_distance(file_of(s)); From c14f4877cf8067e0913a6db4ab05fef9a853c1d0 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 2 Apr 2020 06:33:53 +0300 Subject: [PATCH 059/142] Increase reduction for captures. The idea behind this patch is that if static eval is really bad so capturing of current piece on spot will still produce a position with an eval much lower than alpha then our best chance is to create some kind of king attack. So captures without check are mostly worse than captures with check and can be reduced more. passed STC https://tests.stockfishchess.org/tests/view/5e8514b44411759d9d098543 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 46196 W: 9039 L: 8781 D: 28376 Ptnml(0-2): 750, 5412, 10628, 5446, 862 passed LTC https://tests.stockfishchess.org/tests/view/5e8530134411759d9d09854c LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 23462 W: 3228 L: 2988 D: 17246 Ptnml(0-2): 186, 2125, 6849, 2405, 166 close https://github.com/official-stockfish/Stockfish/pull/2612 bench 4742598 --- src/search.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ad5b364d..eb30d9fa 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1189,10 +1189,17 @@ moves_loop: // When in check, search starts from here // Decrease/increase reduction for moves with a good/bad history (~30 Elo) r -= ss->statScore / 16434; } + else + { + // Increase reduction for captures/promotions if late move and at low depth + if (depth < 8 && moveCount > 2) + r++; - // Increase reduction for captures/promotions if late move and at low depth - else if (depth < 8 && moveCount > 2) - r++; + // Unless giving check, this capture is likely bad + if ( !givesCheck + && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 200 * depth <= alpha) + r++; + } Depth d = Utility::clamp(newDepth - r, 1, newDepth); From 3cb1c6c3c6206c3c2a0d78ce1cb9820256efc96e Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 31 Mar 2020 15:08:55 -0600 Subject: [PATCH 060/142] remove KNPK endgame code In more than 100k local KNPK games, there is no discernible difference between master and master with this endgame removed: master:42971, patch:42973, draws: 3969. Removal does not seem to regress in normal games. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 46390 W: 8998 L: 8884 D: 28508 Ptnml(0-2): 707, 5274, 11163, 5300, 751 https://tests.stockfishchess.org/tests/view/5e83b18ee42a5c3b3ca2ef02 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 44768 W: 5863 L: 5814 D: 33091 Ptnml(0-2): 251, 3918, 14028, 3905, 282 https://tests.stockfishchess.org/tests/view/5e84a82a4411759d9d0984f4 In tests with a book of endgames that can convert into KNPK, no significant difference can be seen either ``` TC 1.0+0.01 Score of patch vs master: 6131 - 6188 - 27681 [0.499] 40000 Elo difference: -0.5 +/- 1.9, LOS: 30.4 %, DrawRatio: 69.2 % TC 2.0+0.02 Score of patch vs master: 5740 - 5741 - 28519 [0.500] 40000 Elo difference: -0.0 +/- 1.8, LOS: 49.6 %, DrawRatio: 71.3 % `` closes https://github.com/official-stockfish/Stockfish/pull/2611 Bench 4512059 --- src/endgame.cpp | 20 -------------------- src/endgame.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 1a5959e5..e232da62 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -79,7 +79,6 @@ namespace Endgames { add("KQKR"); add("KNNKP"); - add("KNPK"); add("KRPKR"); add("KRPKB"); add("KBPKB"); @@ -713,25 +712,6 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// KNP vs K. There is a single rule: if the pawn is a rook pawn on the 7th rank -/// and the defending king prevents the pawn from advancing, the position is drawn. -template<> -ScaleFactor Endgame::operator()(const Position& pos) const { - - assert(verify_material(pos, strongSide, KnightValueMg, 1)); - assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - - // Assume strongSide is white and the pawn is on files A-D - Square pawnSq = normalize(pos, strongSide, pos.square(strongSide)); - Square weakKingSq = normalize(pos, strongSide, pos.square(weakSide)); - - if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1) - return SCALE_FACTOR_DRAW; - - return SCALE_FACTOR_NONE; -} - - /// KP vs KP. This is done by removing the weakest side's pawn and probing the /// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably /// has at least a draw with the pawn as well. The exception is when the stronger diff --git a/src/endgame.h b/src/endgame.h index 49ebb603..fd1aba2d 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -57,7 +57,6 @@ enum EndgameCode { KBPKB, // KBP vs KB KBPPKB, // KBPP vs KB KBPKN, // KBP vs KN - KNPK, // KNP vs K KPKP // KP vs KP }; From fbc7a328c67092799547f93e684323e2c1a6226e Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Thu, 2 Apr 2020 23:57:15 -0400 Subject: [PATCH 061/142] Retire candidate passed pawns Before this commit, some pawns were considered "candidate" passed pawns and given half bonus. After this commit, all of these pawns are scored as passed pawns, and they do not receive less bonus. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 21806 W: 4320 L: 4158 D: 13328 Ptnml(0-2): 367, 2526, 5001, 2596, 413 https://tests.stockfishchess.org/tests/view/5e86b4724411759d9d098639 LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 12590 W: 1734 L: 1617 D: 9239 Ptnml(0-2): 96, 1187, 3645, 1238, 129 https://tests.stockfishchess.org/tests/view/5e86d2874411759d9d098640 This PR and commit are dedicated to our colleague Stefan Geschwentner (@locutus2), one of the most respected and accomplished members of the Stockfish developer community. Stockfish is a volunteer project and has always thrived because of Stefan's talent, insight, generosity, and dedication. Welcome back, Stefan! closes https://github.com/official-stockfish/Stockfish/pull/2613 Bench: 4831963 --- src/evaluate.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 57491f34..f4a5d486 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -638,11 +638,6 @@ namespace { } } // r > RANK_3 - // Scale down bonus for candidate passers which need more than one - // pawn push to become passed. - if (!pos.pawn_passed(Us, s + Up)) - bonus = bonus / 2; - score += bonus - PassedFile * edge_distance(file_of(s)); } From 85bcf4741e271d9b205ac335f7056ec65a2a6ab7 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 4 Apr 2020 18:06:13 +0300 Subject: [PATCH 062/142] Further increase reductions with increasing number of threads This patch doubles the reduction increase with thread count. passed STC https://tests.stockfishchess.org/tests/view/5e874f5a4411759d9d098696 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 9162 W: 1558 L: 1385 D: 6219 Ptnml(0-2): 90, 958, 2343, 1069, 121 passed LTC https://tests.stockfishchess.org/tests/view/5e8762804411759d9d09869f LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 79364 W: 9541 L: 9159 D: 60664 Ptnml(0-2): 462, 6880, 24661, 7172, 507 closes https://github.com/official-stockfish/Stockfish/pull/2615 bench 4831963 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index eb30d9fa..cfda94b8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -194,7 +194,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((24.8 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((24.8 + std::log(Threads.size())) * std::log(i)); } From 195a4fec6d6bd1f9e43f5b3e83a3dcf57dc73744 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 7 Apr 2020 16:53:24 +0300 Subject: [PATCH 063/142] Introduce capture history pruning This patch introduces a heuristic that is similar to countermove based pruning but for captures - capture history pruning. The idea is that we can (almost) safely prune really late captures with negative history if they don't give check so will most likely not produce some king-attacking tactic. passed STC https://tests.stockfishchess.org/tests/view/5e8c60d40ffd2be7f15e5470 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 23748 W: 4758 L: 4529 D: 14461 Ptnml(0-2): 421, 2712, 5400, 2899, 442 passed LTC https://tests.stockfishchess.org/tests/view/5e8c72bf0ffd2be7f15e547f LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 17330 W: 2415 L: 2190 D: 12725 Ptnml(0-2): 126, 1561, 5107, 1704, 167 closes https://github.com/official-stockfish/Stockfish/pull/2618 bench 4417023 --- src/search.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cfda94b8..dba8857e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -789,6 +789,8 @@ namespace { } } + CapturePieceToHistory& captureHistory = thisThread->captureHistory; + // Step 6. Static evaluation of the position if (inCheck) { @@ -899,7 +901,7 @@ namespace { && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); - MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); + MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; while ( (move = mp.next_move()) != MOVE_NONE @@ -954,7 +956,7 @@ moves_loop: // When in check, search starts from here MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->lowPlyHistory, - &thisThread->captureHistory, + &captureHistory, contHist, countermove, ss->killers, @@ -1010,12 +1012,12 @@ moves_loop: // When in check, search starts from here // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold moveCountPruning = moveCount >= futility_move_count(improving, depth); + // Reduced depth of the next LMR search + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); + if ( !captureOrPromotion && !givesCheck) { - // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); - // Countermoves based pruning (~20 Elo) if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold @@ -1035,8 +1037,16 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - continue; + else + { + if ( !givesCheck + && lmrDepth < 1 + && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) + continue; + + if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) + continue; + } } // Step 14. Extensions (~75 Elo) From f83cb95740de019db6ff5567d6f84f218b18cd9e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 12 Apr 2020 20:30:08 +0200 Subject: [PATCH 064/142] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2606 No functional change --- src/bitboard.cpp | 29 +++++++++-------------------- src/bitboard.h | 20 ++++++++++++++------ src/evaluate.cpp | 2 +- src/movegen.cpp | 10 ++-------- src/pawns.cpp | 2 +- src/psqt.cpp | 2 +- src/search.cpp | 25 ++++++++++++++----------- src/syzygy/tbprobe.cpp | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- src/types.h | 6 +++--- 11 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index bb03dfeb..69bbc77b 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -84,23 +84,16 @@ void Bitboards::init() { init_magics(RookTable, RookMagics, RookDirections); init_magics(BishopTable, BishopMagics, BishopDirections); - // Helper returning the target bitboard of a step from a square - auto landing_square_bb = [&](Square s, int step) - { - Square to = Square(s + step); - return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); - }; - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) { PawnAttacks[WHITE][s1] = pawn_attacks_bb(square_bb(s1)); PawnAttacks[BLACK][s1] = pawn_attacks_bb(square_bb(s1)); for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) - PseudoAttacks[KING][s1] |= landing_square_bb(s1, step); + PseudoAttacks[KING][s1] |= safe_destination(s1, step); for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) - PseudoAttacks[KNIGHT][s1] |= landing_square_bb(s1, step); + PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step); PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); @@ -117,20 +110,16 @@ namespace { Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) { - Bitboard attack = 0; + Bitboard attacks = 0; for (int i = 0; i < 4; ++i) - for (Square s = sq + directions[i]; - is_ok(s) && distance(s, s - directions[i]) == 1; - s += directions[i]) - { - attack |= s; + { + Square s = sq; + while(safe_destination(s, directions[i]) && !(occupied & s)) + attacks |= (s += directions[i]); + } - if (occupied & s) - break; - } - - return attack; + return attacks; } diff --git a/src/bitboard.h b/src/bitboard.h index 529e3dfe..9252c3dc 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -106,7 +106,7 @@ extern Magic RookMagics[SQUARE_NB]; extern Magic BishopMagics[SQUARE_NB]; inline Bitboard square_bb(Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(is_ok(s)); return SquareBB[s]; } @@ -123,7 +123,7 @@ inline Bitboard operator&(Square s, Bitboard b) { return b & s; } inline Bitboard operator|(Square s, Bitboard b) { return b | s; } inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; } -inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | square_bb(s2); } +inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | s2; } constexpr bool more_than_one(Bitboard b) { return b & (b - 1); @@ -209,8 +209,8 @@ inline Bitboard between_bb(Square s1, Square s2) { /// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2. inline Bitboard forward_ranks_bb(Color c, Square s) { - return c == WHITE ? ~Rank1BB << 8 * (rank_of(s) - RANK_1) - : ~Rank8BB >> 8 * (RANK_8 - rank_of(s)); + return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s) + : ~Rank8BB >> 8 * relative_rank(BLACK, s); } @@ -255,8 +255,16 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } -inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); } -inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } +inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); } +inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } + +/// Return the target square bitboard if we do not step off the board, empty otherwise + +inline Bitboard safe_destination(Square s, int step) +{ + Square to = Square(s + step); + return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); +} /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f4a5d486..a2e5ef7b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -746,7 +746,7 @@ namespace { { if ( pos.opposite_bishops() && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 22 ; + sf = 22; else sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); diff --git a/src/movegen.cpp b/src/movegen.cpp index 804ef87b..a3abcde8 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -277,16 +277,13 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { assert(!pos.checkers()); Color us = pos.side_to_move(); - Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us); + Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN); while (dc) { Square from = pop_lsb(&dc); PieceType pt = type_of(pos.piece_on(from)); - if (pt == PAWN) - continue; // Will be generated together with direct checks - Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces(); if (pt == KING) @@ -317,10 +314,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // the king evasions in order to skip known illegal moves, which avoids any // useless legality checks later on. while (sliders) - { - Square checksq = pop_lsb(&sliders); - sliderAttacks |= LineBB[ksq][checksq] ^ checksq; - } + sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers(); // Generate evasions for king, capture and non capture moves Bitboard b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; diff --git a/src/pawns.cpp b/src/pawns.cpp index 8759631a..0017b804 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -204,7 +204,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = edge_distance(f); + File d = File(edge_distance(f)); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index d86e98e4..7fa36ac8 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -112,7 +112,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = edge_distance(file_of(s)); + File f = File(edge_distance(file_of(s))); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][flip_rank(s)] = -psq[pc][s]; diff --git a/src/search.cpp b/src/search.cpp index dba8857e..4abc6069 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -303,7 +303,7 @@ void MainThread::search() { } } - previousScore = bestThread->rootMoves[0].score; + bestPreviousScore = bestThread->rootMoves[0].score; // Send again PV info if we have a new best thread if (bestThread != this) @@ -349,12 +349,12 @@ void Thread::search() { if (mainThread) { - if (mainThread->previousScore == VALUE_INFINITE) + if (mainThread->bestPreviousScore == VALUE_INFINITE) for (int i=0; i<4; ++i) mainThread->iterValue[i] = VALUE_ZERO; else for (int i=0; i<4; ++i) - mainThread->iterValue[i] = mainThread->previousScore; + mainThread->iterValue[i] = mainThread->bestPreviousScore; } size_t multiPV = Options["MultiPV"]; @@ -433,13 +433,13 @@ void Thread::search() { // Reset aspiration window starting size if (rootDepth >= 4) { - Value previousScore = rootMoves[pvIdx].previousScore; + Value prev = rootMoves[pvIdx].previousScore; delta = Value(21); - alpha = std::max(previousScore - delta,-VALUE_INFINITE); - beta = std::min(previousScore + delta, VALUE_INFINITE); + alpha = std::max(prev - delta,-VALUE_INFINITE); + beta = std::min(prev + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + (102 - ct / 2) * previousScore / (abs(previousScore) + 157); + int dct = ct + (102 - ct / 2) * prev / (abs(prev) + 157); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -537,7 +537,7 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue) + double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); @@ -626,7 +626,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, formerPv, inCheck, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -696,6 +696,7 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + formerPv = ttPv && !PvNode; if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove)) thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); @@ -900,7 +901,8 @@ namespace { && depth >= 5 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); + Value raisedBeta = beta + 189 - 45 * improving; + assert(raisedBeta < VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; @@ -965,7 +967,6 @@ moves_loop: // When in check, search starts from here value = bestValue; singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - bool formerPv = ttPv && !PvNode; // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); @@ -1039,11 +1040,13 @@ moves_loop: // When in check, search starts from here } else { + // Capture history based pruning when the move doesn't give check if ( !givesCheck && lmrDepth < 1 && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) continue; + // See based pruning if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) continue; } diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 34e4331d..f1fd695c 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -705,7 +705,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp)); - tbFile = edge_distance(file_of(squares[0])); + tbFile = File(edge_distance(file_of(squares[0]))); } // DTZ tables are one-sided, i.e. they store positions only for white to diff --git a/src/thread.cpp b/src/thread.cpp index b5cb87d9..88331f06 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -166,7 +166,7 @@ void ThreadPool::clear() { th->clear(); main()->callsCnt = 0; - main()->previousScore = VALUE_INFINITE; + main()->bestPreviousScore = VALUE_INFINITE; main()->previousTimeReduction = 1.0; } diff --git a/src/thread.h b/src/thread.h index 41d2b8f6..79be197b 100644 --- a/src/thread.h +++ b/src/thread.h @@ -88,7 +88,7 @@ struct MainThread : public Thread { void check_time(); double previousTimeReduction; - Value previousScore; + Value bestPreviousScore; Value iterValue[4]; int callsCnt; bool stopOnPonderhit; diff --git a/src/types.h b/src/types.h index bfcd3f23..cd8d2320 100644 --- a/src/types.h +++ b/src/types.h @@ -177,9 +177,9 @@ enum Value : int { VALUE_NONE = 32002, VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, - VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY, VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, - VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, + VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, KnightValueMg = 781, KnightValueEg = 854, @@ -351,7 +351,7 @@ inline Score operator*(Score s, int i) { /// Multiplication of a Score by a boolean inline Score operator*(Score s, bool b) { - return Score(int(s) * int(b)); + return b ? s : SCORE_ZERO; } constexpr Color operator~(Color c) { From 6596f0eac0c1d25a12bfd923907bfc78beedbc90 Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 3 Apr 2020 15:10:50 -0600 Subject: [PATCH 065/142] Always remember the ttMove In master, if the received ttMove meets the prescribed conditions in the various MovePicker constructors, it is returned as the first move, otherwise we set it to MOVE_NONE. If set to MOVE_NONE, we no longer track what the ttMove was, and it will might be returned later in a list of generated moves. This may be a waste. With this patch, if the ttMove fails to meet the prescribed conditions, we simply skip the TT stages, but still store the move and make sure it's never returned. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 66424 W: 12903 L: 12806 D: 40715 Ptnml(0-2): 1195, 7730, 15230, 7897, 1160 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 45682 W: 5989 L: 5926 D: 33767 Ptnml(0-2): 329, 4361, 13443, 4334, 374 closes https://github.com/official-stockfish/Stockfish/pull/2616 Bench 4928928 --- src/movepick.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 580c6d75..b1e10587 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -59,42 +59,36 @@ namespace { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { + ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); - stage = pos.checkers() ? EVASION_TT : MAIN_TT; - ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + 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), recaptureSquare(rs), depth(d) { + : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { assert(d <= 0); - stage = pos.checkers() ? EVASION_TT : QSEARCH_TT; - ttMove = ttm - && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) - && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + + !(ttm && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) + && 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), threshold(th) { + : pos(p), captureHistory(cph), ttMove(ttm), threshold(th) { assert(!pos.checkers()); - stage = PROBCUT_TT; - ttMove = ttm - && pos.capture(ttm) - && pos.pseudo_legal(ttm) - && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + stage = PROBCUT_TT + !(ttm && pos.capture(ttm) + && pos.pseudo_legal(ttm) + && pos.see_ge(ttm, threshold)); } /// MovePicker::score() assigns a numerical value to each move in a list, used From 2c5f0efa1350ea19d32c599ddd6b9350f1d216ff Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 10 Apr 2020 21:53:00 +0200 Subject: [PATCH 066/142] Extend irreversible moves if these are ttMoves and played in positions with a high value of the rule50 counter. The unusual extension of 2 is safe in this context as awarding it will reset the rule50 counter, making sure it is awarded very rarely in a search path. This patch partially addresses https://github.com/official-stockfish/Stockfish/issues/2620 as it should make it less likely to play a move that resets the counter, but that is worse than alternative moves after a slightly deeper search. passed STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 71658 W: 13840 L: 13560 D: 44258 Ptnml(0-2): 1058, 7921, 17643, 8097, 1110 https://tests.stockfishchess.org/tests/view/5e90d0f6754c3424c4cf9f41 passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 85082 W: 11069 L: 10680 D: 63333 Ptnml(0-2): 459, 6982, 27259, 7393, 448 https://tests.stockfishchess.org/tests/view/5e917470af0a0143109dc341 closes https://github.com/official-stockfish/Stockfish/pull/2623 Bench: 4432822 --- src/search.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 4abc6069..4073f21d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1110,6 +1110,12 @@ moves_loop: // When in check, search starts from here if (type_of(move) == CASTLING) extension = 1; + // Late irreversible move extension + if ( move == ttMove + && pos.rule50_count() > 80 + && (captureOrPromotion || type_of(movedPiece) == PAWN)) + extension = 2; + // Add extension to new depth newDepth += extension; From d7a2d5a44588676abf9b49e35a5a567fd57ec3b0 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Sat, 11 Apr 2020 17:28:45 +0200 Subject: [PATCH 067/142] Remove candidate passers w/o feasible lever +-------+ | o . . | o their pawns | x . . | x our pawns | . x . | <- Can sacrifice to create passer? +-------+ yes 1 2 3 4 5 +-------+ +-------+ +-------+ +-------+ +-------+ | o . . | | o r . | | o r . | | o . b | | o . b | lowercase: theirs | x b . | | x . . | | x . R | | x . R | | x . . | uppercase: ours | . x . | | . x . | | . x . | | . x . | | . x B | +-------+ +-------+ +-------+ +-------+ +-------+ no no yes no yes The value of our top pawn depends on our ability to advance our bottom pawn, levering their blocker. Previously, this pawn configuration was always scored as passer (although a blocked one). Add requirements for the square s above our (possibly) sacrificed pawn: - s must not be occupied by them (1). - If they attack s (2), we must attack s (3). - If they attack s with a minor (4), we must attack s with a minor (5). The attack from their blocker is ignored because it is inherent in the structure; we are ok with sacrificing our bottom pawn. LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 37030 W: 4962 L: 4682 D: 27386 Ptnml(0-2): 266, 3445, 10863, 3625, 316 https://tests.stockfishchess.org/tests/view/5e92a2b4be6ede5b954bf239 STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 40874 W: 8066 L: 7813 D: 24995 Ptnml(0-2): 706, 4753, 9324, 4890, 764 https://tests.stockfishchess.org/tests/view/5e922199af0a0143109dc90e closes https://github.com/official-stockfish/Stockfish/pull/2624 Bench: 4828294 --- src/evaluate.cpp | 19 ++++++++++++++++++- src/pawns.cpp | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a2e5ef7b..2698c813 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -578,16 +578,33 @@ namespace { constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; auto king_proximity = [&](Color c, Square s) { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, unsafeSquares; + Bitboard b, bb, squaresToQueen, unsafeSquares, candidatePassers, leverable; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); + candidatePassers = b & shift(pos.pieces(Them, PAWN)); + if (candidatePassers) + { + // Can we lever the blocker of a candidate passer? + leverable = shift(pos.pieces(Us, PAWN)) + & ~pos.pieces(Them) + & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]) + & (~(attackedBy[Them][KNIGHT] | attackedBy[Them][BISHOP]) + | (attackedBy[Us ][KNIGHT] | attackedBy[Us ][BISHOP])); + + // Remove candidate otherwise + b &= ~candidatePassers + | shift(leverable) + | shift(leverable); + } + while (b) { Square s = pop_lsb(&b); diff --git a/src/pawns.cpp b/src/pawns.cpp index 0017b804..63bc596f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -118,6 +118,7 @@ namespace { // (a) there is no stoppers except some levers // (b) the only stoppers are the leverPush, but we outnumber them // (c) there is only one front stopper which can be levered. + // (Refined in Evaluation::passed) passed = !(stoppers ^ lever) || ( !(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush)) From db59696aaf91641ade911c4a6ca393a1691d78a8 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 13 Apr 2020 03:48:52 +0300 Subject: [PATCH 068/142] Scale up space weight with number of blocked pawns This idea is loosely based on stockfish losses in closed positions in different tournaments. Space weight symmetrically increases for both sides the more blocked position is. passed STC https://tests.stockfishchess.org/tests/view/5e919eefaf0a0143109dc8ce LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 16994 W: 3389 L: 3172 D: 10433 Ptnml(0-2): 277, 1931, 3918, 2040, 331 passed LTC https://tests.stockfishchess.org/tests/view/5e91d04faf0a0143109dc8ea LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 133386 W: 17316 L: 16763 D: 99307 Ptnml(0-2): 945, 12407, 39524, 12784, 1033 closes https://github.com/official-stockfish/Stockfish/pull/2626 Bench: 4966867 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 3 +++ src/pawns.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2698c813..cd535d88 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -695,7 +695,7 @@ namespace { behind |= shift(behind); int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); - int weight = pos.count(Us) - 1; + int weight = pos.count(Us) - 2 + pe->blocked_count() / 2; Score score = make_score(bonus * weight * weight / 16, 0); if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index 63bc596f..7c4eda0f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -86,6 +86,7 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); + e->blockedCount[Us] = 0; // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -105,6 +106,8 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); + e->blockedCount[Us] += bool(blocked); + // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. backward = !(neighbours & forward_ranks_bb(Them, s + Up)) diff --git a/src/pawns.h b/src/pawns.h index bd17618f..41a88c6f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -38,6 +38,7 @@ struct Entry { Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); } + int blocked_count() const { return blockedCount[WHITE] + blockedCount[BLACK]; } template Score king_safety(const Position& pos) { @@ -59,6 +60,7 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; + int blockedCount[COLOR_NB]; }; typedef HashTable Table; From de9fc53af57d1620bb913c357630e724c7ea186b Mon Sep 17 00:00:00 2001 From: silversolver1 <61594747+silversolver1@users.noreply.github.com> Date: Sun, 12 Apr 2020 22:23:04 -0500 Subject: [PATCH 069/142] Removes evasionPrunable STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 25656 W: 4979 L: 4826 D: 15851 Ptnml(0-2): 414, 2971, 5964, 3006, 473 https://tests.stockfishchess.org/tests/view/5e93dbd72cb65b3059c33819 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 43732 W: 5656 L: 5593 D: 32483 Ptnml(0-2): 324, 4072, 13009, 4139, 322 https://tests.stockfishchess.org/tests/view/5e93e37c2cb65b3059c33825 closes https://github.com/official-stockfish/Stockfish/pull/2627 Bench: 4702195 --- src/search.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4073f21d..76011840 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1398,7 +1398,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion, evasionPrunable; + bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion; int moveCount; if (PvNode) @@ -1527,14 +1527,8 @@ moves_loop: // When in check, search starts from here } } - // Detect non-capture evasions that are candidates to be pruned - evasionPrunable = inCheck - && (depth != 0 || moveCount > 2) - && bestValue > VALUE_TB_LOSS_IN_MAX_PLY - && !pos.capture(move); - // Don't search moves with negative SEE values - if ( (!inCheck || evasionPrunable) && !pos.see_ge(move)) + if ( !inCheck && !pos.see_ge(move)) continue; // Speculative prefetch as early as possible From 5c58f6712667076babe9ebaac1689436721c42be Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Mon, 13 Apr 2020 23:01:38 +0200 Subject: [PATCH 070/142] less bonus for blocked connected pawn Use less bonus for blocked connected pawns so closed positions are less worth. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 60004 W: 11904 L: 11619 D: 36481 Ptnml(0-2): 1066, 7083, 13535, 7136, 1182 https://tests.stockfishchess.org/tests/view/5e941a8063d105aebbab23e3 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 36606 W: 4831 L: 4556 D: 27219 Ptnml(0-2): 252, 3353, 10872, 3520, 306 https://tests.stockfishchess.org/tests/view/5e9444b963d105aebbab2427 closes https://github.com/official-stockfish/Stockfish/pull/2629 Bench: 4961260 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7c4eda0f..a2063a8f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -138,7 +138,7 @@ namespace { // Score this pawn if (support | phalanx) { - int v = Connected[r] * (2 + bool(phalanx) - bool(opposed)) + int v = Connected[r] * (4 + 2 * bool(phalanx) - 2 * bool(opposed) - bool(blocked)) / 2 + 21 * popcount(support); score += make_score(v, v * (r - 2) / 4); From ca4e399ea6d88f8f71c8fd692566223496b10f78 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 15 Apr 2020 04:13:50 +0300 Subject: [PATCH 071/142] Space bonus and number of blocked pawns This patch refines the recently introduced interaction between the space bonus and the number of blocked pawns in a position. * pawns count as blocked also if their push square is attacked by 2 enemy pawns; * overall dependence is stronger as well as offset; * bonus increase is capped at 9 blocked pawns in position; passed STC https://tests.stockfishchess.org/tests/view/5e94560663d105aebbab243d LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 29500 W: 5842 L: 5603 D: 18055 Ptnml(0-2): 504, 3443, 6677, 3562, 564 passed LTC https://tests.stockfishchess.org/tests/view/5e95b383c2aaa99f75d1a14d LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 63504 W: 8329 L: 7974 D: 47201 Ptnml(0-2): 492, 5848, 18720, 6197, 495 closes https://github.com/official-stockfish/Stockfish/pull/2631 bench 4956028 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cd535d88..8feedfeb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -695,7 +695,7 @@ namespace { behind |= shift(behind); int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); - int weight = pos.count(Us) - 2 + pe->blocked_count() / 2; + int weight = pos.count(Us) - 3 + std::min(pe->blocked_count(), 9); Score score = make_score(bonus * weight * weight / 16, 0); if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index a2063a8f..75e6ad7a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -106,7 +106,7 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount[Us] += bool(blocked); + e->blockedCount[Us] += blocked || more_than_one(leverPush); // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. From 0e51ff1074d5a66495a21990bd1826a8d06447e8 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 15 Apr 2020 18:22:02 +0300 Subject: [PATCH 072/142] Don't attempt probcut if ttMove is not good enough. This idea is loosely based on xoroshiro idea about raisedBeta and ttmoves. If our ttmove have low enough ttvalue and is deep enough (deeper than our probcut depth) it makes little sense to try probcut moves, since the ttMove already more or less failed to produce one according to transposition table. passed STC https://tests.stockfishchess.org/tests/view/5e9673ddc2718dee3c822920 LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 72148 W: 14038 L: 13741 D: 44369 Ptnml(0-2): 1274, 8326, 16615, 8547, 1312 passed LTC https://tests.stockfishchess.org/tests/view/5e96b378c2718dee3c8229bf LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 89054 W: 11418 L: 10996 D: 66640 Ptnml(0-2): 623, 8113, 26643, 8515, 633 closes https://github.com/official-stockfish/Stockfish/pull/2632 bench 4952731 --- src/search.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 76011840..dae1e23c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -906,8 +906,12 @@ namespace { MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; - while ( (move = mp.next_move()) != MOVE_NONE - && probCutCount < 2 + 2 * cutNode) + while ( (move = mp.next_move()) != MOVE_NONE + && probCutCount < 2 + 2 * cutNode + && !( move == ttMove + && (tte->bound() & BOUND_LOWER) + && tte->depth() >= depth - 4 + && ttValue < raisedBeta)) if (move != excludedMove && pos.legal(move)) { assert(pos.capture_or_promotion(move)); From d87adcc0062fa9707ba2b0b6ce3369a4ab391b6d Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 16 Apr 2020 01:33:48 +0300 Subject: [PATCH 073/142] Queen and Rook Tuning Tuning for multiple parameters for Queen and Rook. passed STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 62790 W: 12033 L: 11754 D: 39003 Ptnml(0-2): 1058, 7186, 14666, 7389, 1096 https://tests.stockfishchess.org/tests/view/5e978c66c9ada107a0370d87 passed LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 89780 W: 11460 L: 11036 D: 67284 Ptnml(0-2): 624, 8151, 26951, 8505, 659 https://tests.stockfishchess.org/tests/view/5e979aaec9ada107a0370d93 closes https://github.com/official-stockfish/Stockfish/pull/2634 Bench: 5111578 --- src/evaluate.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8feedfeb..7eafacf8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -82,7 +82,7 @@ namespace { // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 1080; + constexpr int RookSafeCheck = 1078; constexpr int BishopSafeCheck = 635; constexpr int KnightSafeCheck = 790; @@ -96,19 +96,19 @@ namespace { { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, - { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rook - S( 9,112), S( 16,118), S( 30,132), S( 29,142), S( 32,155), S( 38,165), - S( 46,166), S( 48,169), S( 58,171) }, - { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queen - S( 28, 61), S( 41, 73), S( 43, 79), S( 48, 92), S( 56, 94), S( 60,104), - S( 60,113), S( 66,120), S( 67,123), S( 70,126), S( 71,133), S( 73,136), - S( 79,140), S( 88,143), S( 88,148), S( 99,166), S(102,170), S(102,175), - S(106,184), S(109,191), S(113,206), S(116,212) } + { S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook + S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164), + S( 57,168), S( 57,169), S( 62,172) }, + { S(-34,-36), S(-15,-21), S(-10, -1), S(-10, 22), S( 20, 41), S( 23, 56), // Queen + S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100), + S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141), + S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171), + S(110,182), S(114,182), S(114,192), S(116,219) } }; // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. - constexpr Score RookOnFile[] = { S(21, 4), S(47, 25) }; + constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are @@ -118,7 +118,7 @@ namespace { }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(2, 44), S(36, 71), S(36, 61), S(0, 38), S(51, 38) + S(0, 0), S(3, 46), S(37, 68), S(42, 60), S(0, 38), S(58, 41) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -132,21 +132,21 @@ namespace { constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); constexpr Score KingProtector = S( 7, 8); - constexpr Score KnightOnQueen = S( 16, 12); + constexpr Score KnightOnQueen = S( 16, 11); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); constexpr Score Outpost = S( 30, 21); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnQueenFile = S( 7, 6); + constexpr Score RookOnQueenFile = S( 5, 9); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); - constexpr Score WeakQueen = S( 49, 15); - constexpr Score WeakQueenProtection = S( 14, 0); + constexpr Score TrappedRook = S( 55, 13); + constexpr Score WeakQueen = S( 51, 14); + constexpr Score WeakQueenProtection = S( 15, 0); #undef S From 6f35af7ad31d55d0f0918742b60f4e672fc43ccf Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Thu, 16 Apr 2020 03:56:43 +0200 Subject: [PATCH 074/142] Increase safe check bonus if multiple safe checks Add 50% "safe checks" bonus when there are multiple safe checks from the same piece type. LTC LLR: 2.97 (-2.94,2.94) {0.25,1.75} Total: 128184 W: 16491 L: 15954 D: 95739 Ptnml(0-2): 884, 11793, 38267, 12198, 950 https://tests.stockfishchess.org/tests/view/5e97d1b6c9ada107a0370e03 STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 19022 W: 3733 L: 3514 D: 11775 Ptnml(0-2): 338, 2103, 4414, 2314, 342 https://tests.stockfishchess.org/tests/view/5e97c377c9ada107a0370ddf closes https://github.com/official-stockfish/Stockfish/pull/2636 Bench: 5057329 --- src/evaluate.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7eafacf8..0b1956f1 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -398,9 +398,9 @@ namespace { // Enemy rooks checks rookChecks = b1 & safe & attackedBy[Them][ROOK]; - if (rookChecks) - kingDanger += RookSafeCheck; + kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 3/2 + : RookSafeCheck; else unsafeChecks |= b1 & attackedBy[Them][ROOK]; @@ -411,9 +411,9 @@ namespace { & safe & ~attackedBy[Us][QUEEN] & ~rookChecks; - if (queenChecks) - kingDanger += QueenSafeCheck; + kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2 + : QueenSafeCheck; // Enemy bishops checks: we count them only if they are from squares from // which we can't give a queen check, because queen checks are more valuable. @@ -421,17 +421,17 @@ namespace { & attackedBy[Them][BISHOP] & safe & ~queenChecks; - if (bishopChecks) - kingDanger += BishopSafeCheck; + kingDanger += more_than_one(bishopChecks) ? BishopSafeCheck * 3/2 + : BishopSafeCheck; else unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - if (knightChecks & safe) - kingDanger += KnightSafeCheck; + kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 3/2 + : KnightSafeCheck; else unsafeChecks |= knightChecks; From ecac132bca23c6dfcc697cc3cd069939bc168ed4 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 16 Apr 2020 18:10:44 +0100 Subject: [PATCH 075/142] Scale factor in opposite-color bishop endings This change varies the scale factor with the total number of pieces and pawns on the strongSide. STC : LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 150920 W: 28828 L: 28422 D: 93670 +0.65 Elo Ptnml(0-2): 2507, 17548, 35030, 17782, 2593 https://tests.stockfishchess.org/tests/view/5e983eb2c00499c5410f4951 LTC : LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 69238 W: 8810 L: 8446 D: 51982 +1.58 Elo Ptnml(0-2): 451, 6276, 20879, 6484, 529 https://tests.stockfishchess.org/tests/view/5e985b27c00499c5410f4987 closes https://github.com/official-stockfish/Stockfish/pull/2637 Bench 4821332 --- src/evaluate.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0b1956f1..cbcebd04 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -761,11 +761,16 @@ namespace { // If scale is not already specific, scale down the endgame via general heuristics if (sf == SCALE_FACTOR_NORMAL) { - if ( pos.opposite_bishops() - && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 22; + if (pos.opposite_bishops()) + { + if ( pos.non_pawn_material(WHITE) == BishopValueMg + && pos.non_pawn_material(BLACK) == BishopValueMg) + sf = 22; + else + sf = 22 + 3 * pos.count(strongSide); + } else - sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::min(sf, 36 + 7 * pos.count(strongSide)); sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } From 345b2d153a8092cff93ad660c9d107cd66fda43b Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 15 Apr 2020 23:34:18 +0200 Subject: [PATCH 076/142] Remove one condition in probcut TTmove skipping the removed condition appears illogical and is not needed. passed STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 80418 W: 15217 L: 15144 D: 50057 Ptnml(0-2): 1341, 9399, 18679, 9426, 1364 https://tests.stockfishchess.org/tests/view/5e977eb5c9ada107a0370d6b passed LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 49878 W: 6299 L: 6247 D: 37332 Ptnml(0-2): 327, 4677, 14897, 4693, 345 https://tests.stockfishchess.org/tests/view/5e97e07dc9ada107a0370e53 closes https://github.com/official-stockfish/Stockfish/pull/2638 Bench: 4958027 --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index dae1e23c..fd690dcd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -909,7 +909,6 @@ namespace { while ( (move = mp.next_move()) != MOVE_NONE && probCutCount < 2 + 2 * cutNode && !( move == ttMove - && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 4 && ttValue < raisedBeta)) if (move != excludedMove && pos.legal(move)) From bde1506ba56ae566ac4e797e642017fe386f6425 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 16 Apr 2020 23:12:43 -0600 Subject: [PATCH 077/142] Simplify minPawnDistance This is a functional simplification which fixes an awkward numerical cliff. With master king_safety, no pawns is scored higher than pawn(s) that is/are far from the king. This may motivate SF to throw away pawns to increase king safety. With this patch, there is a consistent value for minPawnDistance where losing a pawn never increases king safety. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 45548 W: 8624 L: 8525 D: 28399 Ptnml(0-2): 592, 4937, 11587, 5096, 562 https://tests.stockfishchess.org/tests/view/5e98ced630be947a14e9ddc5 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 42084 W: 5292 L: 5242 D: 31550 Ptnml(0-2): 193, 3703, 13252, 3649, 245 https://tests.stockfishchess.org/tests/view/5e98e22e30be947a14e9de07 closes https://github.com/official-stockfish/Stockfish/pull/2639 bench 4600292 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 75e6ad7a..066146e2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -244,7 +244,7 @@ Score Entry::do_king_safety(const Position& pos) { // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); - int minPawnDist = pawns ? 8 : 0; + int minPawnDist = 6; if (pawns & PseudoAttacks[KING][ksq]) minPawnDist = 1; From 221893bf679f70098e6f751fded2fe843471c6be Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 18 Apr 2020 03:28:47 +0300 Subject: [PATCH 078/142] Apply multicut pruning more often This patch increases number of nodes where we produce multicut cutoffs. The idea is that if our ttMove failed to produce a singular extension but ttValue is greater than beta we can afford to do one more reduced search near beta excluding ttMove to see if it will produce a fail high - and if it does so produce muticut by analogy to existing logic. passed STC https://tests.stockfishchess.org/tests/view/5e9a162b5b664cdba0ce6e28 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 58238 W: 11192 L: 10917 D: 36129 Ptnml(0-2): 1007, 6704, 13442, 6939, 1027 passed LTC https://tests.stockfishchess.org/tests/view/5e9a1e845b664cdba0ce7411 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 137852 W: 17460 L: 16899 D: 103493 Ptnml(0-2): 916, 12610, 41383, 13031, 986 closes https://github.com/official-stockfish/Stockfish/pull/2640 bench 4881443 --- src/search.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index fd690dcd..a7e90a08 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1091,6 +1091,18 @@ moves_loop: // When in check, search starts from here // a soft bound. else if (singularBeta >= beta) return singularBeta; + + // If the eval of ttMove is greater than beta we try also if there is an other move that + // pushes it over beta, if so also produce a cutoff + else if (ttValue >= beta) + { + ss->excludedMove = move; + value = search(pos, ss, beta - 1, beta, (depth + 3) / 2, cutNode); + ss->excludedMove = MOVE_NONE; + + if (value >= beta) + return beta; + } } // Check extension (~2 Elo) From bb5589b829b79d7c60a820d4b1634dccbc4bbb3f Mon Sep 17 00:00:00 2001 From: pb00067 Date: Tue, 21 Apr 2020 20:55:41 +0200 Subject: [PATCH 079/142] continuation histories when in check If in check, don't write to continuation histories ss-4, ss-6. Adding inCheck to the stack was needed, and might be useful for future patches. Passed STC: https://tests.stockfishchess.org/tests/view/5e9ee24acaaff5d60a50b812 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 61774 W: 11725 L: 11449 D: 38600 Ptnml(0-2): 971, 7211, 14322, 7337, 1046 Passed LTC: https://tests.stockfishchess.org/tests/view/5e9eecb7caaff5d60a50b831 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 250822 W: 32067 L: 31179 D: 187576 Ptnml(0-2): 1745, 23126, 74824, 23928, 1788 closes https://github.com/official-stockfish/Stockfish/pull/2645 bench: 4808463 --- src/search.cpp | 40 ++++++++++++++++++++++------------------ src/search.h | 1 + 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index a7e90a08..a3d4a329 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -626,14 +626,14 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, formerPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, formerPv, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); - inCheck = pos.checkers(); + ss->inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); moveCount = captureCount = quietCount = ss->moveCount = 0; @@ -654,7 +654,7 @@ namespace { if ( Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score @@ -793,7 +793,7 @@ namespace { CapturePieceToHistory& captureHistory = thisThread->captureHistory; // Step 6. Static evaluation of the position - if (inCheck) + if (ss->inCheck) { ss->staticEval = eval = VALUE_NONE; improving = false; @@ -920,7 +920,7 @@ namespace { probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [pos.moved_piece(move)] [to_sq(move)]; @@ -1030,7 +1030,7 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 - && !inCheck + && !ss->inCheck && ss->staticEval + 235 + 172 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] @@ -1146,7 +1146,7 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [movedPiece] [to_sq(move)]; @@ -1365,11 +1365,11 @@ moves_loop: // When in check, search starts from here // must be a mate or a stalemate. If we are in a singular extension search then // return a fail low score. - assert(moveCount || !inCheck || excludedMove || !MoveList(pos).size()); + assert(moveCount || !ss->inCheck || excludedMove || !MoveList(pos).size()); if (!moveCount) bestValue = excludedMove ? alpha - : inCheck ? mated_in(ss->ply) : VALUE_DRAW; + : ss->inCheck ? mated_in(ss->ply) : VALUE_DRAW; else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, @@ -1413,7 +1413,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion; + bool ttHit, pvHit, givesCheck, captureOrPromotion; int moveCount; if (PvNode) @@ -1426,20 +1426,20 @@ moves_loop: // When in check, search starts from here Thread* thisThread = pos.this_thread(); (ss+1)->ply = ss->ply + 1; bestMove = MOVE_NONE; - inCheck = pos.checkers(); + ss->inCheck = pos.checkers(); moveCount = 0; // Check for an immediate draw or maximum ply reached if ( pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : VALUE_DRAW; + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : VALUE_DRAW; assert(0 <= ss->ply && ss->ply < MAX_PLY); // Decide whether or not to include checks: this fixes also the type of // TT entry depth that we are going to use. Note that in qsearch we use // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. - ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS + ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS; // Transposition table lookup posKey = pos.key(); @@ -1457,7 +1457,7 @@ moves_loop: // When in check, search starts from here return ttValue; // Evaluate the position statically - if (inCheck) + if (ss->inCheck) { ss->staticEval = VALUE_NONE; bestValue = futilityBase = -VALUE_INFINITE; @@ -1520,7 +1520,7 @@ moves_loop: // When in check, search starts from here moveCount++; // Futility pruning - if ( !inCheck + if ( !ss->inCheck && !givesCheck && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) @@ -1543,7 +1543,7 @@ moves_loop: // When in check, search starts from here } // Don't search moves with negative SEE values - if ( !inCheck && !pos.see_ge(move)) + if ( !ss->inCheck && !pos.see_ge(move)) continue; // Speculative prefetch as early as possible @@ -1557,7 +1557,7 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [pos.moved_piece(move)] [to_sq(move)]; @@ -1591,7 +1591,7 @@ moves_loop: // When in check, search starts from here // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. - if (inCheck && bestValue == -VALUE_INFINITE) + if (ss->inCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, @@ -1710,8 +1710,12 @@ moves_loop: // When in check, search starts from here void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { for (int i : {1, 2, 4, 6}) + { + if (ss->inCheck && i > 2) + break; if (is_ok((ss-i)->currentMove)) (*(ss-i)->continuationHistory)[pc][to] << bonus; + } } diff --git a/src/search.h b/src/search.h index a900d094..1653ce92 100644 --- a/src/search.h +++ b/src/search.h @@ -49,6 +49,7 @@ struct Stack { Value staticEval; int statScore; int moveCount; + bool inCheck; }; From 4776dc0e126ed311f10f34bfa058a6c86e9d3ef1 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 29 Apr 2020 02:40:16 +0300 Subject: [PATCH 080/142] Introduce futility pruning for captures The idea is somewhat similar to futility pruning for quiet moves - if a late enough capture doesn't give check and the static eval is much lower than alpha we can almost safely assume that this capture wouldn't be a good move. passed STC https://tests.stockfishchess.org/tests/view/5ea8544b53a4548a0348ee5b LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 236040 W: 44420 L: 43894 D: 147726 Ptnml(0-2): 3830, 27202, 55496, 27596, 3896 passed LTC https://tests.stockfishchess.org/tests/view/5ea87c842141237a731f0c7d LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 81336 W: 10429 L: 10028 D: 60879 Ptnml(0-2): 589, 7356, 24404, 7703, 616 closes https://github.com/official-stockfish/Stockfish/pull/2651 bench 4405247 --- src/search.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index a3d4a329..55c520a4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1049,6 +1049,13 @@ moves_loop: // When in check, search starts from here && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) continue; + // Futility pruning for captures + if ( !givesCheck + && lmrDepth < 6 + && !ss->inCheck + && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) + continue; + // See based pruning if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) continue; From 353e20674b2019094059caaa3567e9a44abe9cd1 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 29 Apr 2020 17:39:25 +0200 Subject: [PATCH 081/142] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2628 No functional change --- src/evaluate.cpp | 6 ++++-- src/pawns.cpp | 4 ++-- src/pawns.h | 4 ++-- src/position.cpp | 2 +- src/position.h | 2 +- src/search.cpp | 14 +++++++------- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cbcebd04..9d7728c4 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -740,7 +740,7 @@ namespace { // Now apply the bonus: note that we find the attacking side by extracting the // sign of the midgame or endgame values, and that we carefully cap the bonus // so that the midgame and endgame scores do not change sign after the bonus. - int u = ((mg > 0) - (mg < 0)) * std::max(std::min(complexity + 50, 0), -abs(mg)); + int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) @@ -815,7 +815,8 @@ namespace { initialize(); initialize(); - // Pieces should be evaluated first (populate attack tables) + // Pieces evaluated first (also populates attackedBy, attackedBy2). + // Note that the order of evaluation of the terms is left unspecified score += pieces() - pieces() + pieces() - pieces() + pieces() - pieces() @@ -823,6 +824,7 @@ namespace { score += mobility[WHITE] - mobility[BLACK]; + // More complex interactions that require fully populated attack bitboards score += king< WHITE>() - king< BLACK>() + threats() - threats() + passed< WHITE>() - passed< BLACK>() diff --git a/src/pawns.cpp b/src/pawns.cpp index 066146e2..7b266e77 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -86,7 +86,6 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); - e->blockedCount[Us] = 0; // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -106,7 +105,7 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount[Us] += blocked || more_than_one(leverPush); + e->blockedCount += blocked || more_than_one(leverPush); // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. @@ -178,6 +177,7 @@ Entry* probe(const Position& pos) { return e; e->key = key; + e->blockedCount = 0; e->scores[WHITE] = evaluate(pos, e); e->scores[BLACK] = evaluate(pos, e); diff --git a/src/pawns.h b/src/pawns.h index 41a88c6f..a3284a0f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -38,7 +38,7 @@ struct Entry { Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); } - int blocked_count() const { return blockedCount[WHITE] + blockedCount[BLACK]; } + int blocked_count() const { return blockedCount; } template Score king_safety(const Position& pos) { @@ -60,7 +60,7 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; - int blockedCount[COLOR_NB]; + int blockedCount; }; typedef HashTable Table; diff --git a/src/position.cpp b/src/position.cpp index 6bbb7914..40ebb959 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -306,7 +306,7 @@ void Position::set_castling_right(Color c, Square rfrom) { Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) - & ~(square_bb(kfrom) | rfrom); + & ~(kfrom | rfrom); } diff --git a/src/position.h b/src/position.h index f79c5463..34a6abc3 100644 --- a/src/position.h +++ b/src/position.h @@ -269,7 +269,7 @@ inline bool Position::can_castle(CastlingRights cr) const { } inline int Position::castling_rights(Color c) const { - return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING); + return c & CastlingRights(st->castlingRights); } inline bool Position::castling_impeded(CastlingRights cr) const { diff --git a/src/search.cpp b/src/search.cpp index 55c520a4..7f29f771 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -61,8 +61,8 @@ namespace { // Different node types, used as a template parameter enum NodeType { NonPV, PV }; - constexpr uint64_t ttHitAverageWindow = 4096; - constexpr uint64_t ttHitAverageResolution = 1024; + constexpr uint64_t TtHitAverageWindow = 4096; + constexpr uint64_t TtHitAverageResolution = 1024; // Razor and futility margins constexpr int RazorMargin = 531; @@ -378,7 +378,7 @@ void Thread::search() { multiPV = std::max(multiPV, (size_t)4); multiPV = std::min(multiPV, rootMoves.size()); - ttHitAverage = ttHitAverageWindow * ttHitAverageResolution / 2; + ttHitAverage = TtHitAverageWindow * TtHitAverageResolution / 2; int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns @@ -702,8 +702,8 @@ namespace { thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); // thisThread->ttHitAverage can be used to approximate the running average of ttHit - thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow - + ttHitAverageResolution * ttHit; + thisThread->ttHitAverage = (TtHitAverageWindow - 1) * thisThread->ttHitAverage / TtHitAverageWindow + + TtHitAverageResolution * ttHit; // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -1170,12 +1170,12 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || thisThread->ttHitAverage < 375 * ttHitAverageResolution * ttHitAverageWindow / 1024)) + || thisThread->ttHitAverage < 375 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); // Decrease reduction if the ttHit running average is large - if (thisThread->ttHitAverage > 500 * ttHitAverageResolution * ttHitAverageWindow / 1024) + if (thisThread->ttHitAverage > 500 * TtHitAverageResolution * TtHitAverageWindow / 1024) r--; // Reduction if other threads are searching this position. From 7f8166db89120960effa2ddda1a25188e5ab95b8 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Sat, 25 Apr 2020 15:55:35 -0400 Subject: [PATCH 082/142] Tuned safe checks and minor piece king protectors A combination of terms related to king safety one tuned safe check weights, the other tuned knight and bishop king protector weights separately with some compensation in the high outpost bonuses given to the minor pieces. passed STC LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 39892 W: 7594 L: 7350 D: 24948 Ptnml(0-2): 643, 4559, 9314, 4771, 659 https://tests.stockfishchess.org/tests/view/5ea49635b908f6dd28f34b82 passed LTC LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 104934 W: 13300 L: 12834 D: 78800 Ptnml(0-2): 697, 9571, 31514, 9939, 746 https://tests.stockfishchess.org/tests/view/5ea4abf6b908f6dd28f34bcb closes https://github.com/official-stockfish/Stockfish/pull/2649 Bench 4800754 --- AUTHORS | 1 + src/evaluate.cpp | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/AUTHORS b/AUTHORS index 79eb98a0..9fceebf7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,6 +42,7 @@ Eelco de Groot (KingDefender) Elvin Liu (solarlight2) erbsenzaehler Ernesto Gatti +Linmiao Xu (linrock) Fabian Beuke (madnight) Fabian Fichter (ianfab) fanon diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9d7728c4..874faa6b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -81,10 +81,10 @@ namespace { constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; // Penalties for enemy's safe checks - constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 1078; - constexpr int BishopSafeCheck = 635; - constexpr int KnightSafeCheck = 790; + constexpr int QueenSafeCheck = 772; + constexpr int RookSafeCheck = 1084; + constexpr int BishopSafeCheck = 645; + constexpr int KnightSafeCheck = 792; #define S(mg, eg) make_score(mg, eg) @@ -131,11 +131,14 @@ namespace { constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); - constexpr Score KingProtector = S( 7, 8); + constexpr Score BishopKingProtector = S( 6, 9); + constexpr Score KnightKingProtector = S( 8, 9); constexpr Score KnightOnQueen = S( 16, 11); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 30, 21); + constexpr Score KnightOutpost = S( 56, 36); + constexpr Score BishopOutpost = S( 30, 23); + constexpr Score ReachableOutpost = S( 31, 22); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); @@ -293,17 +296,17 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost * (Pt == KNIGHT ? 2 : 1); - + score += (Pt == KNIGHT) ? KnightOutpost : BishopOutpost; else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) - score += Outpost; + score += ReachableOutpost; // Bonus for a knight or bishop shielded by pawn if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; // Penalty if the piece is far from the king - score -= KingProtector * distance(pos.square(Us), s); + score -= (Pt == KNIGHT ? KnightKingProtector + : BishopKingProtector) * distance(pos.square(Us), s); if (Pt == BISHOP) { @@ -399,7 +402,7 @@ namespace { // Enemy rooks checks rookChecks = b1 & safe & attackedBy[Them][ROOK]; if (rookChecks) - kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 3/2 + kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 175/100 : RookSafeCheck; else unsafeChecks |= b1 & attackedBy[Them][ROOK]; @@ -412,7 +415,7 @@ namespace { & ~attackedBy[Us][QUEEN] & ~rookChecks; if (queenChecks) - kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2 + kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100 : QueenSafeCheck; // Enemy bishops checks: we count them only if they are from squares from @@ -430,7 +433,7 @@ namespace { // Enemy knights checks knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; if (knightChecks & safe) - kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 3/2 + kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100 : KnightSafeCheck; else unsafeChecks |= knightChecks; From eb4a124b8859a6029b61f403e0a9415fa748e4bd Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 2 May 2020 16:45:20 +0300 Subject: [PATCH 083/142] Refine scale factor of opposite colored bishops endgames. This patch makes it dependant on the count of passed pawns of the strong side instead of 22/64 in every case. passed STC https://tests.stockfishchess.org/tests/view/5ead60966ffeed51f6e32591 LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 50336 W: 9473 L: 9241 D: 31622 Ptnml(0-2): 570, 5371, 13098, 5515, 614 passed LTC https://tests.stockfishchess.org/tests/view/5ead6d3b6ffeed51f6e325b0 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 21952 W: 2810 L: 2603 D: 16539 Ptnml(0-2): 101, 1791, 7005, 1958, 121 closes https://github.com/official-stockfish/Stockfish/pull/2658 bench 4247490 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 874faa6b..67e05921 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -768,7 +768,7 @@ namespace { { if ( pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = 22; + sf = 18 + 4 * popcount(pe->passed_pawns(strongSide)); else sf = 22 + 3 * pos.count(strongSide); } From c527c3ad44f7465c79cef93f1e8cfebd998dc627 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 4 Apr 2015 08:54:15 +0200 Subject: [PATCH 084/142] Fishtest Tuning Framework The purpose of the code is to allow developers to easily and flexibly setup SF for a tuning session. Mainly you have just to remove 'const' qualifiers from the variables you want to tune and flag them for tuning, so if you have: int myKing = 10; Score myBonus = S(5, 15); Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } }; and at the end of the update you may want to call a post update function: void my_post_update(); If instead of default Option's min-max values, you prefer your custom ones, returned by: std::pair my_range(int value) Or you jus want to set the range directly, you can simply add below: TUNE(SetRange(my_range), myKing, SetRange(-200, 200), myBonus, myValue, my_post_update); And all the magic happens :-) At startup all the parameters are printed in a format suitable to be copy-pasted in fishtest. In case the post update function is slow and you have many parameters to tune, you can add: UPDATE_ON_LAST(); And the values update, including post update function call, will be done only once, after the engine receives the last UCI option. The last option is the one defined and created as the last one, so this assumes that the GUI sends the options in the same order in which have been defined. closes https://github.com/official-stockfish/Stockfish/pull/2654 No functional change. --- src/Makefile | 2 +- src/main.cpp | 1 + src/tune.cpp | 146 ++++++++++++++++++++++++++++++++++++++ src/tune.h | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/types.h | 2 + 5 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 src/tune.cpp create mode 100644 src/tune.h diff --git a/src/Makefile b/src/Makefile index 15ad6353..0998a551 100644 --- a/src/Makefile +++ b/src/Makefile @@ -38,7 +38,7 @@ PGOBENCH = ./$(EXE) bench ### Object files OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \ material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \ - search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o + search.o thread.o timeman.o tt.o uci.o ucioption.o tune.o syzygy/tbprobe.o ### Establish the operating system name KERNEL = $(shell uname -s) diff --git a/src/main.cpp b/src/main.cpp index 182cf105..6eeda66d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ int main(int argc, char* argv[]) { std::cout << engine_info() << std::endl; UCI::init(Options); + Tune::init(); PSQT::init(); Bitboards::init(); Position::init(); diff --git a/src/tune.cpp b/src/tune.cpp new file mode 100644 index 00000000..fe61151f --- /dev/null +++ b/src/tune.cpp @@ -0,0 +1,146 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "types.h" +#include "misc.h" +#include "uci.h" + +using std::string; + +bool Tune::update_on_last; +const UCI::Option* LastOption = nullptr; +BoolConditions Conditions; +static std::map TuneResults; + +string Tune::next(string& names, bool pop) { + + string name; + + do { + string token = names.substr(0, names.find(',')); + + if (pop) + names.erase(0, token.size() + 1); + + std::stringstream ws(token); + name += (ws >> token, token); // Remove trailing whitespace + + } while ( std::count(name.begin(), name.end(), '(') + - std::count(name.begin(), name.end(), ')')); + + return name; +} + +static void on_tune(const UCI::Option& o) { + + if (!Tune::update_on_last || LastOption == &o) + Tune::read_options(); +} + +static void make_option(const string& n, int v, const SetRange& r) { + + // Do not generate option when there is nothing to tune (ie. min = max) + if (r(v).first == r(v).second) + return; + + if (TuneResults.count(n)) + v = TuneResults[n]; + + Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune); + LastOption = &Options[n]; + + // Print formatted parameters, ready to be copy-pasted in fishtest + std::cout << n << "," + << v << "," + << r(v).first << "," << r(v).second << "," + << (r(v).second - r(v).first) / 20.0 << "," + << "0.0020" + << std::endl; +} + +template<> void Tune::Entry::init_option() { make_option(name, value, range); } + +template<> void Tune::Entry::read_option() { + if (Options.count(name)) + value = Options[name]; +} + +template<> void Tune::Entry::init_option() { make_option(name, value, range); } + +template<> void Tune::Entry::read_option() { + if (Options.count(name)) + value = Value(int(Options[name])); +} + +template<> void Tune::Entry::init_option() { + make_option("m" + name, mg_value(value), range); + make_option("e" + name, eg_value(value), range); +} + +template<> void Tune::Entry::read_option() { + if (Options.count("m" + name)) + value = make_score(Options["m" + name], eg_value(value)); + + if (Options.count("e" + name)) + value = make_score(mg_value(value), Options["e" + name]); +} + +// Instead of a variable here we have a PostUpdate function: just call it +template<> void Tune::Entry::init_option() {} +template<> void Tune::Entry::read_option() { value(); } + + +// Set binary conditions according to a probability that depends +// on the corresponding parameter value. + +void BoolConditions::set() { + + static PRNG rng(now()); + static bool startup = true; // To workaround fishtest bench + + for (size_t i = 0; i < binary.size(); i++) + binary[i] = !startup && (values[i] + int(rng.rand() % variance) > threshold); + + startup = false; + + for (size_t i = 0; i < binary.size(); i++) + sync_cout << binary[i] << sync_endl; +} + + +// Init options with tuning session results instead of default values. Useful to +// get correct bench signature after a tuning session or to test tuned values. +// Just copy fishtest tuning results in a result.txt file and extract the +// values with: +// +// cat results.txt | sed 's/^param: \([^,]*\), best: \([^,]*\).*/ TuneResults["\1"] = int(round(\2));/' +// +// Then paste the output below, as the function body + +#include + +void Tune::read_results() { + + /* ...insert your values here... */ +} diff --git a/src/tune.h b/src/tune.h new file mode 100644 index 00000000..27c3f961 --- /dev/null +++ b/src/tune.h @@ -0,0 +1,195 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008-2017 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef TUNE_H_INCLUDED +#define TUNE_H_INCLUDED + +#include +#include +#include +#include + +typedef std::pair Range; // Option's min-max values +typedef Range (RangeFun) (int); + +// Default Range function, to calculate Option's min-max values +inline Range default_range(int v) { + return v > 0 ? Range(0, 2 * v) : Range(2 * v, 0); +} + +struct SetRange { + explicit SetRange(RangeFun f) : fun(f) {} + SetRange(int min, int max) : fun(nullptr), range(min, max) {} + Range operator()(int v) const { return fun ? fun(v) : range; } + + RangeFun* fun; + Range range; +}; + +#define SetDefaultRange SetRange(default_range) + + +/// BoolConditions struct is used to tune boolean conditions in the +/// code by toggling them on/off according to a probability that +/// depends on the value of a tuned integer parameter: for high +/// values of the parameter condition is always disabled, for low +/// values is always enabled, otherwise it is enabled with a given +/// probability that depnends on the parameter under tuning. + +struct BoolConditions { + void init(size_t size) { values.resize(size, defaultValue), binary.resize(size, 0); } + void set(); + + std::vector binary, values; + int defaultValue = 465, variance = 40, threshold = 500; + SetRange range = SetRange(0, 1000); +}; + +extern BoolConditions Conditions; + +inline void set_conditions() { Conditions.set(); } + + +/// Tune class implements the 'magic' code that makes the setup of a fishtest +/// tuning session as easy as it can be. Mainly you have just to remove const +/// qualifiers from the variables you want to tune and flag them for tuning, so +/// if you have: +/// +/// const Score myScore = S(10, 15); +/// const Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } }; +/// +/// If you have a my_post_update() function to run after values have been updated, +/// and a my_range() function to set custom Option's min-max values, then you just +/// remove the 'const' qualifiers and write somewhere below in the file: +/// +/// TUNE(SetRange(my_range), myScore, myValue, my_post_update); +/// +/// You can also set the range directly, and restore the default at the end +/// +/// TUNE(SetRange(-100, 100), myScore, SetDefaultRange); +/// +/// In case update function is slow and you have many parameters, you can add: +/// +/// UPDATE_ON_LAST(); +/// +/// And the values update, including post update function call, will be done only +/// once, after the engine receives the last UCI option, that is the one defined +/// and created as the last one, so the GUI should send the options in the same +/// order in which have been defined. + +class Tune { + + typedef void (PostUpdate) (); // Post-update function + + Tune() { read_results(); } + Tune(const Tune&) = delete; + void operator=(const Tune&) = delete; + void read_results(); + + static Tune& instance() { static Tune t; return t; } // Singleton + + // Use polymorphism to accomodate Entry of different types in the same vector + struct EntryBase { + virtual ~EntryBase() = default; + virtual void init_option() = 0; + virtual void read_option() = 0; + }; + + template + struct Entry : public EntryBase { + + static_assert(!std::is_const::value, "Parameter cannot be const!"); + + static_assert( std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value, "Parameter type not supported!"); + + Entry(const std::string& n, T& v, const SetRange& r) : name(n), value(v), range(r) {} + void operator=(const Entry&) = delete; // Because 'value' is a reference + void init_option() override; + void read_option() override; + + std::string name; + T& value; + SetRange range; + }; + + // Our facilty to fill the container, each Entry corresponds to a parameter to tune. + // We use variadic templates to deal with an unspecified number of entries, each one + // of a possible different type. + static std::string next(std::string& names, bool pop = true); + + int add(const SetRange&, std::string&&) { return 0; } + + template + int add(const SetRange& range, std::string&& names, T& value, Args&&... args) { + list.push_back(std::unique_ptr(new Entry(next(names), value, range))); + return add(range, std::move(names), args...); + } + + // Template specialization for arrays: recursively handle multi-dimensional arrays + template + int add(const SetRange& range, std::string&& names, T (&value)[N], Args&&... args) { + for (size_t i = 0; i < N; i++) + add(range, next(names, i == N - 1) + "[" + std::to_string(i) + "]", value[i]); + return add(range, std::move(names), args...); + } + + // Template specialization for SetRange + template + int add(const SetRange&, std::string&& names, SetRange& value, Args&&... args) { + return add(value, (next(names), std::move(names)), args...); + } + + // Template specialization for BoolConditions + template + int add(const SetRange& range, std::string&& names, BoolConditions& cond, Args&&... args) { + for (size_t size = cond.values.size(), i = 0; i < size; i++) + add(cond.range, next(names, i == size - 1) + "_" + std::to_string(i), cond.values[i]); + return add(range, std::move(names), args...); + } + + std::vector> list; + +public: + template + static int add(const std::string& names, Args&&... args) { + return instance().add(SetDefaultRange, names.substr(1, names.size() - 2), args...); // Remove trailing parenthesis + } + static void init() { for (auto& e : instance().list) e->init_option(); read_options(); } // Deferred, due to UCI::Options access + static void read_options() { for (auto& e : instance().list) e->read_option(); } + static bool update_on_last; +}; + +// Some macro magic :-) we define a dummy int variable that compiler initializes calling Tune::add() +#define STRINGIFY(x) #x +#define UNIQUE2(x, y) x ## y +#define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__ +#define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__) + +#define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true + +// Some macro to tune toggling of boolean conditions +#define CONDITION(x) (Conditions.binary[__COUNTER__] || (x)) +#define TUNE_CONDITIONS() int UNIQUE(c, __LINE__) = (Conditions.init(__COUNTER__), 0); \ + TUNE(Conditions, set_conditions) + +#endif // #ifndef TUNE_H_INCLUDED diff --git a/src/types.h b/src/types.h index cd8d2320..7b896803 100644 --- a/src/types.h +++ b/src/types.h @@ -465,3 +465,5 @@ constexpr bool is_ok(Move m) { } #endif // #ifndef TYPES_H_INCLUDED + +#include "tune.h" // Global visibility to tuning setup From a91cb9fc1bc403dd610b3e17f022b5afa94dff49 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 6 May 2020 08:44:39 +0100 Subject: [PATCH 085/142] Penalty for all enemy pawns xrayed by our bishop. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 159760 W: 30229 L: 29813 D: 99718 Ptnml(0-2): 2659, 18309, 37534, 18713, 2665 https://tests.stockfishchess.org/tests/view/5eb1d5032326444a3b6d33ce LTC: LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 26496 W: 3908 L: 3656 D: 18932 Ptnml(0-2): 192, 2512, 7610, 2720, 214 https://tests.stockfishchess.org/tests/view/5eb1e2dd2326444a3b6d33f9 closes https://github.com/official-stockfish/Stockfish/pull/2662 Bench 5185517 --- src/evaluate.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 67e05921..e663f21f 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -128,6 +128,7 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); @@ -318,6 +319,9 @@ namespace { score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); + // Penalty for all enemy pawns x-rayed + score -= BishopXRayPawns * popcount(PseudoAttacks[BISHOP][s] & pos.pieces(Them, PAWN)); + // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) score += LongDiagonalBishop; From fcaf0736feb17f1eb639a7ae071acc920b308f74 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Fri, 8 May 2020 12:07:42 +0100 Subject: [PATCH 086/142] Fix syzygy dependencies issue fixes https://github.com/official-stockfish/Stockfish/issues/2660 The problem was caused by .depend being created with a rule for tbprobe.o not for syzygy/tbprobe.o. This patch keeps an explicit list of sources (SRCS), generates OBJS, and compiles all object files to the src/ directory, consistent with .depend. VPATH is used to search the syzygy directory as needed. joint work with @gvreuls closes https://github.com/official-stockfish/Stockfish/pull/2664 No functional change --- src/Makefile | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0998a551..016aafec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,10 +35,14 @@ BINDIR = $(PREFIX)/bin ### Built-in benchmark for pgo-builds PGOBENCH = ./$(EXE) bench -### Object files -OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \ - material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \ - search.o thread.o timeman.o tt.o uci.o ucioption.o tune.o syzygy/tbprobe.o +### Source and object files +SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ + material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \ + search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp + +OBJS = $(notdir $(SRCS:.cpp=.o)) + +VPATH = syzygy ### Establish the operating system name KERNEL = $(shell uname -s) @@ -450,7 +454,7 @@ objclean: # clean auxiliary profiling files profileclean: @rm -rf profdir - @rm -f bench.txt *.gcda ./syzygy/*.gcda *.gcno ./syzygy/*.gcno + @rm -f bench.txt *.gcda *.gcno @rm -f stockfish.profdata *.profraw default: @@ -536,7 +540,7 @@ icc-profile-use: all .depend: - -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null + -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null -include .depend From 8a1de2655ce9790d5f0360e2baefb0f5c0fe2944 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 9 May 2020 19:45:07 +0200 Subject: [PATCH 087/142] Use posix_memalign instead of aligned_alloc should be a little more portable to older linux systems (before glibc-2.16). fixes https://github.com/official-stockfish/Stockfish/issues/2665 closes https://github.com/official-stockfish/Stockfish/pull/2668 No functional change. --- src/misc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 4d6483e7..94681008 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -303,7 +303,8 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment - mem = aligned_alloc(alignment, size); + if (posix_memalign(&mem, alignment, size)) + mem = nullptr; madvise(mem, allocSize, MADV_HUGEPAGE); return mem; } From 66ed8b6c479932f1ec2274b5f567b5a6aecae0a4 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Fri, 8 May 2020 16:59:06 +0200 Subject: [PATCH 088/142] Tune pawn value Small tune of PawnValue parameters -4 / -7 with "closedpos.epd" opening book. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 58776 W: 11787 L: 11511 D: 35478 Ptnml(0-2): 975, 6876, 13443, 7086, 1008 https://tests.stockfishchess.org/tests/view/5eb5aa712326444a3b6d3e33 LTC: LLR: 2.98 (-2.94,2.94) {0.25,1.75} Total: 137544 W: 19687 L: 19115 D: 98742 Ptnml(0-2): 988, 13219, 39901, 13561, 1103 https://tests.stockfishchess.org/tests/view/5eb67a392326444a3b6d3e9a Non regression STC with "noob_3moves.epd" opening book LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 98168 W: 18545 L: 18499 D: 61124 Ptnml(0-2): 1647, 11396, 22951, 11444, 1646 https://tests.stockfishchess.org/tests/view/5eb7e489e0300e8e8c896203 closes https://github.com/official-stockfish/Stockfish/pull/2670 Bench 4696646 --- src/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.h b/src/types.h index 7b896803..580c846a 100644 --- a/src/types.h +++ b/src/types.h @@ -181,7 +181,7 @@ enum Value : int { VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY, - PawnValueMg = 128, PawnValueEg = 213, + PawnValueMg = 124, PawnValueEg = 206, KnightValueMg = 781, KnightValueEg = 854, BishopValueMg = 825, BishopValueEg = 915, RookValueMg = 1276, RookValueEg = 1380, From 86ee4eb84d54dac3f9de5b455ba41909c7722173 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Tue, 12 May 2020 21:41:55 +0200 Subject: [PATCH 089/142] Use a trivially copyable struct for TBTables::Entry instead of a tuple. fixes https://github.com/official-stockfish/Stockfish/issues/2673 which is a warning issued by recent gcc (10.1) closes https://github.com/official-stockfish/Stockfish/pull/2674 No functional change --- AUTHORS | 1 + src/syzygy/tbprobe.cpp | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9fceebf7..36c2a47b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -151,6 +151,7 @@ thaspel theo77186 Tom Truscott Tom Vijlbrief (tomtor) +Tomasz Sobczyk (Sopel97) Torsten Franz (torfranz, tfranzer) Tracey Emery (basepr1me) Uri Blass (uriblass) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index f1fd695c..843f049a 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -60,7 +60,7 @@ namespace { constexpr int TBPIECES = 7; // Max number of supported pieces enum { BigEndian, LittleEndian }; -enum TBType { KEY, WDL, DTZ }; // Used as template parameter +enum TBType { WDL, DTZ }; // Used as template parameter // Each table has a set of flags: all of them refer to DTZ tables, the last one to WDL tables enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 }; @@ -403,7 +403,18 @@ TBTable::TBTable(const TBTable& wdl) : TBTable() { // at init time, accessed at probe time. class TBTables { - typedef std::tuple*, TBTable*> Entry; + struct Entry + { + Key key; + TBTable* wdl; + TBTable* dtz; + + template + TBTable* get() const { + return (TBTable*)(Type == WDL ? (void*)wdl : (void*)dtz); + } + }; + static_assert(std::is_trivially_copyable::value, ""); static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket @@ -415,12 +426,12 @@ class TBTables { void insert(Key key, TBTable* wdl, TBTable* dtz) { uint32_t homeBucket = (uint32_t)key & (Size - 1); - Entry entry = std::make_tuple(key, wdl, dtz); + Entry entry{ key, wdl, dtz }; // Ensure last element is empty to avoid overflow when looking up for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket) { - Key otherKey = std::get(hashTable[bucket]); - if (otherKey == key || !std::get(hashTable[bucket])) { + Key otherKey = hashTable[bucket].key; + if (otherKey == key || !hashTable[bucket].get()) { hashTable[bucket] = entry; return; } @@ -429,7 +440,7 @@ class TBTables { // insert here and search for a new spot for the other element instead. uint32_t otherHomeBucket = (uint32_t)otherKey & (Size - 1); if (otherHomeBucket > homeBucket) { - swap(entry, hashTable[bucket]); + std::swap(entry, hashTable[bucket]); key = otherKey; homeBucket = otherHomeBucket; } @@ -442,8 +453,8 @@ public: template TBTable* get(Key key) { for (const Entry* entry = &hashTable[(uint32_t)key & (Size - 1)]; ; ++entry) { - if (std::get(*entry) == key || !std::get(*entry)) - return std::get(*entry); + if (entry->key == key || !entry->get()) + return entry->get(); } } From d4763424d2728fe2dfd0a6fe747666feb6a2fdbb Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Mon, 4 May 2020 20:49:27 +0300 Subject: [PATCH 090/142] Add support for Windows large pages for users that set the needed privilige "Lock Pages in Memory" large pages will be automatically enabled (see Readme.md). This expert setting might improve speed, 5% - 30%, depending on the hardware, the number of threads and hash size. More for large hashes, large number of threads and NUMA. If the operating system can not allocate large pages (easier after a reboot), default allocation is used automatically. The engine log provides details. closes https://github.com/official-stockfish/Stockfish/pull/2656 fixes https://github.com/official-stockfish/Stockfish/issues/2619 No functional change --- Readme.md | 26 +++++++++++++++- src/main.cpp | 1 + src/misc.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/misc.h | 1 + src/tt.cpp | 9 +++++- 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index a759eff6..35ff095d 100644 --- a/Readme.md +++ b/Readme.md @@ -42,7 +42,7 @@ Currently, Stockfish has the following UCI options: this equal to the number of CPU cores available. * #### Hash - The size of the hash table in MB. + The size of the hash table in MB. It is recommended to set Hash after setting Threads. * #### Clear Hash Clear the hash table. @@ -138,6 +138,30 @@ more compact than Nalimov tablebases, while still storing all information needed for optimal play and in addition being able to take into account the 50-move rule. +## Large Pages + +Stockfish supports large pages on Linux and Windows. Large pages make +the hash access more efficient, improving the engine speed, especially +on large hash sizes. Typical increases are 5..10% in terms of nps, but +speed increases up to 30% have been measured. The support is +automatic. Stockfish attempts to use large pages when available and +will fall back to regular memory allocation when this is not the case. + +### Support on Linux + +Large page support on Linux is obtained by the Linux kernel +transparent huge pages functionality. Typically, transparent huge pages +are already enabled and no configuration is needed. + +### Support on Windows + +The use of large pages requires "Lock Pages in Memory" privilege. See +[Enable the Lock Pages in Memory Option (Windows)](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows) +on how to enable this privilege. Logout/login may be needed +afterwards. Due to memory fragmentation, it may not always be +possible to allocate large pages even when enabled. A reboot +might alleviate this problem. To determine whether large pages +are in use, see the engine log. ## Compiling Stockfish yourself from the sources diff --git a/src/main.cpp b/src/main.cpp index 6eeda66d..c7cf2c6f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) { UCI::loop(argc, argv); + TT.resize(0); Threads.set(0); return 0; } diff --git a/src/misc.cpp b/src/misc.cpp index 94681008..b1c0feeb 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -309,6 +309,69 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { return mem; } +#elif defined(_WIN64) + +static void* aligned_ttmem_alloc_large_pages(size_t allocSize) { + + HANDLE hProcessToken { }; + LUID luid { }; + void* mem = nullptr; + + const size_t largePageSize = GetLargePageMinimum(); + if (!largePageSize) + return nullptr; + + // We need SeLockMemoryPrivilege, so try to enable it for the process + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) + return nullptr; + + if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid)) + { + TOKEN_PRIVILEGES tp { }; + TOKEN_PRIVILEGES prevTp { }; + DWORD prevTpLen = 0; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds, + // we still need to query GetLastError() to ensure that the privileges were actually obtained... + if (AdjustTokenPrivileges( + hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) && + GetLastError() == ERROR_SUCCESS) + { + // round up size to full pages and allocate + allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1); + mem = VirtualAlloc( + NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + + // privilege no longer needed, restore previous state + AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL); + } + } + + CloseHandle(hProcessToken); + + return mem; +} + +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { + + // try to allocate large pages + mem = aligned_ttmem_alloc_large_pages(allocSize); + if (mem) + sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; + else + sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + + // fall back to regular, page aligned, allocation if necessary + if (!mem) + mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + return mem; +} + #else void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { @@ -322,6 +385,28 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { #endif +/// aligned_ttmem_free will free the previously allocated ttmem +#if defined(_WIN64) + +void aligned_ttmem_free(void* mem) { + + if (!VirtualFree(mem, 0, MEM_RELEASE)) + { + DWORD err = GetLastError(); + std::cerr << "Failed to free transposition table. Error code: 0x" << + std::hex << err << std::dec << std::endl; + exit(EXIT_FAILURE); + } +} + +#else + +void aligned_ttmem_free(void *mem) { + free(mem); +} + +#endif + namespace WinProcGroup { diff --git a/src/misc.h b/src/misc.h index e0e0e98b..9d53c2da 100644 --- a/src/misc.h +++ b/src/misc.h @@ -34,6 +34,7 @@ const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); void* aligned_ttmem_alloc(size_t size, void*& mem); +void aligned_ttmem_free(void* mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 7e95a2a4..6ee63138 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,7 +63,14 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - free(mem); + if (mem) + aligned_ttmem_free(mem); + + if (!mbSize) + { + mem = nullptr; + return; + } clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); From cca643669db016f20c6e91f50892a0b44f297a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 8 May 2020 10:32:52 +0200 Subject: [PATCH 091/142] Move 50 moves counter to initiative. simplify the usage of the 50 moves counter, moving it frome the scale factor to initiative. This patch was inspired by recent games where a blocked or semi-blocked position was 'blundered', by moving a pawn, into a lost endgame. This patch improves this situation, finding a more robust move more often. for example (1s searches with many threads): ``` FEN 8/p3kp2/Pp2p3/1n2PpP1/5P2/1Kp5/8/R7 b - - 68 143 master: 6 bestmove b5c7 6 bestmove e7e8 12 bestmove e7d8 176 bestmove e7d7 patch: 3 bestmove b5c7 5 bestmove e7d8 192 bestmove e7d7 ``` fixes https://github.com/official-stockfish/Stockfish/issues/2620 the patch also tests well passed STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 50168 W: 9508 L: 9392 D: 31268 Ptnml(0-2): 818, 5873, 11616, 5929, 848 https://tests.stockfishchess.org/tests/view/5ebb07287dd5693aad4e680b passed LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 7520 W: 981 L: 870 D: 5669 Ptnml(0-2): 49, 647, 2256, 760, 48 https://tests.stockfishchess.org/tests/view/5ebbff747dd5693aad4e6858 closes https://github.com/official-stockfish/Stockfish/pull/2666 Bench: 4395562 --- src/evaluate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e663f21f..d972db5a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -739,6 +739,7 @@ namespace { + 24 * infiltration + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable + - 2 * pos.rule50_count() -110 ; Value mg = mg_value(score); @@ -778,8 +779,6 @@ namespace { } else sf = std::min(sf, 36 + 7 * pos.count(strongSide)); - - sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); @@ -856,7 +855,8 @@ namespace { Trace::add(TOTAL, score); } - return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view + // Side to move point of view + return (pos.side_to_move() == WHITE ? v : -v) + Tempo; } } // namespace From beb327f910ed782f358d69201643ccd99b982a48 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Thu, 14 May 2020 12:00:35 +0300 Subject: [PATCH 092/142] Fix a Windows-only crash on exit without 'quit' There was a bug in commit d4763424d2728fe2dfd0a6fe747666feb6a2fdbb (Add support for Windows large pages) that could result in trying to free memory allocated with VirtualAlloc incorrectly with free(). Fix this by reverting the TT.resize(0) logic in the previous commit, and instead, just call aligned_ttmem_free() in TranspositionTable::~TranspositionTable(). fixes https://github.com/official-stockfish/Stockfish/issues/2677 closes https://github.com/official-stockfish/Stockfish/pull/2679 No functional change --- src/main.cpp | 1 - src/misc.cpp | 2 +- src/misc.h | 2 +- src/tt.cpp | 9 +-------- src/tt.h | 2 +- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c7cf2c6f..6eeda66d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,6 @@ int main(int argc, char* argv[]) { UCI::loop(argc, argv); - TT.resize(0); Threads.set(0); return 0; } diff --git a/src/misc.cpp b/src/misc.cpp index b1c0feeb..e0cc6ed5 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -390,7 +390,7 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { void aligned_ttmem_free(void* mem) { - if (!VirtualFree(mem, 0, MEM_RELEASE)) + if (mem && !VirtualFree(mem, 0, MEM_RELEASE)) { DWORD err = GetLastError(); std::cerr << "Failed to free transposition table. Error code: 0x" << diff --git a/src/misc.h b/src/misc.h index 9d53c2da..05bfc7de 100644 --- a/src/misc.h +++ b/src/misc.h @@ -34,7 +34,7 @@ const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); void* aligned_ttmem_alloc(size_t size, void*& mem); -void aligned_ttmem_free(void* mem); +void aligned_ttmem_free(void* mem); // nop if mem == nullptr void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 6ee63138..4e06bed9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,14 +63,7 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - if (mem) - aligned_ttmem_free(mem); - - if (!mbSize) - { - mem = nullptr; - return; - } + aligned_ttmem_free(mem); clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); diff --git a/src/tt.h b/src/tt.h index 8b70f797..bd723a86 100644 --- a/src/tt.h +++ b/src/tt.h @@ -75,7 +75,7 @@ class TranspositionTable { static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); public: - ~TranspositionTable() { free(mem); } + ~TranspositionTable() { aligned_ttmem_free(mem); } void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound TTEntry* probe(const Key key, bool& found) const; int hashfull() const; From c6ce612f0ada9b5f0d9530128545d1ee7d58b3e5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 13 May 2020 11:52:41 -0600 Subject: [PATCH 093/142] Simplify Time Management This is a functional simplification of the time management system. With this patch, there is a simple equation for each of two distinct time controls: basetime + increment, and x moves in y seconds (+increment). These equations are easy to plot and understand making future modifications or adding additional time controls much easier. SlowMover is reset to 100 so that is has no effect unless a user changes it. There are two scaling variables: * Opt_scale is a scale factor (or percentage) of time to use for this current move. * Max_scale is a scale factor to apply to the resulting optimumTime. There seems to be some elo gain in most scenarios. Better performance is attributable to one of two things: * minThinkingTime was not allowing reasonable time calculations for very short games like 10+0 or 10+0.01. This is because adding almost no increment and substracting move overhead for 50 moves quickly results in almost 0 time very early in the game. Master depended on minThinkingTime to handle these short games instead of good time management. This patch addresses this issue by lowering minThinkingTime to 0 and adjusting moverOverhead if there are very low increments. * Notice that the time distribution curves tail downward for the first 10 moves or so. This causes less time to attribute for very early moves leaving more time available for middle moves where more important decisions happen. Here is a summary of tests for this version at different time controls: SMP 5+0.05 LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 46544 W: 7175 L: 7089 D: 32280 Ptnml(0-2): 508, 4826, 12517, 4914, 507 https://tests.stockfishchess.org/tests/user/protonspring STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 20480 W: 3872 L: 3718 D: 12890 Ptnml(0-2): 295, 2364, 4824, 2406, 351 https://tests.stockfishchess.org/tests/view/5ebc343e7dd5693aad4e6873 STC, sudden death LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 7024 W: 1706 L: 1489 D: 3829 Ptnml(0-2): 149, 813, 1417, 938, 195 https://tests.stockfishchess.org/tests/view/5ebc346f7dd5693aad4e6875 STC, TCEC style LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 4192 W: 1014 L: 811 D: 2367 Ptnml(0-2): 66, 446, 912, 563, 109 https://tests.stockfishchess.org/tests/view/5ebc34857dd5693aad4e6877 40/10 LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 54032 W: 10592 L: 10480 D: 32960 Ptnml(0-2): 967, 6148, 12677, 6254, 970 https://tests.stockfishchess.org/tests/view/5ebc50597dd5693aad4e688d LTC, sudden death LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 9152 W: 1391 L: 1263 D: 6498 Ptnml(0-2): 75, 888, 2526, 1008, 79 https://tests.stockfishchess.org/tests/view/5ebc6f5c7dd5693aad4e689b LTC LLR: 2.98 (-2.94,2.94) {-1.50,0.50} Total: 12344 W: 1563 L: 1459 D: 9322 Ptnml(0-2): 70, 1103, 3740, 1171, 88 https://tests.stockfishchess.org/tests/view/5ebc6f4c7dd5693aad4e6899 closes https://github.com/official-stockfish/Stockfish/pull/2678 Bench: 4395562 --- src/timeman.cpp | 111 +++++++++++++++++----------------------------- src/ucioption.cpp | 4 +- 2 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index 0848be42..f794ab13 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -28,58 +28,10 @@ TimeManagement Time; // Our global time management object -namespace { - - enum TimeType { OptimumTime, MaxTime }; - - constexpr int MoveHorizon = 50; // Plan time management at most this many moves ahead - constexpr double MaxRatio = 7.3; // When in trouble, we can step over reserved time with this ratio - constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio - - - // move_importance() is a skew-logistic function based on naive statistical - // analysis of "how many games are still undecided after n half-moves". Game - // is considered "undecided" as long as neither side has >275cp advantage. - // Data was extracted from the CCRL game database with some simple filtering criteria. - - double move_importance(int ply) { - - constexpr double XScale = 6.85; - constexpr double XShift = 64.5; - constexpr double Skew = 0.171; - - return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero - } - - template - TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover) { - - constexpr double TMaxRatio = (T == OptimumTime ? 1.0 : MaxRatio); - constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio); - - double moveImportance = (move_importance(ply) * slowMover) / 100.0; - double otherMovesImportance = 0.0; - - for (int i = 1; i < movesToGo; ++i) - otherMovesImportance += move_importance(ply + 2 * i); - - double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance); - double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance); - - return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast - } - -} // namespace - - -/// init() is called at the beginning of the search and calculates the allowed -/// thinking time out of the time control and current game ply. We support four -/// different kinds of time controls, passed in 'limits': -/// -/// inc == 0 && movestogo == 0 means: x basetime [sudden death!] -/// inc == 0 && movestogo != 0 means: x moves in y minutes -/// inc > 0 && movestogo == 0 means: x basetime + z increment -/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment +/// init() is called at the beginning of the search and calculates the bounds +/// of time allowed for the current game ply. We currently support: +// 1) x basetime (+z increment) +// 2) x moves in y seconds (+z increment) void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { @@ -87,7 +39,10 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { TimePoint moveOverhead = Options["Move Overhead"]; TimePoint slowMover = Options["Slow Mover"]; TimePoint npmsec = Options["nodestime"]; - TimePoint hypMyTime; + + // opt_scale is a percentage of available time to use for the current move. + // max_scale is a multiplier applied to optimumTime. + double opt_scale, max_scale; // If we have to play in 'nodes as time' mode, then convert from time // to nodes, and use resulting values in time management formulas. @@ -105,29 +60,43 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { } startTime = limits.startTime; - optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime); - const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon; + //Maximum move horizon of 50 moves + int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; - // We calculate optimum time usage for different hypothetical "moves to go" values - // and choose the minimum of calculated search time values. Usually the greatest - // hypMTG gives the minimum values. - for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG) + // Adjust moveOverhead if there are tiny increments + moveOverhead = std::max(10, std::min(limits.inc[us] / 2, moveOverhead)); + + // Make sure timeLeft is > 0 since we may use it as a divisor + TimePoint timeLeft = std::max(TimePoint(1), + limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); + + // A user may scale time usage by setting UCI option "Slow Mover" + // Default is 100 and changing this value will probably lose elo. + timeLeft = slowMover * timeLeft / 100; + + // x basetime (+ z increment) + // If there is a healthy increment, timeLeft can exceed actual available + // game time for the current move, so also cap to 20% of available game time. + if (limits.movestogo == 0) { - // Calculate thinking time for hypothetical "moves to go"-value - hypMyTime = limits.time[us] - + limits.inc[us] * (hypMTG - 1) - - moveOverhead * (2 + std::min(hypMTG, 40)); - - hypMyTime = std::max(hypMyTime, TimePoint(0)); - - TimePoint t1 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - TimePoint t2 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - - optimumTime = std::min(t1, optimumTime); - maximumTime = std::min(t2, maximumTime); + opt_scale = std::min(0.007 + std::pow(ply + 3.0, 0.5) / 250.0, + 0.2 * limits.time[us] / double(timeLeft)); + max_scale = 4 + std::pow(ply + 3, 0.3); } + // x moves in y seconds (+ z increment) + else + { + opt_scale = std::min((0.8 + ply / 128.0) / mtg, + 0.8 * limits.time[us] / double(timeLeft)); + max_scale = std::min(6.3, 1.5 + 0.11 * mtg); + } + + // Never use more than 80% of the available time for this move + optimumTime = std::max(minThinkingTime, opt_scale * timeLeft); + maximumTime = std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime); + if (Options["Ponder"]) optimumTime += optimumTime / 4; } diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 26fcf302..ad576fda 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -69,8 +69,8 @@ void init(OptionsMap& o) { o["MultiPV"] << Option(1, 1, 500); o["Skill Level"] << Option(20, 0, 20); o["Move Overhead"] << Option(30, 0, 5000); - o["Minimum Thinking Time"] << Option(20, 0, 5000); - o["Slow Mover"] << Option(84, 10, 1000); + o["Minimum Thinking Time"] << Option( 0, 0, 5000); + o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); o["UCI_Chess960"] << Option(false); o["UCI_AnalyseMode"] << Option(false); From d116e27f0f6c89c887420890ffe61c6708ef5c08 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 15 May 2020 19:37:56 +0200 Subject: [PATCH 094/142] Workaround for older compiler gcc < 5 doesn't fully support the c++11 `std::is_trivially_copyable::value` Remove it, as it is not essential. fixes https://github.com/official-stockfish/Stockfish/issues/2681 closes https://github.com/official-stockfish/Stockfish/pull/2682 No functional change. --- src/syzygy/tbprobe.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 843f049a..adc45d58 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -414,7 +414,6 @@ class TBTables { return (TBTable*)(Type == WDL ? (void*)wdl : (void*)dtz); } }; - static_assert(std::is_trivially_copyable::value, ""); static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket From 83c9e5911ef7fe6ff71dc116856fac85bb9076eb Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 15 May 2020 17:23:49 -0600 Subject: [PATCH 095/142] Don't adjust MoveOverhead by increment This is a change to address a potential timing issue for slow networks. Move Overhead was limited by TC increment, which might be problematic if small increments (or sudden death) on slow networks (needing high Move Overhead) are used. STC, sudden death. LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 169368 W: 38023 L: 38054 D: 93291 Ptnml(0-2): 3767, 20250, 36595, 20391, 3681 https://tests.stockfishchess.org/tests/view/5ebf25efe9d85f94dc42986f STC, 10+0.1 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 83896 W: 16092 L: 16026 D: 51778 Ptnml(0-2): 1401, 9697, 19670, 9795, 1385 https://tests.stockfishchess.org/tests/view/5ec0239de9d85f94dc42991e closes https://github.com/official-stockfish/Stockfish/pull/2684 No functional change. --- src/timeman.cpp | 3 --- src/ucioption.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index f794ab13..0021e96b 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -64,9 +64,6 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { //Maximum move horizon of 50 moves int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; - // Adjust moveOverhead if there are tiny increments - moveOverhead = std::max(10, std::min(limits.inc[us] / 2, moveOverhead)); - // Make sure timeLeft is > 0 since we may use it as a divisor TimePoint timeLeft = std::max(TimePoint(1), limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); diff --git a/src/ucioption.cpp b/src/ucioption.cpp index ad576fda..66fd42d1 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -68,7 +68,7 @@ void init(OptionsMap& o) { o["Ponder"] << Option(false); o["MultiPV"] << Option(1, 1, 500); o["Skill Level"] << Option(20, 0, 20); - o["Move Overhead"] << Option(30, 0, 5000); + o["Move Overhead"] << Option(10, 0, 5000); o["Minimum Thinking Time"] << Option( 0, 0, 5000); o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); From dd1adce7488b20b4125946077bcbbf665b9797f7 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sun, 17 May 2020 20:46:25 +0100 Subject: [PATCH 096/142] Increase base time use and limit max used. This change increases the base part of optimumTime at all depths. It also reduces the size of max_scale and thus maximumTime by using a linear scale instead of pow(x, 0.3) and by limiting max_scale to no more than 7 (previously as high as 8 or 9 at very high depths). Tested using the closedpos book: STC 10+0.1: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 83696 W: 16813 L: 16508 D: 50375 Ptnml(0-2): 1315, 9649, 19686, 9812, 1386 https://tests.stockfishchess.org/tests/view/5ebfa92de9d85f94dc42989b LTC 60+0.6: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 39384 W: 5868 L: 5582 D: 27934 Ptnml(0-2): 276, 3697, 11489, 3925, 305 https://tests.stockfishchess.org/tests/view/5ec0a6dce9d85f94dc42995a Test for non-regression: STC Sudden Death 10+0 : LLR: 2.94 (-2.94,2.94) {-2.00,0.00} Total: 111976 W: 25661 L: 25768 D: 60547 Ptnml(0-2): 2567, 13420, 24118, 13319, 2564 https://tests.stockfishchess.org/tests/view/5ec23b3be9d85f94dc429a58 closes https://github.com/official-stockfish/Stockfish/pull/2685 Bench 4395562 --- src/timeman.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index 0021e96b..45e9db58 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -77,9 +77,9 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { // game time for the current move, so also cap to 20% of available game time. if (limits.movestogo == 0) { - opt_scale = std::min(0.007 + std::pow(ply + 3.0, 0.5) / 250.0, + opt_scale = std::min(0.008 + std::pow(ply + 3.0, 0.5) / 250.0, 0.2 * limits.time[us] / double(timeLeft)); - max_scale = 4 + std::pow(ply + 3, 0.3); + max_scale = 4 + std::min(36, ply) / 12.0; } // x moves in y seconds (+ z increment) From b36a1fa1b4ffded06aba53e1003b40827c39803c Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Tue, 19 May 2020 12:08:01 +0300 Subject: [PATCH 097/142] Avoid sending info strings before 'uci' has been received Do not send the following info string on the first call to aligned_ttmem_alloc() on Windows: info string Hash table allocation: Windows large pages [not] used. The first call occurs before the 'uci' command has been received. This confuses some GUIs, which expect the first engine-sent command to be 'id' as the response to the 'uci' command. (see https://github.com/official-stockfish/Stockfish/issues/2681) closes https://github.com/official-stockfish/Stockfish/pull/2689 No functional change. --- src/misc.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index e0cc6ed5..c6254784 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -358,12 +358,21 @@ static void* aligned_ttmem_alloc_large_pages(size_t allocSize) { void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { + static bool firstCall = true; + // try to allocate large pages mem = aligned_ttmem_alloc_large_pages(allocSize); - if (mem) - sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; - else - sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + + // Suppress info strings on the first call. The first call occurs before 'uci' + // is received and in that case this output confuses some GUIs. + if (!firstCall) + { + if (mem) + sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; + else + sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + } + firstCall = false; // fall back to regular, page aligned, allocation if necessary if (!mem) From 20ceeac8b3a3bd13a64d6a224ef190d6cdd94f63 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 20 May 2020 08:33:59 -0600 Subject: [PATCH 098/142] Simplify evaluation for blocked passers. This is a functional simplification of the evaluation code for blocked passers. I've also changed a few variable names for clarity. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 141984 W: 27450 L: 27466 D: 87068 Ptnml(0-2): 2414, 16511, 33175, 16461, 2431 https://tests.stockfishchess.org/tests/view/5ec4001b05aa4bc72d9759e7 LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 30536 W: 3966 L: 3885 D: 22685 Ptnml(0-2): 216, 2841, 9073, 2922, 216 https://tests.stockfishchess.org/tests/view/5ec4bd0d377121ac09e101b7 Closes https://github.com/official-stockfish/Stockfish/pull/2690 Bench: 4704681 --- src/evaluate.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d972db5a..d04d724a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -591,25 +591,22 @@ namespace { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, unsafeSquares, candidatePassers, leverable; + Bitboard b, bb, squaresToQueen, unsafeSquares, blockedPassers, helpers; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); - candidatePassers = b & shift(pos.pieces(Them, PAWN)); - if (candidatePassers) + blockedPassers = b & shift(pos.pieces(Them, PAWN)); + if (blockedPassers) { - // Can we lever the blocker of a candidate passer? - leverable = shift(pos.pieces(Us, PAWN)) - & ~pos.pieces(Them) - & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]) - & (~(attackedBy[Them][KNIGHT] | attackedBy[Them][BISHOP]) - | (attackedBy[Us ][KNIGHT] | attackedBy[Us ][BISHOP])); + helpers = shift(pos.pieces(Us, PAWN)) + & ~pos.pieces(Them) + & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]); - // Remove candidate otherwise - b &= ~candidatePassers - | shift(leverable) - | shift(leverable); + // Remove blocked candidate passers that don't have help to pass + b &= ~blockedPassers + | shift(helpers) + | shift(helpers); } while (b) From 6c1af710d16c6a358cc09c51a133120605c39e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 20 May 2020 17:06:42 +0200 Subject: [PATCH 099/142] A combo of parameters tweaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is a combinaison of two recent parameters tweaks which had failed narrowly (yellow) at long time control: • improvement in move ordering during search by softening the distinction between bad captures and good captures during move generation, leading to improved awareness of Stockfish of potential piece sacrifices (idea by Rahul Dsilva) • increase in the weight of pawns in the "initiative" part of the evaluation function. With this change Stockfish should have more incentive to exchange pawns when losing, and to keep pawns when winning. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 10704 W: 2178 L: 1974 D: 6552 Ptnml(0-2): 168, 1185, 2464, 1345, 190 https://tests.stockfishchess.org/tests/view/5ec5553b377121ac09e1023d LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 60592 W: 7835 L: 7494 D: 45263 Ptnml(0-2): 430, 5514, 18086, 5817, 449 https://tests.stockfishchess.org/tests/view/5ec55ca2377121ac09e10249 Closes https://github.com/official-stockfish/Stockfish/pull/2691 Bench: 4519117 --- src/evaluate.cpp | 2 +- src/movepick.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d04d724a..449cf6d7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -730,7 +730,7 @@ namespace { // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() - + 11 * pos.count() + + 12 * pos.count() + 9 * outflanking + 21 * pawnsOnBothFlanks + 24 * infiltration diff --git a/src/movepick.cpp b/src/movepick.cpp index b1e10587..e26f42ef 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -169,7 +169,7 @@ top: case GOOD_CAPTURE: if (select([&](){ - return pos.see_ge(*cur, Value(-55 * cur->value / 1024)) ? + return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ? // Move losing capture to endBadCaptures to be tried later true : (*endBadCaptures++ = *cur, false); })) return *(cur - 1); From 09c6917d053582267a2960e8c375883e0d9461da Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 21 May 2020 12:29:36 +0200 Subject: [PATCH 100/142] Tweak knight mobility New tuned values for knight mobility in endgames. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 112576 W: 21999 L: 21644 D: 68933 Ptnml(0-2): 2009, 13084, 25735, 13463, 1997 https://tests.stockfishchess.org/tests/view/5ec58379377121ac09e10272 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 125192 W: 16200 L: 15671 D: 93321 Ptnml(0-2): 891, 11584, 37182, 11983, 956 https://tests.stockfishchess.org/tests/view/5ec5c0b8377121ac09e1028b Closes https://github.com/official-stockfish/Stockfish/pull/2693 Bench: 4778956 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 449cf6d7..e80e9442 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -91,8 +91,8 @@ namespace { // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. constexpr Score MobilityBonus[][32] = { - { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knight - S( 22, 23), S( 28, 27), S( 33, 33) }, + { S(-62,-81), S(-53,-56), S(-12,-31), S( -4,-16), S( 3, 5), S( 13, 11), // Knight + S( 22, 17), S( 28, 20), S( 33, 25) }, { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, From cdf5cfdb92b4ac7df8c2c3d891797787081c1ca2 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 22 May 2020 11:08:44 +0200 Subject: [PATCH 101/142] Add doubled isolated pawn penalty. This patch gives an additional penalty if a doubled isolated pawn is stopped only by a single opponent pawn on the same file. Thanks to NKONSTANTAKIS, who shared this idea on the forum! https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/vC4Qn-PMlS4. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 84872 W: 16688 L: 16370 D: 51814 Ptnml(0-2): 1507, 9940, 19274, 10158, 1557 https://tests.stockfishchess.org/tests/view/5ec65bd955202b947dc5d4ac LTC: LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 58104 W: 7614 L: 7278 D: 43212 Ptnml(0-2): 411, 5369, 17196, 5625, 451 https://tests.stockfishchess.org/tests/view/5ec6e9f2c23f5b0710632b19 Closes https://github.com/official-stockfish/Stockfish/pull/2694 Bench: 5148950 --- src/pawns.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7b266e77..c20cb529 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,12 +32,13 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); - constexpr Score Doubled = S(11, 56); - constexpr Score Isolated = S( 5, 15); - constexpr Score WeakLever = S( 0, 56); - constexpr Score WeakUnopposed = S(13, 27); + constexpr Score Backward = S( 9, 24); + constexpr Score BlockedStorm = S(82, 82); + constexpr Score Doubled = S(11, 56); + constexpr Score DoubledIsolated = S(15, 57); + constexpr Score Isolated = S( 5, 15); + constexpr Score WeakLever = S( 0, 56); + constexpr Score WeakUnopposed = S(13, 27); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -144,9 +145,16 @@ namespace { } else if (!neighbours) + { score -= Isolated + WeakUnopposed * !opposed; + if ( (ourPawns & forward_file_bb(Them, s)) + && popcount(opposed) == 1 + && !(theirPawns & adjacent_files_bb(s))) + score -= DoubledIsolated; + } + else if (backward) score -= Backward + WeakUnopposed * !opposed; From 669b5d83ef1d930c80854236f324de2fdcecf57c Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 21 May 2020 08:25:37 +0200 Subject: [PATCH 102/142] Improve CI testing also enable CXXFLAGS="-D_GLIBCXX_DEBUG" in CI. closes https://github.com/official-stockfish/Stockfish/pull/2692 No functional change. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e2b42e6d..e2ae61be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: - echo "Reference bench:" $benchref # # Verify bench number against various builds - - export CXXFLAGS=-Werror + - export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG" - make clean && make -j2 ARCH=x86-64 optimize=no debug=yes build && ../tests/signature.sh $benchref - make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref - make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref From d940e59dad51e78d5146bb21c8f792379df64816 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 21 May 2020 21:17:21 +0100 Subject: [PATCH 103/142] Keep low ply history from previous move This patch keeps the low-ply history from the previous move, shifting the data down by 2 ply. Tested with closedpos book: STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 71584 W: 14175 L: 13891 D: 43518 Ptnml(0-2): 1069, 8228, 16993, 8354, 1148 https://tests.stockfishchess.org/tests/view/5ec0eaafe9d85f94dc429974 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 96552 W: 13946 L: 13498 D: 69108 Ptnml(0-2): 676, 9082, 28375, 9404, 739 https://tests.stockfishchess.org/tests/view/5ec145efe9d85f94dc4299b0 closes https://github.com/official-stockfish/Stockfish/pull/2688 Bench 5148950 --- src/search.cpp | 3 +++ src/thread.cpp | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7f29f771..5e9cd463 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -357,6 +357,9 @@ void Thread::search() { mainThread->iterValue[i] = mainThread->bestPreviousScore; } + std::copy(&lowPlyHistory[2][0], &lowPlyHistory.back().back() + 1, &lowPlyHistory[0][0]); + std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); + size_t multiPV = Options["MultiPV"]; // Pick integer skill levels, but non-deterministically round up or down diff --git a/src/thread.cpp b/src/thread.cpp index 88331f06..2e0c216e 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -212,7 +212,6 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); - th->lowPlyHistory.fill(0); } setupStates->back() = tmp; From 383b12e1a5cc03a122e9a071eebde87eac85b116 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 23 May 2020 13:26:13 +0200 Subject: [PATCH 104/142] small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2653 No functional change --- src/bitboard.cpp | 2 +- src/evaluate.cpp | 2 +- src/main.cpp | 2 +- src/movegen.cpp | 44 ++++++++++++++++++++++++++++-------------- src/pawns.cpp | 5 ++--- src/position.cpp | 2 +- src/position.h | 7 +++---- src/search.cpp | 14 +++++++------- src/syzygy/tbprobe.cpp | 6 +++--- src/thread.cpp | 2 +- src/timeman.cpp | 12 ++++++------ src/tt.cpp | 6 +++--- src/tune.cpp | 6 +++--- src/ucioption.cpp | 4 ++-- 14 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 69bbc77b..f650eef6 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -69,7 +69,7 @@ const std::string Bitboards::pretty(Bitboard b) { void Bitboards::init() { for (unsigned i = 0; i < (1 << 16); ++i) - PopCnt16[i] = std::bitset<16>(i).count(); + PopCnt16[i] = uint8_t(std::bitset<16>(i).count()); for (Square s = SQ_A1; s <= SQ_H8; ++s) SquareBB[s] = (1ULL << s); diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e80e9442..2d1f4b9e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -311,7 +311,7 @@ namespace { if (Pt == BISHOP) { - // Penalty according to number of pawns on the same color square as the + // Penalty according to the number of our pawns on the same color square as the // bishop, bigger when the center files are blocked with pawns and smaller // when the bishop is outside the pawn chain. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); diff --git a/src/main.cpp b/src/main.cpp index 6eeda66d..fafefee2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { Position::init(); Bitbases::init(); Endgames::init(); - Threads.set(Options["Threads"]); + Threads.set(size_t(Options["Threads"])); Search::clear(); // After threads are up UCI::loop(argc, argv); diff --git a/src/movegen.cpp b/src/movegen.cpp index a3abcde8..5787d174 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -213,8 +213,31 @@ namespace { template - ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { + ExtMove* generate_all(const Position& pos, ExtMove* moveList) { constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations + Bitboard target; + + switch (Type) + { + case CAPTURES: + target = pos.pieces(~Us); + break; + case QUIETS: + case QUIET_CHECKS: + target = ~pos.pieces(); + break; + case EVASIONS: + { + Square checksq = lsb(pos.checkers()); + target = between_bb(pos.square(Us), checksq) | checksq; + break; + } + case NON_EVASIONS: + target = ~pos.pieces(Us); + break; + default: + static_assert(true, "Unsupported type in generate_all()"); + } moveList = generate_pawn_moves(pos, moveList, target); moveList = generate_moves(pos, moveList, Us, target); @@ -255,12 +278,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Color us = pos.side_to_move(); - Bitboard target = Type == CAPTURES ? pos.pieces(~us) - : Type == QUIETS ? ~pos.pieces() - : Type == NON_EVASIONS ? ~pos.pieces(us) : 0; - - return us == WHITE ? generate_all(pos, moveList, target) - : generate_all(pos, moveList, target); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } // Explicit template instantiations @@ -293,8 +312,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { *moveList++ = make_move(from, pop_lsb(&b)); } - return us == WHITE ? generate_all(pos, moveList, ~pos.pieces()) - : generate_all(pos, moveList, ~pos.pieces()); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } @@ -325,11 +344,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { return moveList; // Double check, only a king move can save the day // Generate blocking evasions or captures of the checking piece - Square checksq = lsb(pos.checkers()); - Bitboard target = between_bb(checksq, ksq) | checksq; - - return us == WHITE ? generate_all(pos, moveList, target) - : generate_all(pos, moveList, target); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } diff --git a/src/pawns.cpp b/src/pawns.cpp index c20cb529..b883dda2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -87,6 +87,7 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); + e->blockedCount += popcount(shift(ourPawns) & (theirPawns | doubleAttackThem)); // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -106,8 +107,6 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount += blocked || more_than_one(leverPush); - // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. backward = !(neighbours & forward_ranks_bb(Them, s + Up)) @@ -216,7 +215,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = File(edge_distance(f)); + int d = edge_distance(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/position.cpp b/src/position.cpp index 40ebb959..f5ff3da1 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -591,7 +591,7 @@ bool Position::pseudo_legal(const Move m) const { if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture && !((from + pawn_push(us) == to) && empty(to)) // Not a single push && !( (from + 2 * pawn_push(us) == to) // Not a double push - && (rank_of(from) == relative_rank(us, RANK_2)) + && (relative_rank(us, from) == RANK_2) && empty(to) && empty(to - pawn_push(us)))) return false; diff --git a/src/position.h b/src/position.h index 34a6abc3..ae624926 100644 --- a/src/position.h +++ b/src/position.h @@ -98,7 +98,7 @@ public: bool is_on_semiopen_file(Color c, Square s) const; // Castling - int castling_rights(Color c) const; + CastlingRights castling_rights(Color c) const; bool can_castle(CastlingRights cr) const; bool castling_impeded(CastlingRights cr) const; Square castling_rook_square(CastlingRights cr) const; @@ -268,7 +268,7 @@ inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } -inline int Position::castling_rights(Color c) const { +inline CastlingRights Position::castling_rights(Color c) const { return c & CastlingRights(st->castlingRights); } @@ -399,8 +399,7 @@ inline Thread* Position::this_thread() const { inline void Position::put_piece(Piece pc, Square s) { board[s] = pc; - byTypeBB[ALL_PIECES] |= s; - byTypeBB[type_of(pc)] |= s; + byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s; byColorBB[color_of(pc)] |= s; index[s] = pieceCount[pc]++; pieceList[pc][index[s]] = s; diff --git a/src/search.cpp b/src/search.cpp index 5e9cd463..3b3c0f2a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -272,9 +272,9 @@ void MainThread::search() { Thread* bestThread = this; // Check if there are threads with a better score than main thread - if ( Options["MultiPV"] == 1 + if ( int(Options["MultiPV"]) == 1 && !Limits.depth - && !(Skill(Options["Skill Level"]).enabled() || Options["UCI_LimitStrength"]) + && !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) && rootMoves[0].pv[0] != MOVE_NONE) { std::map votes; @@ -350,17 +350,17 @@ void Thread::search() { if (mainThread) { if (mainThread->bestPreviousScore == VALUE_INFINITE) - for (int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) mainThread->iterValue[i] = VALUE_ZERO; else - for (int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) mainThread->iterValue[i] = mainThread->bestPreviousScore; } std::copy(&lowPlyHistory[2][0], &lowPlyHistory.back().back() + 1, &lowPlyHistory[0][0]); std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); - size_t multiPV = Options["MultiPV"]; + size_t multiPV = size_t(Options["MultiPV"]); // Pick integer skill levels, but non-deterministically round up or down // such that the average integer skill corresponds to the input floating point one. @@ -540,8 +540,8 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; + double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index adc45d58..6bfd78ad 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -530,7 +530,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) { // I(k) = k * d->span + d->span / 2 (1) // First step is to get the 'k' of the I(k) nearest to our idx, using definition (1) - uint32_t k = idx / d->span; + uint32_t k = uint32_t(idx / d->span); // Then we read the corresponding SparseIndex[] entry uint32_t block = number(&d->sparseIndex[k].block); @@ -576,7 +576,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) { // All the symbols of a given length are consecutive integers (numerical // sequence property), so we can compute the offset of our symbol of // length len, stored at the beginning of buf64. - sym = (buf64 - d->base64[len]) >> (64 - len - d->minSymLen); + sym = Sym((buf64 - d->base64[len]) >> (64 - len - d->minSymLen)); // Now add the value of the lowest symbol of length len to get our symbol sym += number(&d->lowestSym[len]); @@ -984,7 +984,7 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) { d->sizeofBlock = 1ULL << *data++; d->span = 1ULL << *data++; - d->sparseIndexSize = (tbSize + d->span - 1) / d->span; // Round up + d->sparseIndexSize = size_t((tbSize + d->span - 1) / d->span); // Round up auto padding = number(data++); d->blocksNum = number(data); data += sizeof(uint32_t); d->blockLengthSize = d->blocksNum + padding; // Padded to ensure SparseIndex[] diff --git a/src/thread.cpp b/src/thread.cpp index 2e0c216e..c1713122 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -151,7 +151,7 @@ void ThreadPool::set(size_t requested) { clear(); // Reallocate the hash with the new threadpool size - TT.resize(Options["Hash"]); + TT.resize(size_t(Options["Hash"])); // Init thread number dependent search params. Search::init(); diff --git a/src/timeman.cpp b/src/timeman.cpp index 45e9db58..1f598745 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -35,10 +35,10 @@ TimeManagement Time; // Our global time management object void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { - TimePoint minThinkingTime = Options["Minimum Thinking Time"]; - TimePoint moveOverhead = Options["Move Overhead"]; - TimePoint slowMover = Options["Slow Mover"]; - TimePoint npmsec = Options["nodestime"]; + TimePoint minThinkingTime = TimePoint(Options["Minimum Thinking Time"]); + TimePoint moveOverhead = TimePoint(Options["Move Overhead"]); + TimePoint slowMover = TimePoint(Options["Slow Mover"]); + TimePoint npmsec = TimePoint(Options["nodestime"]); // opt_scale is a percentage of available time to use for the current move. // max_scale is a multiplier applied to optimumTime. @@ -91,8 +91,8 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { } // Never use more than 80% of the available time for this move - optimumTime = std::max(minThinkingTime, opt_scale * timeLeft); - maximumTime = std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime); + optimumTime = std::max(minThinkingTime, TimePoint(opt_scale * timeLeft)); + maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime)); if (Options["Ponder"]) optimumTime += optimumTime / 4; diff --git a/src/tt.cpp b/src/tt.cpp index 4e06bed9..0a3c54a1 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -94,8 +94,8 @@ void TranspositionTable::clear() { WinProcGroup::bindThisThread(idx); // Each thread will zero its part of the hash table - const size_t stride = clusterCount / Options["Threads"], - start = stride * idx, + const size_t stride = size_t(clusterCount / Options["Threads"]), + start = size_t(stride * idx), len = idx != Options["Threads"] - 1 ? stride : clusterCount - start; @@ -103,7 +103,7 @@ void TranspositionTable::clear() { }); } - for (std::thread& th: threads) + for (std::thread& th : threads) th.join(); } diff --git a/src/tune.cpp b/src/tune.cpp index fe61151f..696b4cb8 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -83,7 +83,7 @@ template<> void Tune::Entry::init_option() { make_option(name, value, range template<> void Tune::Entry::read_option() { if (Options.count(name)) - value = Options[name]; + value = int(Options[name]); } template<> void Tune::Entry::init_option() { make_option(name, value, range); } @@ -100,10 +100,10 @@ template<> void Tune::Entry::init_option() { template<> void Tune::Entry::read_option() { if (Options.count("m" + name)) - value = make_score(Options["m" + name], eg_value(value)); + value = make_score(int(Options["m" + name]), eg_value(value)); if (Options.count("e" + name)) - value = make_score(mg_value(value), Options["e" + name]); + value = make_score(mg_value(value), int(Options["e" + name])); } // Instead of a variable here we have a PostUpdate function: just call it diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 66fd42d1..16add76e 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -38,9 +38,9 @@ namespace UCI { /// 'On change' actions, triggered by an option's value change void on_clear_hash(const Option&) { Search::clear(); } -void on_hash_size(const Option& o) { TT.resize(o); } +void on_hash_size(const Option& o) { TT.resize(size_t(o)); } void on_logger(const Option& o) { start_logger(o); } -void on_threads(const Option& o) { Threads.set(o); } +void on_threads(const Option& o) { Threads.set(size_t(o)); } void on_tb_path(const Option& o) { Tablebases::init(o); } From 86575bcdd88f6d211b4f182966e44a40faf1e315 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 23 May 2020 12:22:34 +0300 Subject: [PATCH 105/142] Queen Mobility Tweak It's ok to have low mobility values for the Queen in the middlegame, but it's absolutely not ok to have low mobility values for the Queen in the endgame. Decrease penalty for bad mobility in MG and increase it in EG. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 17264 W: 3424 L: 3206 D: 10634 Ptnml(0-2): 279, 2004, 3893, 2132, 324 https://tests.stockfishchess.org/tests/view/5ec8f9c1526edcbe9091eba1 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 175016 W: 22071 L: 21404 D: 131541 Ptnml(0-2): 1195, 15796, 52914, 16353, 1250 https://tests.stockfishchess.org/tests/view/5ec9057c404591b2793007df closes https://github.com/official-stockfish/Stockfish/pull/2697 Bench: 4487054 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2d1f4b9e..7aa67f26 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -99,7 +99,7 @@ namespace { { S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164), S( 57,168), S( 57,169), S( 62,172) }, - { S(-34,-36), S(-15,-21), S(-10, -1), S(-10, 22), S( 20, 41), S( 23, 56), // Queen + { S(-30,-48), S(-12,-30), S( -8, -7), S( -9, 19), S( 20, 40), S( 23, 55), // Queen S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100), S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141), S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171), From 81c58855e43572e5493497a9894ac5060936005c Mon Sep 17 00:00:00 2001 From: ElbertoOne Date: Sat, 23 May 2020 13:14:02 +0200 Subject: [PATCH 106/142] Remove and replace DoubledIsolated penalty by Doubled The values for both penalties were very close, so DoubledIsolated can be removed and replaced by Doubled. Passed STC (simplification): https://tests.stockfishchess.org/tests/view/5ec7c18e2a585b485af54407 LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 105360 W: 20175 L: 20136 D: 65049 Ptnml(0-2): 1803, 12230, 24572, 12275, 1800 Passed LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 15440 W: 1978 L: 1877 D: 11585 Ptnml(0-2): 92, 1405, 4667, 1422, 134 closes https://github.com/official-stockfish/Stockfish/pull/2696 Bench: 4668875 --- src/pawns.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index b883dda2..f9dbcae2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,13 +32,12 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); - constexpr Score Doubled = S(11, 56); - constexpr Score DoubledIsolated = S(15, 57); - constexpr Score Isolated = S( 5, 15); - constexpr Score WeakLever = S( 0, 56); - constexpr Score WeakUnopposed = S(13, 27); + constexpr Score Backward = S( 9, 24); + constexpr Score BlockedStorm = S(82, 82); + constexpr Score Doubled = S(11, 56); + constexpr Score Isolated = S( 5, 15); + constexpr Score WeakLever = S( 0, 56); + constexpr Score WeakUnopposed = S(13, 27); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -151,7 +150,7 @@ namespace { if ( (ourPawns & forward_file_bb(Them, s)) && popcount(opposed) == 1 && !(theirPawns & adjacent_files_bb(s))) - score -= DoubledIsolated; + score -= Doubled; } else if (backward) From 7f2c8a2b81af19033a62845408b7ae19ed513053 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 24 May 2020 01:54:37 +0200 Subject: [PATCH 107/142] Remove attacked pawns from storm evaluation STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 54456 W: 11009 L: 10737 D: 32710 Ptnml(0-2): 929, 6326, 12523, 6444, 1006 https://tests.stockfishchess.org/tests/view/5ec962e4404591b2793008a5 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 62448 W: 9018 L: 8664 D: 44766 Ptnml(0-2): 462, 5928, 18121, 6220, 493 https://tests.stockfishchess.org/tests/view/5ec976a8a586eee45aa2ab40 Non regression STC with "noob_3moves.epd" opening book LLR: 3.81 (-2.94,2.94) {-1.50,0.50} Total: 91896 W: 17770 L: 17653 D: 56473 Ptnml(0-2): 1598, 10782, 21124, 10793, 1651 https://tests.stockfishchess.org/tests/view/5ec9b83ea586eee45aa2ab96 closes https://github.com/official-stockfish/Stockfish/pull/2698 Bench 4488597 --- src/pawns.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index f9dbcae2..8354cc15 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -33,12 +33,13 @@ namespace { // Pawn penalties constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); constexpr Score WeakLever = S( 0, 56); constexpr Score WeakUnopposed = S(13, 27); + constexpr Score BlockedStorm[RANK_NB] = {S( 0, 0), S( 0, 0), S( 76, 78), S(-10, 15), S(-7, 10), S(-4, 6), S(-1, 2)}; + // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -200,8 +201,8 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { constexpr Color Them = ~Us; Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); - Bitboard ourPawns = b & pos.pieces(Us); - Bitboard theirPawns = b & pos.pieces(Them); + Bitboard ourPawns = b & pos.pieces(Us) & ~pawnAttacks[Them]; + Bitboard theirPawns = b & pos.pieces(Them) & ~pawnAttacks[Us]; Score bonus = make_score(5, 5); @@ -218,7 +219,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) - bonus -= BlockedStorm * int(theirRank == RANK_3); + bonus -= BlockedStorm[theirRank]; else bonus -= make_score(UnblockedStorm[d][theirRank], 0); } From d40d04c17ceadff6f15d1cb1d4d469f823a35a02 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 25 May 2020 21:14:07 +0300 Subject: [PATCH 108/142] Give bonus for rooks that are alligned with enemy kingring The idea of this patch is that if rooks are not directly attacking the opponent king, they can support king attacks staying behind pawns or minor pieces and be really deadly if position slightly opens up at enemy king ring ranks. Loosely based on some stockfish games where it underestimated attacks on it king when enemy has one or two rooks supporting pawn pushes towards it king. passed STC https://tests.stockfishchess.org/tests/view/5ecb093680f2c838b96550f9 LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 53672 W: 10535 L: 10265 D: 32872 Ptnml(0-2): 952, 6210, 12258, 6448, 968 passed LTC https://tests.stockfishchess.org/tests/view/5ecb639f80f2c838b9655117 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 62424 W: 8094 L: 7748 D: 46582 Ptnml(0-2): 426, 5734, 18565, 6042, 445 closes https://github.com/official-stockfish/Stockfish/pull/2700 Bench: 4663220 --- src/evaluate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7aa67f26..8e8cc091 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -143,6 +143,7 @@ namespace { constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); + constexpr Score RookOnKingRing = S( 16, 0); constexpr Score RookOnQueenFile = S( 5, 9); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); @@ -287,6 +288,8 @@ namespace { kingAttackersWeight[Us] += KingAttackWeights[Pt]; kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } + else if (Pt == ROOK && (file_bb(s) & kingRing[Them])) + score += RookOnKingRing; int mob = popcount(b & mobilityArea[Us]); From fb8095718bd0789d2743fa6216c6aa522555dc4b Mon Sep 17 00:00:00 2001 From: xoto10 Date: Tue, 26 May 2020 00:27:05 +0100 Subject: [PATCH 109/142] In BlockedStorm, theirPawns includes ones attacked by us. Pawns heading towards our king tend to be dangerous whether or not we are attacking them so remove this test. STC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 91184 W: 18196 L: 18137 D: 54851 Ptnml(0-2): 1580, 10656, 21092, 10653, 1611 https://tests.stockfishchess.org/tests/view/5ecc3f7080f2c838b9655841 LTC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 14152 W: 2045 L: 1937 D: 10170 Ptnml(0-2): 99, 1325, 4130, 1413, 109 https://tests.stockfishchess.org/tests/view/5ecc4f3180f2c838b9655861 closes https://github.com/official-stockfish/Stockfish/pull/2702 Bench 4828973 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 8354cc15..3ce89630 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -202,7 +202,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us) & ~pawnAttacks[Them]; - Bitboard theirPawns = b & pos.pieces(Them) & ~pawnAttacks[Us]; + Bitboard theirPawns = b & pos.pieces(Them); Score bonus = make_score(5, 5); From a5e3b4eddede900c1df610e8e25026a79d706500 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 28 May 2020 09:48:31 -0600 Subject: [PATCH 110/142] Consolidate all attacks bitboards This is a non-functional simplification that simplifies getting attacks bitboards. * consolidates all attacks to attacks_bb (remove Position::attacks_from(..)). * attacks_bb(square) gets pseudo attacks * attacks_bb(square, bitboard) gets attacks considering occupied squares in the bitboard). * pawn_attacks_bb(Color, Square) gets pawn attacks like other pawn attack bitboards. * Wraps all access to PawnAttacks arrays and PseudoAttacks arrays and adds asserts as appropriate. Passed STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 90208 W: 17533 L: 17482 D: 55193 Ptnml(0-2): 1412, 10232, 21798, 10217, 1445 https://tests.stockfishchess.org/tests/view/5ece996275787cc0c05d9790 closes https://github.com/official-stockfish/Stockfish/pull/2703 No functional change --- src/bitbase.cpp | 10 +++++----- src/bitboard.h | 35 ++++++++++++++++++++++++++++++----- src/endgame.cpp | 10 +++++----- src/evaluate.cpp | 16 ++++++++-------- src/movegen.cpp | 20 ++++++++++---------- src/pawns.cpp | 6 +++--- src/position.cpp | 30 +++++++++++++++--------------- src/position.h | 21 --------------------- 8 files changed, 76 insertions(+), 72 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index bef2dc49..be6f0d0a 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -112,7 +112,7 @@ namespace { if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 || ksq[WHITE] == psq || ksq[BLACK] == psq - || (stm == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) + || (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK]))) result = INVALID; // Immediate win if a pawn can be promoted without getting captured @@ -120,13 +120,13 @@ namespace { && rank_of(psq) == RANK_7 && ksq[stm] != psq + NORTH && ( distance(ksq[~stm], psq + NORTH) > 1 - || (PseudoAttacks[KING][ksq[stm]] & (psq + NORTH)))) + || (attacks_bb(ksq[stm]) & (psq + NORTH)))) result = WIN; // Immediate draw if it is a stalemate or a king captures undefended pawn else if ( stm == BLACK - && ( !(PseudoAttacks[KING][ksq[stm]] & ~(PseudoAttacks[KING][ksq[~stm]] | PawnAttacks[~stm][psq])) - || (PseudoAttacks[KING][ksq[stm]] & psq & ~PseudoAttacks[KING][ksq[~stm]]))) + && ( !(attacks_bb(ksq[stm]) & ~(attacks_bb(ksq[~stm]) | pawn_attacks_bb(~stm, psq))) + || (attacks_bb(ksq[stm]) & psq & ~attacks_bb(ksq[~stm])))) result = DRAW; // Position will be classified later @@ -149,7 +149,7 @@ namespace { const Result Bad = (stm == WHITE ? DRAW : WIN); Result r = INVALID; - Bitboard b = PseudoAttacks[KING][ksq[stm]]; + Bitboard b = attacks_bb(ksq[stm]); while (b) r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)] diff --git a/src/bitboard.h b/src/bitboard.h index 9252c3dc..93f838f8 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -176,6 +176,12 @@ constexpr Bitboard pawn_attacks_bb(Bitboard b) { : shift(b) | shift(b); } +inline Bitboard pawn_attacks_bb(Color c, Square s) { + + assert(is_ok(s)); + return PawnAttacks[c][s]; +} + /// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the /// given color from the squares in the given bitboard. @@ -266,19 +272,38 @@ inline Bitboard safe_destination(Square s, int step) return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); } -/// attacks_bb() returns a bitboard representing all the squares attacked by a -/// piece of type Pt (bishop or rook) placed on 's'. +/// attacks_bb(Square) returns the pseudo attacks of the give piece type +/// assuming an empty board. + +template +inline Bitboard attacks_bb(Square s) { + + assert((Pt != PAWN) && (is_ok(s))); + + return PseudoAttacks[Pt][s]; +} + +/// attacks_bb(Square, Bitboard) returns the attacks by the given piece +/// assuming the board is occupied according to the passed Bitboard. +/// Sliding piece attacks do not continue passed an occupied square. template inline Bitboard attacks_bb(Square s, Bitboard occupied) { - const Magic& m = Pt == ROOK ? RookMagics[s] : BishopMagics[s]; - return m.attacks[m.index(occupied)]; + assert((Pt != PAWN) && (is_ok(s))); + + switch (Pt) + { + case BISHOP: return BishopMagics[s].attacks[BishopMagics[s].index(occupied)]; + case ROOK : return RookMagics[s].attacks[ RookMagics[s].index(occupied)]; + case QUEEN : return attacks_bb(s, occupied) | attacks_bb(s, occupied); + default : return PseudoAttacks[Pt][s]; + } } inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) { - assert(pt != PAWN); + assert((pt != PAWN) && (is_ok(s))); switch (pt) { diff --git a/src/endgame.cpp b/src/endgame.cpp index e232da62..7b9c145e 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -391,8 +391,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && relative_rank(weakSide, pos.square(strongSide)) >= RANK_4 && relative_rank(weakSide, rsq) == RANK_3 && ( pos.pieces(weakSide, PAWN) - & pos.attacks_from(kingSq) - & pos.attacks_from(rsq, strongSide))) + & attacks_bb(kingSq) + & pawn_attacks_bb(strongSide, rsq))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -535,7 +535,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // the corner if ( rk == RANK_6 && distance(psq + 2 * push, ksq) <= 1 - && (PseudoAttacks[BISHOP][bsq] & (psq + push)) + && (attacks_bb(bsq) & (psq + push)) && distance(bsq, psq) >= 2) return ScaleFactor(8); } @@ -670,14 +670,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if ( ksq == blockSq1 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 - || (pos.attacks_from(blockSq2) & pos.pieces(weakSide, BISHOP)) + || (attacks_bb(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP)) || distance(psq1, psq2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq1 - || (pos.attacks_from(blockSq1) & pos.pieces(weakSide, BISHOP)))) + || (attacks_bb(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP)))) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8e8cc091..ad79db5c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -235,7 +235,7 @@ namespace { mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them)); // Initialize attackedBy[] for king and pawns - attackedBy[Us][KING] = pos.attacks_from(ksq); + attackedBy[Us][KING] = attacks_bb(ksq); attackedBy[Us][PAWN] = pe->pawn_attacks(Us); attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); @@ -243,7 +243,7 @@ namespace { // Init our king safety tables Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G), Utility::clamp(rank_of(ksq), RANK_2, RANK_7)); - kingRing[Us] = PseudoAttacks[KING][s] | s; + kingRing[Us] = attacks_bb(s) | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -273,7 +273,7 @@ namespace { // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK)) - : pos.attacks_from(s); + : attacks_bb(s, pos.pieces()); if (pos.blockers_for_king(Us) & s) b &= LineBB[pos.square(Us)][s]; @@ -323,7 +323,7 @@ namespace { * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Penalty for all enemy pawns x-rayed - score -= BishopXRayPawns * popcount(PseudoAttacks[BISHOP][s] & pos.pieces(Them, PAWN)); + score -= BishopXRayPawns * popcount(attacks_bb(s) & pos.pieces(Them, PAWN)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) @@ -438,7 +438,7 @@ namespace { unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks - knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + knightChecks = attacks_bb(ksq) & attackedBy[Them][KNIGHT]; if (knightChecks & safe) kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100 : KnightSafeCheck; @@ -564,12 +564,12 @@ namespace { Square s = pos.square(Them); safe = mobilityArea[Us] & ~stronglyProtected; - b = attackedBy[Us][KNIGHT] & pos.attacks_from(s); + b = attackedBy[Us][KNIGHT] & attacks_bb(s); score += KnightOnQueen * popcount(b & safe); - b = (attackedBy[Us][BISHOP] & pos.attacks_from(s)) - | (attackedBy[Us][ROOK ] & pos.attacks_from(s)); + b = (attackedBy[Us][BISHOP] & attacks_bb(s, pos.pieces())) + | (attackedBy[Us][ROOK ] & attacks_bb(s, pos.pieces())); score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]); } diff --git a/src/movegen.cpp b/src/movegen.cpp index 5787d174..81b8c929 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -40,7 +40,7 @@ namespace { // Knight promotion is the only promotion that can give a direct check // that's not already included in the queen promotion. - if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq)) + if (Type == QUIET_CHECKS && (attacks_bb(to) & ksq)) *moveList++ = make(to - D, to, KNIGHT); else (void)ksq; // Silence a warning under MSVC @@ -84,8 +84,8 @@ namespace { if (Type == QUIET_CHECKS) { - b1 &= pos.attacks_from(ksq, Them); - b2 &= pos.attacks_from(ksq, Them); + b1 &= pawn_attacks_bb(Them, ksq); + b2 &= pawn_attacks_bb(Them, ksq); // Add pawn pushes which give discovered check. This is possible only // if the pawn is not on the same file as the enemy king, because we @@ -166,7 +166,7 @@ namespace { if (Type == EVASIONS && !(target & (pos.ep_square() - Up))) return moveList; - b1 = pawnsNotOn7 & pos.attacks_from(pos.ep_square(), Them); + b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square()); assert(b1); @@ -192,14 +192,14 @@ namespace { if (Checks) { if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) - && !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt))) + && !(attacks_bb(from) & target & pos.check_squares(Pt))) continue; if (pos.blockers_for_king(~us) & from) continue; } - Bitboard b = pos.attacks_from(from) & target; + Bitboard b = attacks_bb(from, pos.pieces()) & target; if (Checks) b &= pos.check_squares(Pt); @@ -248,7 +248,7 @@ namespace { if (Type != QUIET_CHECKS && Type != EVASIONS) { Square ksq = pos.square(Us); - Bitboard b = pos.attacks_from(ksq) & target; + Bitboard b = attacks_bb(ksq) & target; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); @@ -303,10 +303,10 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Square from = pop_lsb(&dc); PieceType pt = type_of(pos.piece_on(from)); - Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces(); + Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces(); if (pt == KING) - b &= ~PseudoAttacks[QUEEN][pos.square(~us)]; + b &= ~attacks_bb(pos.square(~us)); while (b) *moveList++ = make_move(from, pop_lsb(&b)); @@ -336,7 +336,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers(); // Generate evasions for king, capture and non capture moves - Bitboard b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; + Bitboard b = attacks_bb(ksq) & ~pos.pieces(us) & ~sliderAttacks; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); diff --git a/src/pawns.cpp b/src/pawns.cpp index 3ce89630..467137b3 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -100,8 +100,8 @@ namespace { opposed = theirPawns & forward_file_bb(Us, s); blocked = theirPawns & (s + Up); stoppers = theirPawns & passed_pawn_span(Us, s); - lever = theirPawns & PawnAttacks[Us][s]; - leverPush = theirPawns & PawnAttacks[Us][s + Up]; + lever = theirPawns & pawn_attacks_bb(Us, s); + leverPush = theirPawns & pawn_attacks_bb(Us, s + Up); doubled = ourPawns & (s - Up); neighbours = ourPawns & adjacent_files_bb(s); phalanx = neighbours & rank_bb(s); @@ -253,7 +253,7 @@ Score Entry::do_king_safety(const Position& pos) { Bitboard pawns = pos.pieces(Us, PAWN); int minPawnDist = 6; - if (pawns & PseudoAttacks[KING][ksq]) + if (pawns & attacks_bb(ksq)) minPawnDist = 1; else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); diff --git a/src/position.cpp b/src/position.cpp index f5ff3da1..d2e33b30 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -139,7 +139,7 @@ void Position::init() { for (Piece pc : Pieces) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2) - if (PseudoAttacks[type_of(pc)][s1] & s2) + if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2)) { Move move = make_move(s1, s2); Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side; @@ -319,10 +319,10 @@ void Position::set_check_info(StateInfo* si) const { Square ksq = square(~sideToMove); - si->checkSquares[PAWN] = attacks_from(ksq, ~sideToMove); - si->checkSquares[KNIGHT] = attacks_from(ksq); - si->checkSquares[BISHOP] = attacks_from(ksq); - si->checkSquares[ROOK] = attacks_from(ksq); + si->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq); + si->checkSquares[KNIGHT] = attacks_bb(ksq); + si->checkSquares[BISHOP] = attacks_bb(ksq, pieces()); + si->checkSquares[ROOK] = attacks_bb(ksq, pieces()); si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK]; si->checkSquares[KING] = 0; } @@ -455,8 +455,8 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners pinners = 0; // Snipers are sliders that attack 's' when a piece and other snipers are removed - Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) - | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; + Bitboard snipers = ( (attacks_bb< ROOK>(s) & pieces(QUEEN, ROOK)) + | (attacks_bb(s) & pieces(QUEEN, BISHOP))) & sliders; Bitboard occupancy = pieces() ^ snipers; while (snipers) @@ -480,12 +480,12 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners Bitboard Position::attackers_to(Square s, Bitboard occupied) const { - return (attacks_from(s, BLACK) & pieces(WHITE, PAWN)) - | (attacks_from(s, WHITE) & pieces(BLACK, PAWN)) - | (attacks_from(s) & pieces(KNIGHT)) + return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN)) + | (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN)) + | (attacks_bb(s) & pieces(KNIGHT)) | (attacks_bb< ROOK>(s, occupied) & pieces( ROOK, QUEEN)) | (attacks_bb(s, occupied) & pieces(BISHOP, QUEEN)) - | (attacks_from(s) & pieces(KING)); + | (attacks_bb(s) & pieces(KING)); } @@ -588,7 +588,7 @@ bool Position::pseudo_legal(const Move m) const { if ((Rank8BB | Rank1BB) & to) return false; - if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture + if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture && !((from + pawn_push(us) == to) && empty(to)) // Not a single push && !( (from + 2 * pawn_push(us) == to) // Not a double push && (relative_rank(us, from) == RANK_2) @@ -596,7 +596,7 @@ bool Position::pseudo_legal(const Move m) const { && empty(to - pawn_push(us)))) return false; } - else if (!(attacks_from(type_of(pc), from) & to)) + else if (!(attacks_bb(type_of(pc), from, pieces()) & to)) return false; // Evasions generator already takes care to avoid some kind of illegal moves @@ -670,7 +670,7 @@ bool Position::gives_check(Move m) const { Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); - return (PseudoAttacks[ROOK][rto] & square(~sideToMove)) + return (attacks_bb(rto) & square(~sideToMove)) && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square(~sideToMove)); } default: @@ -794,7 +794,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { { // Set en-passant square if the moved pawn can be captured if ( (int(to) ^ int(from)) == 16 - && (attacks_from(to - pawn_push(us), us) & pieces(them, PAWN))) + && (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN))) { st->epSquare = to - pawn_push(us); k ^= Zobrist::enpassant[file_of(st->epSquare)]; diff --git a/src/position.h b/src/position.h index ae624926..8f8c8f7a 100644 --- a/src/position.h +++ b/src/position.h @@ -112,9 +112,6 @@ public: // Attacks to/from a given square Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s, Bitboard occupied) const; - Bitboard attacks_from(PieceType pt, Square s) const; - template Bitboard attacks_from(Square s) const; - template Bitboard attacks_from(Square s, Color c) const; Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; // Properties of moves @@ -284,24 +281,6 @@ inline Square Position::castling_rook_square(CastlingRights cr) const { return castlingRookSquare[cr]; } -template -inline Bitboard Position::attacks_from(Square s) const { - static_assert(Pt != PAWN, "Pawn attacks need color"); - - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, pieces()) - : Pt == QUEEN ? attacks_from(s) | attacks_from(s) - : PseudoAttacks[Pt][s]; -} - -template<> -inline Bitboard Position::attacks_from(Square s, Color c) const { - return PawnAttacks[c][s]; -} - -inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, pieces()); -} - inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, pieces()); } From 616eb60008308f686930c0c94116aab170398dc1 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 28 May 2020 22:34:43 +0200 Subject: [PATCH 111/142] Less pruning in draw PV lines. no futility pruning for certain captures if the PvNode has a draw eval. passed STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 59392 W: 11576 L: 11302 D: 36514 Ptnml(0-2): 977, 6816, 13920, 6922, 1061 https://tests.stockfishchess.org/tests/view/5ed0b1bb042fa6d77c355295 passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 64040 W: 8273 L: 7923 D: 47844 Ptnml(0-2): 424, 5842, 19220, 6028, 506 https://tests.stockfishchess.org/tests/view/5ed145e0042fa6d77c35531c closes https://github.com/official-stockfish/Stockfish/pull/2705 Bench: 4704615 --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index 3b3c0f2a..4747beb2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1055,6 +1055,7 @@ moves_loop: // When in check, search starts from here // Futility pruning for captures if ( !givesCheck && lmrDepth < 6 + && !(PvNode && abs(bestValue) < 2) && !ss->inCheck && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; From 8c3d9d996af7aa34f019785818eecbeb9338b95f Mon Sep 17 00:00:00 2001 From: ElbertoOne Date: Sun, 31 May 2020 16:39:03 +0200 Subject: [PATCH 112/142] Isolated pawns tweak Give opposed doubled isolated pawns only the Doubled penalty. The other isolated pawns get the Isolated penalty and the WeakUnopposed penalty. The popcount condition has been replaced with an opposed check, which is non-functional, but probably gives a speed-up. Passed STC (https://tests.stockfishchess.org/tests/view/5ed0f0f0042fa6d77c3552f5): LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 121832 W: 23562 L: 23195 D: 75075 Ptnml(0-2): 2092, 14064, 28313, 14279, 2168 LTC: (https://tests.stockfishchess.org/tests/view/5ed22e40042fa6d77c355387) LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 103368 W: 13232 L: 12768 D: 77368 Ptnml(0-2): 693, 9484, 30919, 9842, 746 closes https://github.com/official-stockfish/Stockfish/pull/2706 Bench: 4085694 --- src/pawns.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 467137b3..c1119a41 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -145,13 +145,13 @@ namespace { else if (!neighbours) { - score -= Isolated - + WeakUnopposed * !opposed; - - if ( (ourPawns & forward_file_bb(Them, s)) - && popcount(opposed) == 1 + if ( opposed + && (ourPawns & forward_file_bb(Them, s)) && !(theirPawns & adjacent_files_bb(s))) score -= Doubled; + else + score -= Isolated + + WeakUnopposed * !opposed; } else if (backward) From d1ec10cd4fe1e67114178f444cfebd2ff1183408 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 31 May 2020 17:00:47 +0200 Subject: [PATCH 113/142] Give bonus for bishops that are alligned with enemy kingring. Inspired by the succesful patch "Give bonus for rooks that are alligned with enemy kingring" from Vizvezdenec, this idea has been reused for bishops. Here, we only consider attacks that are not blocked by any pawn. Also we have a 50% higher bonus than for the rooks. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 68960 W: 13495 L: 13202 D: 42263 Ptnml(0-2): 1213, 8018, 15802, 8157, 1290 https://tests.stockfishchess.org/tests/view/5ed27495042fa6d77c3553aa LTC: LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 54560 W: 7105 L: 6780 D: 40675 Ptnml(0-2): 379, 4986, 16254, 5253, 408 https://tests.stockfishchess.org/tests/view/5ed30375596e6dc1e1f97425 closes https://github.com/official-stockfish/Stockfish/pull/2708 Bench: 4860021 --- src/evaluate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ad79db5c..dc7134a8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -128,6 +128,7 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@ -288,9 +289,13 @@ namespace { kingAttackersWeight[Us] += KingAttackWeights[Pt]; kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } + else if (Pt == ROOK && (file_bb(s) & kingRing[Them])) score += RookOnKingRing; + else if (Pt == BISHOP && (attacks_bb(s, pos.pieces(PAWN)) & kingRing[Them])) + score += BishopOnKingRing; + int mob = popcount(b & mobilityArea[Us]); mobility[Us] += MobilityBonus[Pt - 2][mob]; From 16566a8fcf76b9b72b6e746f318f77045df90017 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Tue, 2 Jun 2020 22:27:11 +0200 Subject: [PATCH 114/142] Singular quiet LMR If ttMove is a capture and had a singular extension, it is probably the best move. No need to make a decrease of LMR on other moves. STC LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 41968 W: 8170 L: 7918 D: 25880 Ptnml(0-2): 733, 4770, 9726, 5022, 733 https://tests.stockfishchess.org/tests/view/5ed6b666f29b40b0fc95a884 LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 71376 W: 9200 L: 8827 D: 53349 Ptnml(0-2): 486, 6544, 21342, 6743, 573 https://tests.stockfishchess.org/tests/view/5ed7578bf29b40b0fc95a8c9 closes https://github.com/official-stockfish/Stockfish/pull/2713 Bench: 4733799 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4747beb2..1e133447 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -630,7 +630,8 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; bool ttHit, ttPv, formerPv, givesCheck, improving, didLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, + ttCapture, singularQuietLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -971,7 +972,7 @@ moves_loop: // When in check, search starts from here depth > 12 ? ss->ply : MAX_PLY); value = bestValue; - singularLMR = moveCountPruning = false; + singularQuietLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); // Mark this node as being searched @@ -1092,7 +1093,7 @@ moves_loop: // When in check, search starts from here if (value < singularBeta) { extension = 1; - singularLMR = true; + singularQuietLMR = !ttCapture; } // Multi-cut pruning @@ -1198,7 +1199,7 @@ moves_loop: // When in check, search starts from here r--; // Decrease reduction if ttMove has been singularly extended (~3 Elo) - if (singularLMR) + if (singularQuietLMR) r -= 1 + formerPv; if (!captureOrPromotion) From 784263596ff9b01187341274b6f3cbd8971a2d2c Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 31 May 2020 16:51:38 +0200 Subject: [PATCH 115/142] Minimal thinking time, even if only one rootMove. without search, the eval returned can be misleading (e.g. mate instead of draw), leading to wrong adjudication. With a minimal search, this is avoided. This patch leads to 1ms long searches if there is only 1 move, similar patches all indicate a small Elo gain. Fixes https://github.com/official-stockfish/Stockfish/issues/2707 Passed non-regression STC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 22312 W: 4350 L: 4204 D: 13758 Ptnml(0-2): 323, 2488, 5437, 2536, 372 https://tests.stockfishchess.org/tests/view/5ed562b0f29b40b0fc95a7d0 closes https://github.com/official-stockfish/Stockfish/pull/2709 Bench: 4733799 --- src/search.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 1e133447..35110538 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -556,9 +556,11 @@ void Thread::search() { } double bestMoveInstability = 1 + totBestMoveChanges / Threads.size(); - // Stop the search if we have only one legal move, or if available time elapsed - if ( rootMoves.size() == 1 - || Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability) + double totalTime = rootMoves.size() == 1 ? 0 : + Time.optimum() * fallingEval * reduction * bestMoveInstability; + + // Stop the search if we have exceeded the totalTime, at least 1ms search. + if (Time.elapsed() > totalTime) { // If we are allowed to ponder do not stop the search now but // keep pondering until the GUI sends "ponderhit" or "stop". @@ -569,7 +571,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6) + && Time.elapsed() > totalTime * 0.6) Threads.increaseDepth = false; else Threads.increaseDepth = true; From fd8e88427b1268bfddc0b2ab72f639f758b7be0b Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 3 Jun 2020 18:06:49 -0600 Subject: [PATCH 116/142] small speed-up in movegen pass color as a template parameter. closes https://github.com/official-stockfish/Stockfish/pull/2715 No functional change. --- src/movegen.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 81b8c929..b57f41a9 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -179,13 +179,12 @@ namespace { } - template - ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, - Bitboard target) { + template + ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - const Square* pl = pos.squares(us); + const Square* pl = pos.squares(Us); for (Square from = *pl; from != SQ_NONE; from = *++pl) { @@ -195,7 +194,7 @@ namespace { && !(attacks_bb(from) & target & pos.check_squares(Pt))) continue; - if (pos.blockers_for_king(~us) & from) + if (pos.blockers_for_king(~Us) & from) continue; } @@ -240,10 +239,10 @@ namespace { } moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target); - moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); if (Type != QUIET_CHECKS && Type != EVASIONS) { From 15e190e9428b21fbfe29ce020c456077dc5fdd04 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Sat, 6 Jun 2020 12:56:38 +0200 Subject: [PATCH 117/142] Use lowply-history also on low depths STC: https://tests.stockfishchess.org/tests/view/5ed75078f29b40b0fc95a8b9 LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 73928 W: 14301 L: 14005 D: 45622 Ptnml(0-2): 1243, 8572, 17096, 8752, 1301 LTC: https://tests.stockfishchess.org/tests/view/5ed895e0f29b40b0fc95a976 LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 154848 W: 19684 L: 19074 D: 116090 Ptnml(0-2): 1048, 14108, 46627, 14468, 1173 closes https://github.com/official-stockfish/Stockfish/pull/2718 bench: 4582693 --- src/movepick.cpp | 2 +- src/search.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index e26f42ef..78102c52 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -110,7 +110,7 @@ void MovePicker::score() { + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] - + (ply < MAX_LPH ? 4 * (*lowPlyHistory)[ply][from_to(m)] : 0); + + (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0); else // Type == EVASIONS { diff --git a/src/search.cpp b/src/search.cpp index 35110538..efa7b9c5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -971,7 +971,7 @@ moves_loop: // When in check, search starts from here contHist, countermove, ss->killers, - depth > 12 ? ss->ply : MAX_PLY); + ss->ply); value = bestValue; singularQuietLMR = moveCountPruning = false; From 902309020a8ebf97a649cacfdc2dc2881b630966 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 3 Jun 2020 11:05:58 +0100 Subject: [PATCH 118/142] join scale_factor, initiative and mg+eg reduction Merging this code into one function `winnable()`. Should allow common concepts used to adjust the eg value, either by addition or scaling, to be combined more effectively. Improve trace function. closes https://github.com/official-stockfish/Stockfish/pull/2710 No functional change. --- src/evaluate.cpp | 54 ++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index dc7134a8..12a4c7bf 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -35,7 +35,7 @@ namespace Trace { enum Tracing { NO_TRACE, TRACE }; enum Term { // The first 8 entries are reserved for PieceType - MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, INITIATIVE, TOTAL, TERM_NB + MATERIAL = 8, IMBALANCE, MOBILITY, THREAT, PASSED, SPACE, WINNABLE, TOTAL, TERM_NB }; Score scores[TERM_NB][COLOR_NB]; @@ -59,7 +59,7 @@ namespace Trace { std::ostream& operator<<(std::ostream& os, Term t) { - if (t == MATERIAL || t == IMBALANCE || t == INITIATIVE || t == TOTAL) + if (t == MATERIAL || t == IMBALANCE || t == WINNABLE || t == TOTAL) os << " ---- ----" << " | " << " ---- ----"; else os << scores[t][WHITE] << " | " << scores[t][BLACK]; @@ -173,8 +173,7 @@ namespace { template Score threats() const; template Score passed() const; template Score space() const; - ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score) const; + Value winnable(Score score) const; const Position& pos; Material::Entry* me; @@ -717,12 +716,12 @@ namespace { } - // Evaluation::initiative() computes the initiative correction value - // for the position. It is a second order bonus/malus based on the + // Evaluation::winnable() adjusts the mg and eg score components based on the // known attacking/defending status of the players. + // A single value is derived from the mg and eg values and returned. template - Score Evaluation::initiative(Score score) const { + Value Evaluation::winnable(Score score) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -756,17 +755,10 @@ namespace { int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); - if (T) - Trace::add(INITIATIVE, make_score(u, v)); + mg += u; + eg += v; - return make_score(u, v); - } - - - // Evaluation::scale_factor() computes the scale factor for the winning side - - template - ScaleFactor Evaluation::scale_factor(Value eg) const { + // Compute the scale factor for the winning side Color strongSide = eg > VALUE_DRAW ? WHITE : BLACK; int sf = me->scale_factor(pos, strongSide); @@ -786,7 +778,18 @@ namespace { sf = std::min(sf, 36 + 7 * pos.count(strongSide)); } - return ScaleFactor(sf); + // Interpolate between the middlegame and (scaled by 'sf') endgame score + v = mg * int(me->game_phase()) + + eg * int(PHASE_MIDGAME - me->game_phase()) * ScaleFactor(sf) / SCALE_FACTOR_NORMAL; + v /= PHASE_MIDGAME; + + if (T) + { + Trace::add(WINNABLE, make_score(u, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL - eg_value(score))); + Trace::add(TOTAL, make_score(mg, eg * ScaleFactor(sf) / SCALE_FACTOR_NORMAL)); + } + + return Value(v); } @@ -841,14 +844,8 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(score); - - // Interpolate between a middlegame and a (scaled by 'sf') endgame score - ScaleFactor sf = scale_factor(eg_value(score)); - v = mg_value(score) * int(me->game_phase()) - + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; - - v /= PHASE_MIDGAME; + // Derive single value from mg and eg parts of score + v = winnable(score); // In case of tracing add all remaining individual evaluation terms if (T) @@ -857,7 +854,6 @@ namespace { Trace::add(IMBALANCE, me->imbalance()); Trace::add(PAWN, pe->pawn_score(WHITE), pe->pawn_score(BLACK)); Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]); - Trace::add(TOTAL, score); } // Side to move point of view @@ -909,11 +905,11 @@ std::string Eval::trace(const Position& pos) { << " Threats | " << Term(THREAT) << " Passed | " << Term(PASSED) << " Space | " << Term(SPACE) - << " Initiative | " << Term(INITIATIVE) + << " Winnable | " << Term(WINNABLE) << " ------------+-------------+-------------+------------\n" << " Total | " << Term(TOTAL); - ss << "\nTotal evaluation: " << to_cp(v) << " (white side)\n"; + ss << "\nFinal evaluation: " << to_cp(v) << " (white side)\n"; return ss.str(); } From b0eb5a1ba3d094a1d2236db6f33e0d2164ec3480 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sat, 6 Jun 2020 21:25:32 -0600 Subject: [PATCH 119/142] Wrap all access to LineBB and add assert This is a non-functional code style change which provides a safe access handler for LineBB. Also includes an assert in debug mode to verify square correctness. closes https://github.com/official-stockfish/Stockfish/pull/2719 No functional change --- src/bitboard.h | 20 ++++++++++++++++---- src/evaluate.cpp | 2 +- src/movegen.cpp | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 93f838f8..704f4bb4 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -200,12 +200,24 @@ inline Bitboard adjacent_files_bb(Square s) { return shift(file_bb(s)) | shift(file_bb(s)); } - -/// between_bb() returns squares that are linearly between the given squares +/// line_bb(Square, Square) returns a Bitboard representing an entire line +/// (from board edge to board edge) that intersects the given squares. /// If the given squares are not on a same file/rank/diagonal, return 0. +/// Ex. line_bb(SQ_C4, SQ_F7) returns a bitboard with the A2-G8 diagonal. + +inline Bitboard line_bb(Square s1, Square s2) { + + assert(is_ok(s1) && is_ok(s2)); + return LineBB[s1][s2]; +} + +/// between_bb() returns a Bitboard representing squares that are linearly +/// between the given squares (excluding the given squares). +/// If the given squares are not on a same file/rank/diagonal, return 0. +/// Ex. between_bb(SQ_C4, SQ_F7) returns a bitboard with squares D5 and E6. inline Bitboard between_bb(Square s1, Square s2) { - Bitboard b = LineBB[s1][s2] & ((AllSquares << s1) ^ (AllSquares << s2)); + Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2)); return b & (b - 1); //exclude lsb } @@ -249,7 +261,7 @@ inline Bitboard passed_pawn_span(Color c, Square s) { /// straight or on a diagonal line. inline bool aligned(Square s1, Square s2, Square s3) { - return LineBB[s1][s2] & s3; + return line_bb(s1, s2) & s3; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 12a4c7bf..c042c016 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -276,7 +276,7 @@ namespace { : attacks_bb(s, pos.pieces()); if (pos.blockers_for_king(Us) & s) - b &= LineBB[pos.square(Us)][s]; + b &= line_bb(pos.square(Us), s); attackedBy2[Us] |= attackedBy[Us][ALL_PIECES] & b; attackedBy[Us][Pt] |= b; diff --git a/src/movegen.cpp b/src/movegen.cpp index b57f41a9..17203a95 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -332,7 +332,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // the king evasions in order to skip known illegal moves, which avoids any // useless legality checks later on. while (sliders) - sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers(); + sliderAttacks |= line_bb(ksq, pop_lsb(&sliders)) & ~pos.checkers(); // Generate evasions for king, capture and non capture moves Bitboard b = attacks_bb(ksq) & ~pos.pieces(us) & ~sliderAttacks; From 1c65310c0e5ac639a51c3d6b9b114d48aa57bdd8 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 31 May 2020 23:31:14 -0600 Subject: [PATCH 120/142] Refactor some threads related code. This is a code style change that moves some pure thread code into the threads class. It is a bit more code, but it makes search.cpp cleaner and easier to read by hiding some thread specific functionality. STC (SMP) LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 75896 W: 12073 L: 12026 D: 51797 Ptnml(0-2): 828, 8224, 19872, 8121, 903 https://tests.stockfishchess.org/tests/view/5ed492e8f29b40b0fc95a74c closes https://github.com/official-stockfish/Stockfish/pull/2720 No functional change. --- src/search.cpp | 50 ++++++++----------------------------------------- src/thread.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- src/thread.h | 3 +++ 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index efa7b9c5..e3a5a92e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -236,14 +236,8 @@ void MainThread::search() { } else { - for (Thread* th : Threads) - { - th->bestMoveChanges = 0; - if (th != this) - th->start_searching(); - } - - Thread::search(); // Let's start searching! + Threads.start_searching(); // start non-main threads + Thread::search(); // main thread start searching } // When we reach the maximum depth, we can arrive here without a raise of @@ -260,9 +254,7 @@ void MainThread::search() { Threads.stop = true; // Wait until all threads have finished - for (Thread* th : Threads) - if (th != this) - th->wait_for_search_finished(); + Threads.wait_for_search_finished(); // When playing in 'nodes as time' mode, subtract the searched nodes from // the available ones before exiting. @@ -271,37 +263,11 @@ void MainThread::search() { Thread* bestThread = this; - // Check if there are threads with a better score than main thread - if ( int(Options["MultiPV"]) == 1 - && !Limits.depth - && !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) - && rootMoves[0].pv[0] != MOVE_NONE) - { - std::map votes; - Value minScore = this->rootMoves[0].score; - - // Find minimum score - for (Thread* th: Threads) - minScore = std::min(minScore, th->rootMoves[0].score); - - // Vote according to score and depth, and select the best thread - for (Thread* th : Threads) - { - votes[th->rootMoves[0].pv[0]] += - (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - - if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) - { - // Make sure we pick the shortest mate / TB conversion or stave off mate the longest - if (th->rootMoves[0].score > bestThread->rootMoves[0].score) - bestThread = th; - } - else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY - || ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY - && votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) - bestThread = th; - } - } + if (int(Options["MultiPV"]) == 1 && + !Limits.depth && + !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) && + rootMoves[0].pv[0] != MOVE_NONE) + bestThread = Threads.get_best_thread(); bestPreviousScore = bestThread->rootMoves[0].score; diff --git a/src/thread.cpp b/src/thread.cpp index c1713122..a27a60c6 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -208,7 +208,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, for (Thread* th : *this) { - th->nodes = th->tbHits = th->nmpMinPly = 0; + th->nodes = th->tbHits = th->nmpMinPly = th->bestMoveChanges = 0; th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); @@ -218,3 +218,52 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, main()->start_searching(); } + +Thread* ThreadPool::get_best_thread() const { + + Thread* bestThread = front(); + std::map votes; + Value minScore = VALUE_NONE; + + // Find minimum score of all threads + for (Thread* th: *this) + minScore = std::min(minScore, th->rootMoves[0].score); + + // Vote according to score and depth, and select the best thread + for (Thread* th : *this) + { + votes[th->rootMoves[0].pv[0]] += + (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); + + if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) + { + // Make sure we pick the shortest mate / TB conversion or stave off mate the longest + if (th->rootMoves[0].score > bestThread->rootMoves[0].score) + bestThread = th; + } + else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY + || ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY + && votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) + bestThread = th; + } + + return bestThread; +} + +/// Start non-main threads. + +void ThreadPool::start_searching() { + + for (Thread* th : *this) + if (th != front()) + th->start_searching(); +} + +/// Wait for non-main threads. + +void ThreadPool::wait_for_search_finished() const { + + for (Thread* th : *this) + if (th != front()) + th->wait_for_search_finished(); +} diff --git a/src/thread.h b/src/thread.h index 79be197b..a69e1d10 100644 --- a/src/thread.h +++ b/src/thread.h @@ -109,6 +109,9 @@ struct ThreadPool : public std::vector { MainThread* main() const { return static_cast(front()); } uint64_t nodes_searched() const { return accumulate(&Thread::nodes); } uint64_t tb_hits() const { return accumulate(&Thread::tbHits); } + Thread* get_best_thread() const; + void start_searching(); + void wait_for_search_finished() const; std::atomic_bool stop, increaseDepth; From d0cb9b286f4d7415be002855201e75340c8adef0 Mon Sep 17 00:00:00 2001 From: NguyenPham Date: Mon, 8 Jun 2020 07:48:38 +1000 Subject: [PATCH 121/142] show coordinates when displaying board closes https://github.com/official-stockfish/Stockfish/pull/2723 No functional change --- AUTHORS | 1 + src/bitboard.cpp | 3 ++- src/position.cpp | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 36c2a47b..1cd7ff54 100644 --- a/AUTHORS +++ b/AUTHORS @@ -115,6 +115,7 @@ Nick Pelling (nickpelling) Nicklas Persson (NicklasPersson) Niklas Fiekas (niklasf) Nikolay Kostov (NikolayIT) +Nguyen Pham Ondrej Mosnáček (WOnder93) Oskar Werkelin Ahlin Pablo Vazquez diff --git a/src/bitboard.cpp b/src/bitboard.cpp index f650eef6..3bb3ff8f 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -56,8 +56,9 @@ const std::string Bitboards::pretty(Bitboard b) { for (File f = FILE_A; f <= FILE_H; ++f) s += b & make_square(f, r) ? "| X " : "| "; - s += "|\n+---+---+---+---+---+---+---+---+\n"; + s += "| " + std::to_string(1 + r) + "\n+---+---+---+---+---+---+---+---+\n"; } + s += " a b c d e f g h\n"; return s; } diff --git a/src/position.cpp b/src/position.cpp index d2e33b30..c9db6224 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -64,10 +64,11 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { for (File f = FILE_A; f <= FILE_H; ++f) os << " | " << PieceToChar[pos.piece_on(make_square(f, r))]; - os << " |\n +---+---+---+---+---+---+---+---+\n"; + os << " | " << (1 + r) << "\n +---+---+---+---+---+---+---+---+\n"; } - os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase + os << " a b c d e f g h\n" + << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase << std::setfill('0') << std::setw(16) << pos.key() << std::setfill(' ') << std::dec << "\nCheckers: "; From b081e52239e6496070a376452ca04dcc6d1993c5 Mon Sep 17 00:00:00 2001 From: nguyenpham Date: Mon, 8 Jun 2020 08:49:27 +1000 Subject: [PATCH 122/142] Improve Readme.md about compiling Reparagraph, add an example how to compile on Unix-like systems closes https://github.com/official-stockfish/Stockfish/pull/2724 No functional change --- Readme.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Readme.md b/Readme.md index 35ff095d..2b1de86b 100644 --- a/Readme.md +++ b/Readme.md @@ -165,17 +165,23 @@ are in use, see the engine log. ## Compiling Stockfish yourself from the sources -On Unix-like systems, it should be possible to compile Stockfish -directly from the source code with the included Makefile. +Stockfish has support for 32 or 64-bit CPUs, certain hardware +instructions, big-endian machines such as Power PC, and other platforms. -Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT -instruction, big-endian machines such as Power PC, and other platforms. +On Unix-like systems, it should be easy to compile Stockfish +directly from the source code with the included Makefile in the folder +`src`. In general it is recommended to run `make help` to see a list of make +targets with corresponding descriptions. -In general it is recommended to run `make help` to see a list of make -targets with corresponding descriptions. When not using the Makefile to -compile (for instance with Microsoft MSVC) you need to manually -set/unset some switches in the compiler command line; see file *types.h* -for a quick reference. +``` + cd src + make help + make build ARCH=x86-64-modern +``` + +When not using the Makefile to compile (for instance with Microsoft MSVC) you +need to manually set/unset some switches in the compiler command line; see +file *types.h* for a quick reference. When reporting an issue or a bug, please tell us which version and compiler you used to create your executable. These informations can From 4b10578acbe099482ed40200478df4d775c01af5 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Fri, 5 Jun 2020 20:17:00 +0300 Subject: [PATCH 123/142] Increase the maximum hash size by a factor of 256 Conceptually group hash clusters into super clusters of 256 clusters. This scheme allows us to use hash sizes up to 32 TB (= 2^32 super clusters = 2^40 clusters). Use 48 bits of the Zobrist key to choose the cluster index. We use 8 extra bits to mitigate the quantization error for very large hashes when scaling the hash key to cluster index. The hash index computation is organized to be compatible with the existing scheme for power-of-two hash sizes up to 128 GB. Fixes https://github.com/official-stockfish/Stockfish/issues/1349 closes https://github.com/official-stockfish/Stockfish/pull/2722 Passed non-regression STC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 37976 W: 7336 L: 7211 D: 23429 Ptnml(0-2): 578, 4295, 9149, 4356, 610 https://tests.stockfishchess.org/tests/view/5edcbaaef29b40b0fc95abc5 No functional change. --- src/tt.cpp | 8 ++++++-- src/tt.h | 13 ++++++++++--- src/ucioption.cpp | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/tt.cpp b/src/tt.cpp index 0a3c54a1..92aaee00 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -65,8 +65,10 @@ void TranspositionTable::resize(size_t mbSize) { aligned_ttmem_free(mem); - clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); - table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); + superClusterCount = mbSize * 1024 * 1024 / (sizeof(Cluster) * ClustersPerSuperCluster); + + table = static_cast( + aligned_ttmem_alloc(superClusterCount * ClustersPerSuperCluster * sizeof(Cluster), mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize @@ -89,6 +91,8 @@ void TranspositionTable::clear() { { threads.emplace_back([this, idx]() { + const size_t clusterCount = superClusterCount * ClustersPerSuperCluster; + // Thread binding gives faster search on systems with a first-touch policy if (Options["Threads"] > 8) WinProcGroup::bindThisThread(idx); diff --git a/src/tt.h b/src/tt.h index bd723a86..76db03da 100644 --- a/src/tt.h +++ b/src/tt.h @@ -66,6 +66,7 @@ private: class TranspositionTable { static constexpr int ClusterSize = 3; + static constexpr int ClustersPerSuperCluster = 256; struct Cluster { TTEntry entry[ClusterSize]; @@ -82,15 +83,21 @@ public: void resize(size_t mbSize); void clear(); - // The 32 lowest order bits of the key are used to get the index of the cluster TTEntry* first_entry(const Key key) const { - return &table[(uint32_t(key) * uint64_t(clusterCount)) >> 32].entry[0]; + + // The index is computed from + // Idx = (K48 * SCC) / 2^40, with K48 the 48 lowest bits swizzled. + + const uint64_t firstTerm = uint32_t(key) * uint64_t(superClusterCount); + const uint64_t secondTerm = (uint16_t(key >> 32) * uint64_t(superClusterCount)) >> 16; + + return &table[(firstTerm + secondTerm) >> 24].entry[0]; } private: friend struct TTEntry; - size_t clusterCount; + size_t superClusterCount; Cluster* table; void* mem; uint8_t generation8; // Size must be not bigger than TTEntry::genBound8 diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 16add76e..90190b53 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -56,8 +56,8 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const void init(OptionsMap& o) { - // at most 2^32 clusters. - constexpr int MaxHashMB = Is64Bit ? 131072 : 2048; + // At most 2^32 superclusters. Supercluster = 8 kB + constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; o["Debug Log File"] << Option("", on_logger); o["Contempt"] << Option(24, -100, 100); From 3af083a7cd9be1659f1d8a39a65e33b87608f762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 10 Jun 2020 00:10:07 +0200 Subject: [PATCH 124/142] Improve the anti-shuffling policy We replace the current decrease of the complexity term in initiative when shuffling by a direct damping of the evaluation. This scheme may have two benefits over the initiative approach: a) the damping effect is more brutal for fortresses with heavy pieces on the board, because the initiative term is almost an endgame term; b) the initiative implementation had a funny side effect, almost a bug, in the rare positions where mg > 0, eg < 0 and the tampered eval returned a positive value (ie with heavy pieces still on the board): sending eg to zero via shuffling would **increase** the tampered eval instead of decreasing it, which is somewhat illogical. This patch avoids this phenomenon. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 43072 W: 8373 L: 8121 D: 26578 Ptnml(0-2): 729, 4954, 9940, 5162, 751 https://tests.stockfishchess.org/tests/view/5ee008ebf29b40b0fc95ade2 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 37376 W: 4816 L: 4543 D: 28017 Ptnml(0-2): 259, 3329, 11286, 3508, 306 https://tests.stockfishchess.org/tests/view/5ee03b06f29b40b0fc95ae0c Closes https://github.com/official-stockfish/Stockfish/pull/2727 Bench: 4757174 --- src/evaluate.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c042c016..b173cd3b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -743,7 +743,6 @@ namespace { + 24 * infiltration + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 2 * pos.rule50_count() -110 ; Value mg = mg_value(score); @@ -857,7 +856,12 @@ namespace { } // Side to move point of view - return (pos.side_to_move() == WHITE ? v : -v) + Tempo; + v = (pos.side_to_move() == WHITE ? v : -v) + Tempo; + + // Damp down the evaluation linearly when shuffling + v = v * (100 - pos.rule50_count()) / 100; + + return v; } } // namespace From c44c62efc24fbe6355a9c19e287b2c78e6fd6c1d Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 13 Jun 2020 05:03:59 +0300 Subject: [PATCH 125/142] Adjust history threshold for quiet moves futility pruning This patch adjusts the threshold for futility pruning of quiet moves using the continuation history array contHist[5], in the same way as it is used in movepicker. passed STC: https://tests.stockfishchess.org/tests/view/5ee3f88bca6c451633a9959f LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 55984 W: 10822 L: 10552 D: 34610 Ptnml(0-2): 952, 6435, 12941, 6719, 945 passed LTC: https://tests.stockfishchess.org/tests/view/5ee4186dca6c451633a995cf LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 41712 W: 5402 L: 5114 D: 31196 Ptnml(0-2): 293, 3766, 12469, 4016, 312 closes https://github.com/official-stockfish/Stockfish/pull/2734 Bench: 4715960 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e3a5a92e..f5887f3f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1006,7 +1006,8 @@ moves_loop: // When in check, search starts from here && ss->staticEval + 235 + 172 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < 27400) + + (*contHist[3])[movedPiece][to_sq(move)] + + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 31400) continue; // Prune moves with negative SEE (~20 Elo) From 4d657618e956decdd51bceca77c2c5489dfcf6af Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 10 Jun 2020 13:19:21 +0200 Subject: [PATCH 126/142] Quantize eval to multiples of 16 Removes some excess precision, helps searchs. Effectively reintroduces evaluation grain, with a slightly different context. https://github.com/official-stockfish/Stockfish/commit/45dbd9cd0303d0db469670af8ec3598731a4eace passed STC LLR: 2.97 (-2.94,2.94) {-0.50,1.50} Total: 197032 W: 37938 L: 37462 D: 121632 Ptnml(0-2): 3359, 22994, 45446, 23246, 3471 https://tests.stockfishchess.org/tests/view/5ee0c228f29b40b0fc95ae53 passed LTC LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 77696 W: 9970 L: 9581 D: 58145 Ptnml(0-2): 530, 7075, 23311, 7340, 592 https://tests.stockfishchess.org/tests/view/5ee21426f29b40b0fc95af43 passed LTC SMP LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 64136 W: 7425 L: 7091 D: 49620 Ptnml(0-2): 345, 5416, 20228, 5718, 361 https://tests.stockfishchess.org/tests/view/5ee387bbf29b40b0fc95b04c closes https://github.com/official-stockfish/Stockfish/pull/2733 Bench: 4939103 --- src/evaluate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index b173cd3b..036b93a9 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -855,6 +855,9 @@ namespace { Trace::add(MOBILITY, mobility[WHITE], mobility[BLACK]); } + // Evaluation grain + v = (v / 16) * 16; + // Side to move point of view v = (pos.side_to_move() == WHITE ? v : -v) + Tempo; From 42b7dbcb5e20ae9015122601522be8b455787a4a Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sat, 13 Jun 2020 09:54:07 +0100 Subject: [PATCH 127/142] Tuned values for search constants Tuned search constants after many search patches since the last successful tune. 1st LTC @ 60+0.6 th 1 : LLR: 2.97 (-2.94,2.94) {0.25,1.75} Total: 57656 W: 7369 L: 7036 D: 43251 Ptnml(0-2): 393, 5214, 17336, 5437, 448 https://tests.stockfishchess.org/tests/view/5ee1e074f29b40b0fc95af19 SMP LTC @ 20+0.2 th 8 : LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 83576 W: 9731 L: 9341 D: 64504 Ptnml(0-2): 464, 7062, 26369, 7406, 487 https://tests.stockfishchess.org/tests/view/5ee35a21f29b40b0fc95b008 The changes were rebased on top of a successful patch by Viz (see #2734) and two different ways of doing this were tested. The successful test modified the constants in the patch by Viz in a similar manner to the tuning run: LTC (rebased) @ 60+0.6 th 1 : LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 193384 W: 24241 L: 23521 D: 145622 Ptnml(0-2): 1309, 17497, 58472, 17993, 1421 https://tests.stockfishchess.org/tests/view/5ee43319ca6c451633a995f9 Further work: the recent patch to quantize eval #2733 affects search quit quite a bit, so doing another tune in, say, three months time might be a good idea. closes https://github.com/official-stockfish/Stockfish/pull/2735 Bench 4246971 --- src/search.cpp | 58 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f5887f3f..5ad650d2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -65,9 +65,9 @@ namespace { constexpr uint64_t TtHitAverageResolution = 1024; // Razor and futility margins - constexpr int RazorMargin = 531; + constexpr int RazorMargin = 516; Value futility_margin(Depth d, bool improving) { - return Value(217 * (d - improving)); + return Value(224 * (d - improving)); } // Reductions lookup table, initialized at startup @@ -75,16 +75,16 @@ namespace { Depth reduction(bool i, Depth d, int mn) { int r = Reductions[d] * Reductions[mn]; - return (r + 511) / 1024 + (!i && r > 1007); + return (r + 529) / 1024 + (!i && r > 1050); } constexpr int futility_move_count(bool improving, Depth depth) { - return (4 + depth * depth) / (2 - improving); + return (3 + depth * depth) / (2 - improving); } // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return d > 15 ? -8 : 19 * d * d + 155 * d - 132; + return d > 15 ? 28 : 19 * d * d + 135 * d - 136; } // Add a small random component to draw evaluations to avoid 3fold-blindness @@ -194,7 +194,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((24.8 + std::log(Threads.size())) * std::log(i)); + Reductions[i] = int((24.9 + std::log(Threads.size())) * std::log(i)); } @@ -408,7 +408,7 @@ void Thread::search() { beta = std::min(prev + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + (102 - ct / 2) * prev / (abs(prev) + 157); + int dct = ct + (104 - ct / 2) * prev / (abs(prev) + 143); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -506,13 +506,13 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; + double fallingEval = (293 + 6 * (mainThread->bestPreviousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 742.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.94 : 0.91; - double reduction = (1.41 + mainThread->previousTimeReduction) / (2.27 * timeReduction); + timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.93 : 0.96; + double reduction = (1.36 + mainThread->previousTimeReduction) / (2.21 * timeReduction); // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) @@ -537,7 +537,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > totalTime * 0.6) + && Time.elapsed() > totalTime * 0.57) Threads.increaseDepth = false; else Threads.increaseDepth = true; @@ -819,10 +819,10 @@ namespace { // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23397 + && (ss-1)->statScore < 24714 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 32 * depth - 30 * improving + 120 * ttPv + 292 + && ss->staticEval >= beta - 29 * depth - 31 * improving + 119 * ttPv + 299 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -830,7 +830,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = (854 + 68 * depth) / 258 + std::min(int(eval - beta) / 192, 3); + Depth R = (793 + 70 * depth) / 252 + std::min(int(eval - beta) / 192, 3); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -870,10 +870,10 @@ namespace { // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth >= 5 + && depth > 5 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { - Value raisedBeta = beta + 189 - 45 * improving; + Value raisedBeta = beta + 182 - 48 * improving; assert(raisedBeta < VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; @@ -904,7 +904,7 @@ namespace { // If the qsearch held, perform the regular search if (value >= raisedBeta) - value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4, !cutNode); + value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 5, !cutNode); pos.undo_move(move); @@ -1003,15 +1003,15 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 && !ss->inCheck - && ss->staticEval + 235 + 172 * lmrDepth <= alpha + && ss->staticEval + 252 + 176 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 31400) + + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 30251) continue; // Prune moves with negative SEE (~20 Elo) - if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } else @@ -1027,11 +1027,11 @@ moves_loop: // When in check, search starts from here && lmrDepth < 6 && !(PvNode && abs(bestValue) < 2) && !ss->inCheck - && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) + && ss->staticEval + 264 + 397 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; // See based pruning - if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) + if (!pos.see_ge(move, Value(-192) * depth)) // (~25 Elo) continue; } } @@ -1144,12 +1144,12 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || thisThread->ttHitAverage < 375 * TtHitAverageResolution * TtHitAverageWindow / 1024)) + || thisThread->ttHitAverage < 399 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); // Decrease reduction if the ttHit running average is large - if (thisThread->ttHitAverage > 500 * TtHitAverageResolution * TtHitAverageWindow / 1024) + if (thisThread->ttHitAverage > 492 * TtHitAverageResolution * TtHitAverageWindow / 1024) r--; // Reduction if other threads are searching this position. @@ -1195,14 +1195,14 @@ moves_loop: // When in check, search starts from here - 4926; // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) - if (ss->statScore >= -102 && (ss-1)->statScore < -114) + if (ss->statScore >= -99 && (ss-1)->statScore < -116) r--; - else if ((ss-1)->statScore >= -116 && ss->statScore < -154) + else if ((ss-1)->statScore >= -117 && ss->statScore < -150) r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 16434; + r -= ss->statScore / 15896; } else { @@ -1474,7 +1474,7 @@ moves_loop: // When in check, search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 154; + futilityBase = bestValue + 138; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From 995ee4b31105ad8c7976cc68c11fabfdc5108e63 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sun, 14 Jun 2020 21:50:27 +0100 Subject: [PATCH 128/142] Retuned values after eval quantize patch. The last search tune patch was tested before the implementation of #2733 which presumably changed the search characteristics noticeably. Another tuning run was done, see https://tests.stockfishchess.org/tests/view/5ee5b434ca6c451633a9a08c and the updated values passed these tests: STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 34352 W: 6600 L: 6360 D: 21392 Ptnml(0-2): 581, 3947, 7914, 4119, 615 https://tests.stockfishchess.org/tests/view/5ee62f05ca6c451633a9a15f LTC 60+0.6 th 1 : LLR: 2.97 (-2.94,2.94) {0.25,1.75} Total: 11176 W: 1499 L: 1304 D: 8373 Ptnml(0-2): 69, 933, 3403, 1100, 83 https://tests.stockfishchess.org/tests/view/5ee6205bca6c451633a9a147 SMP LTC 20+0.2 th 8 : LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 54032 W: 6126 L: 5826 D: 42080 Ptnml(0-2): 278, 4454, 17280, 4698, 306 https://tests.stockfishchess.org/tests/view/5ee62f25ca6c451633a9a162 Closes https://github.com/official-stockfish/Stockfish/pull/2742 Bench 4957812 --- src/search.cpp | 68 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5ad650d2..cf89a892 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -65,9 +65,9 @@ namespace { constexpr uint64_t TtHitAverageResolution = 1024; // Razor and futility margins - constexpr int RazorMargin = 516; + constexpr int RazorMargin = 527; Value futility_margin(Depth d, bool improving) { - return Value(224 * (d - improving)); + return Value(227 * (d - improving)); } // Reductions lookup table, initialized at startup @@ -75,7 +75,7 @@ namespace { Depth reduction(bool i, Depth d, int mn) { int r = Reductions[d] * Reductions[mn]; - return (r + 529) / 1024 + (!i && r > 1050); + return (r + 570) / 1024 + (!i && r > 1018); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -84,7 +84,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return d > 15 ? 28 : 19 * d * d + 135 * d - 136; + return d > 15 ? 27 : 17 * d * d + 133 * d - 134; } // Add a small random component to draw evaluations to avoid 3fold-blindness @@ -194,7 +194,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((24.9 + std::log(Threads.size())) * std::log(i)); + Reductions[i] = int((24.8 + std::log(Threads.size())) * std::log(i)); } @@ -403,12 +403,12 @@ void Thread::search() { if (rootDepth >= 4) { Value prev = rootMoves[pvIdx].previousScore; - delta = Value(21); + delta = Value(19); alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + (104 - ct / 2) * prev / (abs(prev) + 143); + int dct = ct + (110 - ct / 2) * prev / (abs(prev) + 140); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -506,13 +506,13 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (293 + 6 * (mainThread->bestPreviousScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 742.0; + double fallingEval = (296 + 6 * (mainThread->bestPreviousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 725.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.93 : 0.96; - double reduction = (1.36 + mainThread->previousTimeReduction) / (2.21 * timeReduction); + timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.92 : 0.95; + double reduction = (1.47 + mainThread->previousTimeReduction) / (2.22 * timeReduction); // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) @@ -537,7 +537,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > totalTime * 0.57) + && Time.elapsed() > totalTime * 0.56) Threads.increaseDepth = false; else Threads.increaseDepth = true; @@ -819,10 +819,10 @@ namespace { // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 24714 + && (ss-1)->statScore < 23824 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 29 * depth - 31 * improving + 119 * ttPv + 299 + && ss->staticEval >= beta - 33 * depth - 33 * improving + 112 * ttPv + 311 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -830,7 +830,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = (793 + 70 * depth) / 252 + std::min(int(eval - beta) / 192, 3); + Depth R = (737 + 77 * depth) / 246 + std::min(int(eval - beta) / 192, 3); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -870,10 +870,10 @@ namespace { // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth > 5 + && depth > 4 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { - Value raisedBeta = beta + 182 - 48 * improving; + Value raisedBeta = beta + 176 - 49 * improving; assert(raisedBeta < VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; @@ -904,7 +904,7 @@ namespace { // If the qsearch held, perform the regular search if (value >= raisedBeta) - value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 5, !cutNode); + value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4, !cutNode); pos.undo_move(move); @@ -1003,15 +1003,15 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 && !ss->inCheck - && ss->staticEval + 252 + 176 * lmrDepth <= alpha + && ss->staticEval + 284 + 188 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 30251) + + (*contHist[5])[movedPiece][to_sq(move)] / 2 < 28388) continue; // Prune moves with negative SEE (~20 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + if (!pos.see_ge(move, Value(-(29 - std::min(lmrDepth, 17)) * lmrDepth * lmrDepth))) continue; } else @@ -1027,11 +1027,11 @@ moves_loop: // When in check, search starts from here && lmrDepth < 6 && !(PvNode && abs(bestValue) < 2) && !ss->inCheck - && ss->staticEval + 264 + 397 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) + && ss->staticEval + 267 + 391 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; // See based pruning - if (!pos.see_ge(move, Value(-192) * depth)) // (~25 Elo) + if (!pos.see_ge(move, Value(-202) * depth)) // (~25 Elo) continue; } } @@ -1144,12 +1144,12 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || thisThread->ttHitAverage < 399 * TtHitAverageResolution * TtHitAverageWindow / 1024)) + || thisThread->ttHitAverage < 415 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); // Decrease reduction if the ttHit running average is large - if (thisThread->ttHitAverage > 492 * TtHitAverageResolution * TtHitAverageWindow / 1024) + if (thisThread->ttHitAverage > 473 * TtHitAverageResolution * TtHitAverageWindow / 1024) r--; // Reduction if other threads are searching this position. @@ -1164,7 +1164,7 @@ moves_loop: // When in check, search starts from here r++; // Decrease reduction if opponent's move count is high (~5 Elo) - if ((ss-1)->moveCount > 14) + if ((ss-1)->moveCount > 13) r--; // Decrease reduction if ttMove has been singularly extended (~3 Elo) @@ -1192,17 +1192,17 @@ moves_loop: // When in check, search starts from here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 4926; + - 4826; // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) - if (ss->statScore >= -99 && (ss-1)->statScore < -116) + if (ss->statScore >= -100 && (ss-1)->statScore < -112) r--; - else if ((ss-1)->statScore >= -117 && ss->statScore < -150) + else if ((ss-1)->statScore >= -125 && ss->statScore < -138) r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 15896; + r -= ss->statScore / 14615; } else { @@ -1212,7 +1212,7 @@ moves_loop: // When in check, search starts from here // Unless giving check, this capture is likely bad if ( !givesCheck - && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 200 * depth <= alpha) + && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 211 * depth <= alpha) r++; } @@ -1474,7 +1474,7 @@ moves_loop: // When in check, search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 138; + futilityBase = bestValue + 141; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, @@ -1724,8 +1724,8 @@ moves_loop: // When in check, search starts from here thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } - if (depth > 12 && ss->ply < MAX_LPH) - thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7); + if (depth > 11 && ss->ply < MAX_LPH) + thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 6); } // When playing with strength handicap, choose best move among a set of RootMoves From 1ea488d34c0b6a03fa3d89d289fe72fd1408cafd Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 14 Jun 2020 23:35:07 -0700 Subject: [PATCH 129/142] Use 128 bit multiply for TT index Remove super cluster stuff from TT and just use a 128 bit multiply. STC https://tests.stockfishchess.org/tests/view/5ee719b3aae8aec816ab7548 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 12736 W: 2502 L: 2333 D: 7901 Ptnml(0-2): 191, 1452, 2944, 1559, 222 LTC https://tests.stockfishchess.org/tests/view/5ee732d1aae8aec816ab7556 LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 27584 W: 3431 L: 3350 D: 20803 Ptnml(0-2): 173, 2500, 8400, 2511, 208 Scheme back to being derived from https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ Also the default optimized version of the index calculation now uses fewer instructions. https://godbolt.org/z/Tktxbv Might benefit from mulx (requires -mbmi2) closes https://github.com/official-stockfish/Stockfish/pull/2744 bench: 4320954 --- src/misc.h | 13 +++++++++++++ src/search.cpp | 2 +- src/tt.cpp | 16 ++++++---------- src/tt.h | 12 ++---------- src/ucioption.cpp | 1 - 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/misc.h b/src/misc.h index 05bfc7de..373f1b77 100644 --- a/src/misc.h +++ b/src/misc.h @@ -110,6 +110,19 @@ public: { return T(rand64() & rand64() & rand64()); } }; +inline uint64_t mul_hi64(uint64_t a, uint64_t b) { +#if defined(__GNUC__) && defined(IS_64BIT) + __extension__ typedef unsigned __int128 uint128; + return ((uint128)a * (uint128)b) >> 64; +#else + uint64_t aL = (uint32_t)a, aH = a >> 32; + uint64_t bL = (uint32_t)b, bH = b >> 32; + uint64_t c1 = (aL * bL) >> 32; + uint64_t c2 = aH * bL + c1; + uint64_t c3 = aL * bH + (uint32_t)c2; + return aH * bH + (c2 >> 32) + (c3 >> 32); +#endif +} /// Under Windows it is not possible for a process to run on more than one /// logical processor group. This usually means to be limited to use max 64 diff --git a/src/search.cpp b/src/search.cpp index cf89a892..67339ed7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -662,7 +662,7 @@ namespace { // search to overwrite a previous full search TT value, so we use a different // position key in case of an excluded move. excludedMove = ss->excludedMove; - posKey = pos.key() ^ Key(excludedMove << 16); // Isn't a very good hash + posKey = pos.key() ^ (Key(excludedMove) << 48); // Isn't a very good hash tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] diff --git a/src/tt.cpp b/src/tt.cpp index 92aaee00..d0a5d4e0 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -36,17 +36,17 @@ TranspositionTable TT; // Our global transposition table void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { // Preserve any existing move for the same position - if (m || (k >> 48) != key16) + if (m || (uint16_t)k != key16) move16 = (uint16_t)m; // Overwrite less valuable entries - if ( (k >> 48) != key16 + if ((uint16_t)k != key16 || d - DEPTH_OFFSET > depth8 - 4 || b == BOUND_EXACT) { assert(d >= DEPTH_OFFSET); - key16 = (uint16_t)(k >> 48); + key16 = (uint16_t)k; value16 = (int16_t)v; eval16 = (int16_t)ev; genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b); @@ -65,10 +65,8 @@ void TranspositionTable::resize(size_t mbSize) { aligned_ttmem_free(mem); - superClusterCount = mbSize * 1024 * 1024 / (sizeof(Cluster) * ClustersPerSuperCluster); - - table = static_cast( - aligned_ttmem_alloc(superClusterCount * ClustersPerSuperCluster * sizeof(Cluster), mem)); + clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); + table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize @@ -91,8 +89,6 @@ void TranspositionTable::clear() { { threads.emplace_back([this, idx]() { - const size_t clusterCount = superClusterCount * ClustersPerSuperCluster; - // Thread binding gives faster search on systems with a first-touch policy if (Options["Threads"] > 8) WinProcGroup::bindThisThread(idx); @@ -121,7 +117,7 @@ void TranspositionTable::clear() { TTEntry* TranspositionTable::probe(const Key key, bool& found) const { TTEntry* const tte = first_entry(key); - const uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster + const uint16_t key16 = (uint16_t)key; // Use the low 16 bits as key inside the cluster for (int i = 0; i < ClusterSize; ++i) if (!tte[i].key16 || tte[i].key16 == key16) diff --git a/src/tt.h b/src/tt.h index 76db03da..3e1d0e99 100644 --- a/src/tt.h +++ b/src/tt.h @@ -66,7 +66,6 @@ private: class TranspositionTable { static constexpr int ClusterSize = 3; - static constexpr int ClustersPerSuperCluster = 256; struct Cluster { TTEntry entry[ClusterSize]; @@ -84,20 +83,13 @@ public: void clear(); TTEntry* first_entry(const Key key) const { - - // The index is computed from - // Idx = (K48 * SCC) / 2^40, with K48 the 48 lowest bits swizzled. - - const uint64_t firstTerm = uint32_t(key) * uint64_t(superClusterCount); - const uint64_t secondTerm = (uint16_t(key >> 32) * uint64_t(superClusterCount)) >> 16; - - return &table[(firstTerm + secondTerm) >> 24].entry[0]; + return &table[mul_hi64(key, clusterCount)].entry[0]; } private: friend struct TTEntry; - size_t superClusterCount; + size_t clusterCount; Cluster* table; void* mem; uint8_t generation8; // Size must be not bigger than TTEntry::genBound8 diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 90190b53..7037ea57 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -56,7 +56,6 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const void init(OptionsMap& o) { - // At most 2^32 superclusters. Supercluster = 8 kB constexpr int MaxHashMB = Is64Bit ? 33554432 : 2048; o["Debug Log File"] << Option("", on_logger); From 4c72c95359e28ea3e5a4357a7679de794ebd3e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 16 Jun 2020 13:21:24 +0200 Subject: [PATCH 130/142] Small bonus to favor thorn pawns We increase a little bit the midgame value of pawns on a4, h4, a6 and h6. Original idea by Malcolm Campbell, who tried the version restricted to the pawns on the H column a couple of weeks ago and got a patch which almost passed LTC. The current pull request just adds the same idea for pawns on the A column. Possible follow-ups: maybe tweak the a5/h5 pawn values, and/or add a malus for very low king mobility in midgame? STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 33416 W: 6516 L: 6275 D: 20625 Ptnml(0-2): 575, 3847, 7659, 4016, 611 https://tests.stockfishchess.org/tests/view/5ee6c4e687586124bc2c10d4 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 134368 W: 16869 L: 16319 D: 101180 Ptnml(0-2): 908, 12083, 40708, 12521, 964 https://tests.stockfishchess.org/tests/view/5ee74e60aae8aec816ab756a closes https://github.com/official-stockfish/Stockfish/pull/2747 Bench: 5299456 --- src/psqt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psqt.cpp b/src/psqt.cpp index 7fa36ac8..abd23547 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -91,9 +91,9 @@ constexpr Score PBonus[RANK_NB][FILE_NB] = { }, { S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) }, { S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) }, - { S( -8, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S(-12, -9) }, + { S( -4, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S( -8, -9) }, { S( 13, 9), S( 0, 4), S(-13, 3), S( 1,-12), S( 11,-12), S( -2, -6), S(-13, 13), S( 5, 8) }, - { S( -5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S(-18, 13) }, + { S( 5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S( -8, 13) }, { S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) } }; From bc3c215490edf24cef0ff87d74ab01eeb91ae1bc Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 17 Jun 2020 05:36:30 +0300 Subject: [PATCH 131/142] More reduction for evading pawn moves. pawn moves are irreversable unlike other evading moves; pawn is the least valuable piece in the game. So it makes a lot of sence to assume that evading pawn moves are on average not as good as other evading moves thus can be reduced more. Passed STC https://tests.stockfishchess.org/tests/view/5ee9602e563bc7aa756002dc LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 94176 W: 17993 L: 17668 D: 58515 Ptnml(0-2): 1634, 10742, 21989, 11111, 1612 Passed LTC https://tests.stockfishchess.org/tests/view/5ee97342563bc7aa75600301 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 20432 W: 2572 L: 2354 D: 15506 Ptnml(0-2): 146, 1707, 6280, 1949, 134 closes https://github.com/official-stockfish/Stockfish/pull/2749 Bench: 5073064 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 67339ed7..d96ed7da 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1186,7 +1186,7 @@ moves_loop: // When in check, search starts from here // hence break make_move(). (~2 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) - r -= 2 + ttPv; + r -= 2 + ttPv - (type_of(movedPiece) == PAWN); ss->statScore = thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] From 6f15e7fab277c2595633ad08fdc25bdd7e0ab166 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 21 Jun 2020 15:21:46 +0200 Subject: [PATCH 132/142] small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2695 No functional change --- src/Makefile | 2 +- src/bitbase.cpp | 16 ++++++++-------- src/bitboard.cpp | 25 ++++++++++++------------- src/bitboard.h | 2 +- src/evaluate.cpp | 11 +++++------ src/movepick.cpp | 2 +- src/movepick.h | 8 ++++---- src/pawns.cpp | 14 +++++++------- src/pawns.h | 2 +- src/psqt.cpp | 2 +- src/search.cpp | 2 +- src/syzygy/tbprobe.cpp | 6 +++--- src/timeman.cpp | 2 +- src/types.h | 17 ++++------------- 14 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/Makefile b/src/Makefile index 016aafec..41c2aff6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -336,7 +336,7 @@ ifeq ($(pext),yes) endif endif -### 3.8 Link Time Optimization, it works since gcc 4.5 but not on mingw under Windows. +### 3.8 Link Time Optimization ### This is a mix of compile and link time options because the lto link phase ### needs access to the optimization flags. ifeq ($(optimize),yes) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index be6f0d0a..7e27eb96 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -108,25 +108,25 @@ namespace { stm = Color ((idx >> 12) & 0x01); psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7))); - // Check if two pieces are on the same square or if a king can be captured + // Invalid if two pieces are on the same square or if a king can be captured if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 || ksq[WHITE] == psq || ksq[BLACK] == psq || (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK]))) result = INVALID; - // Immediate win if a pawn can be promoted without getting captured + // Win if the pawn can be promoted without getting captured else if ( stm == WHITE && rank_of(psq) == RANK_7 - && ksq[stm] != psq + NORTH - && ( distance(ksq[~stm], psq + NORTH) > 1 - || (attacks_bb(ksq[stm]) & (psq + NORTH)))) + && ksq[WHITE] != psq + NORTH + && ( distance(ksq[BLACK], psq + NORTH) > 1 + || (distance(ksq[WHITE], psq + NORTH) == 1))) result = WIN; - // Immediate draw if it is a stalemate or a king captures undefended pawn + // Draw if it is stalemate or the black king can capture the pawn else if ( stm == BLACK - && ( !(attacks_bb(ksq[stm]) & ~(attacks_bb(ksq[~stm]) | pawn_attacks_bb(~stm, psq))) - || (attacks_bb(ksq[stm]) & psq & ~attacks_bb(ksq[~stm])))) + && ( !(attacks_bb(ksq[BLACK]) & ~(attacks_bb(ksq[WHITE]) | pawn_attacks_bb(WHITE, psq))) + || (attacks_bb(ksq[BLACK]) & ~attacks_bb(ksq[WHITE]) & psq))) result = DRAW; // Position will be classified later diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 3bb3ff8f..0bf7eef9 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -40,7 +40,7 @@ namespace { Bitboard RookTable[0x19000]; // To store rook attacks Bitboard BishopTable[0x1480]; // To store bishop attacks - void init_magics(Bitboard table[], Magic magics[], Direction directions[]); + void init_magics(PieceType pt, Bitboard table[], Magic magics[]); } @@ -79,11 +79,8 @@ void Bitboards::init() { for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); - Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; - Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; - - init_magics(RookTable, RookMagics, RookDirections); - init_magics(BishopTable, BishopMagics, BishopDirections); + init_magics(ROOK, RookTable, RookMagics); + init_magics(BISHOP, BishopTable, BishopMagics); for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) { @@ -109,15 +106,17 @@ void Bitboards::init() { namespace { - Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) { + Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) { Bitboard attacks = 0; + Direction RookDirections[4] = {NORTH, SOUTH, EAST, WEST}; + Direction BishopDirections[4] = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; - for (int i = 0; i < 4; ++i) + for(Direction d : (pt == ROOK ? RookDirections : BishopDirections)) { Square s = sq; - while(safe_destination(s, directions[i]) && !(occupied & s)) - attacks |= (s += directions[i]); + while(safe_destination(s, d) && !(occupied & s)) + attacks |= (s += d); } return attacks; @@ -129,7 +128,7 @@ namespace { // www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so // called "fancy" approach. - void init_magics(Bitboard table[], Magic magics[], Direction directions[]) { + void init_magics(PieceType pt, Bitboard table[], Magic magics[]) { // Optimal PRNG seeds to pick the correct magics in the shortest time int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 }, @@ -149,7 +148,7 @@ namespace { // the number of 1s of the mask. Hence we deduce the size of the shift to // apply to the 64 or 32 bits word to get the index. Magic& m = magics[s]; - m.mask = sliding_attack(directions, s, 0) & ~edges; + m.mask = sliding_attack(pt, s, 0) & ~edges; m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask); // Set the offset for the attacks table of the square. We have individual @@ -161,7 +160,7 @@ namespace { b = size = 0; do { occupancy[size] = b; - reference[size] = sliding_attack(directions, s, b); + reference[size] = sliding_attack(pt, s, b); if (HasPext) m.attacks[pext(b, m.mask)] = reference[size]; diff --git a/src/bitboard.h b/src/bitboard.h index 704f4bb4..0f55810c 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -253,7 +253,7 @@ inline Bitboard pawn_attack_span(Color c, Square s) { /// the given color and on the given square is a passed pawn. inline Bitboard passed_pawn_span(Color c, Square s) { - return forward_ranks_bb(c, s) & (adjacent_files_bb(s) | file_bb(s)); + return pawn_attack_span(c, s) | forward_file_bb(c, s); } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 036b93a9..3b0891a2 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -676,16 +676,15 @@ namespace { } - // Evaluation::space() computes the space evaluation for a given side. The - // space evaluation is a simple bonus based on the number of safe squares - // available for minor pieces on the central four files on ranks 2--4. Safe - // squares one, two or three squares behind a friendly pawn are counted - // twice. Finally, the space bonus is multiplied by a weight. The aim is to - // improve play on game opening. + // Evaluation::space() computes a space evaluation for a given side, aiming to improve game + // play in the opening. It is based on the number of safe squares on the 4 central files + // on ranks 2 to 4. Completely safe squares behind a friendly pawn are counted twice. + // Finally, the space bonus is multiplied by a weight which decreases according to occupancy. template template Score Evaluation::space() const { + // Early exit if, for example, both queens or 6 minor pieces have been exchanged if (pos.non_pawn_material() < SpaceThreshold) return SCORE_ZERO; diff --git a/src/movepick.cpp b/src/movepick.cpp index 78102c52..5775f810 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -57,7 +57,7 @@ namespace { /// MovePicker constructor for the main search MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, - const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) + const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl) : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { diff --git a/src/movepick.h b/src/movepick.h index 33c4b086..aaff388f 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -88,9 +88,9 @@ enum StatsType { NoCaptures, Captures }; /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards typedef Stats ButterflyHistory; -/// LowPlyHistory at higher depths records successful quiet moves on plies 0 to 3 -/// and quiet moves which are/were in the PV (ttPv) -/// It get cleared with each new search and get filled during iterative deepening +/// At higher depths LowPlyHistory records successful quiet moves near the root and quiet +/// moves which are/were in the PV (ttPv) +/// It is cleared with each new search and filled during iterative deepening constexpr int MAX_LPH = 4; typedef Stats LowPlyHistory; @@ -133,7 +133,7 @@ public: const CapturePieceToHistory*, const PieceToHistory**, Move, - Move*, + const Move*, int); Move next_move(bool skipQuiets = false); diff --git a/src/pawns.cpp b/src/pawns.cpp index c1119a41..597dff2b 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -150,17 +150,17 @@ namespace { && !(theirPawns & adjacent_files_bb(s))) score -= Doubled; else - score -= Isolated - + WeakUnopposed * !opposed; + score -= Isolated + + WeakUnopposed * !opposed; } else if (backward) - score -= Backward - + WeakUnopposed * !opposed; + score -= Backward + + WeakUnopposed * !opposed; if (!support) - score -= Doubled * doubled - + WeakLever * more_than_one(lever); + score -= Doubled * doubled + + WeakLever * more_than_one(lever); } return score; @@ -196,7 +196,7 @@ Entry* probe(const Position& pos) { /// penalty for a king, looking at the king file and the two closest files. template -Score Entry::evaluate_shelter(const Position& pos, Square ksq) { +Score Entry::evaluate_shelter(const Position& pos, Square ksq) const { constexpr Color Them = ~Us; diff --git a/src/pawns.h b/src/pawns.h index a3284a0f..e6098069 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -50,7 +50,7 @@ struct Entry { Score do_king_safety(const Position& pos); template - Score evaluate_shelter(const Position& pos, Square ksq); + Score evaluate_shelter(const Position& pos, Square ksq) const; Key key; Score scores[COLOR_NB]; diff --git a/src/psqt.cpp b/src/psqt.cpp index abd23547..27c7a36f 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -106,7 +106,7 @@ Score psq[PIECE_NB][SQUARE_NB]; // tables are initialized by flipping and changing the sign of the white scores. void init() { - for (Piece pc = W_PAWN; pc <= W_KING; ++pc) + for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING}) { Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); diff --git a/src/search.cpp b/src/search.cpp index d96ed7da..563d1aab 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -670,7 +670,7 @@ namespace { ttPv = PvNode || (ttHit && tte->is_pv()); formerPv = ttPv && !PvNode; - if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove)) + if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !priorCapture && is_ok((ss-1)->currentMove)) thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); // thisThread->ttHitAverage can be used to approximate the running average of ttHit diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 6bfd78ad..95d58945 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1200,7 +1200,7 @@ WDLScore search(Position& pos, ProbeState* result) { auto moveList = MoveList(pos); size_t totalCount = moveList.size(), moveCount = 0; - for (const Move& move : moveList) + for (const Move move : moveList) { if ( !pos.capture(move) && (!CheckZeroingMoves || type_of(pos.moved_piece(move)) != PAWN)) @@ -1362,7 +1362,7 @@ void Tablebases::init(const std::string& paths) { LeadPawnsSize[leadPawnsCnt][f] = idx; } - // Add entries in TB tables if the corresponding ".rtbw" file exsists + // Add entries in TB tables if the corresponding ".rtbw" file exists for (PieceType p1 = PAWN; p1 < KING; ++p1) { TBTables.add({KING, p1, KING}); @@ -1469,7 +1469,7 @@ int Tablebases::probe_dtz(Position& pos, ProbeState* result) { StateInfo st; int minDTZ = 0xFFFF; - for (const Move& move : MoveList(pos)) + for (const Move move : MoveList(pos)) { bool zeroing = pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN; diff --git a/src/timeman.cpp b/src/timeman.cpp index 1f598745..d27962b7 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -79,7 +79,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { { opt_scale = std::min(0.008 + std::pow(ply + 3.0, 0.5) / 250.0, 0.2 * limits.time[us] / double(timeLeft)); - max_scale = 4 + std::min(36, ply) / 12.0; + max_scale = std::min(7.0, 4.0 + ply / 12.0); } // x moves in y seconds (+ z increment) diff --git a/src/types.h b/src/types.h index 580c846a..969d4e65 100644 --- a/src/types.h +++ b/src/types.h @@ -40,7 +40,6 @@ #include #include -#include #include #include #include @@ -214,7 +213,6 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = { typedef int Depth; enum : int { - DEPTH_QS_CHECKS = 0, DEPTH_QS_NO_CHECKS = -1, DEPTH_QS_RECAPTURES = -5, @@ -282,11 +280,11 @@ inline Value mg_value(Score s) { } #define ENABLE_BASE_OPERATORS_ON(T) \ -constexpr T operator+(T d1, T d2) { return T(int(d1) + int(d2)); } \ -constexpr T operator-(T d1, T d2) { return T(int(d1) - int(d2)); } \ +constexpr T operator+(T d1, int d2) { return T(int(d1) + d2); } \ +constexpr T operator-(T d1, int d2) { return T(int(d1) - d2); } \ constexpr T operator-(T d) { return T(-int(d)); } \ -inline T& operator+=(T& d1, T d2) { return d1 = d1 + d2; } \ -inline T& operator-=(T& d1, T d2) { return d1 = d1 - d2; } +inline T& operator+=(T& d1, int d2) { return d1 = d1 + d2; } \ +inline T& operator-=(T& d1, int d2) { return d1 = d1 - d2; } #define ENABLE_INCR_OPERATORS_ON(T) \ inline T& operator++(T& d) { return d = T(int(d) + 1); } \ @@ -305,7 +303,6 @@ ENABLE_FULL_OPERATORS_ON(Value) ENABLE_FULL_OPERATORS_ON(Direction) ENABLE_INCR_OPERATORS_ON(PieceType) -ENABLE_INCR_OPERATORS_ON(Piece) ENABLE_INCR_OPERATORS_ON(Square) ENABLE_INCR_OPERATORS_ON(File) ENABLE_INCR_OPERATORS_ON(Rank) @@ -316,12 +313,6 @@ ENABLE_BASE_OPERATORS_ON(Score) #undef ENABLE_INCR_OPERATORS_ON #undef ENABLE_BASE_OPERATORS_ON -/// Additional operators to add integers to a Value -constexpr Value operator+(Value v, int i) { return Value(int(v) + i); } -constexpr Value operator-(Value v, int i) { return Value(int(v) - i); } -inline Value& operator+=(Value& v, int i) { return v = v + i; } -inline Value& operator-=(Value& v, int i) { return v = v - i; } - /// Additional operators to add a Direction to a Square constexpr Square operator+(Square s, Direction d) { return Square(int(s) + int(d)); } constexpr Square operator-(Square s, Direction d) { return Square(int(s) - int(d)); } From 8a3f155b1cc1175b33ddc97d0572b5557269b0fa Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 17 Jun 2020 15:15:54 -0600 Subject: [PATCH 133/142] Make endgames consistent Changes variable names and occasionally consolidated variable declarations. Piece squares are consistently prefixed with "weak" or "strong." passed STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 29008 W: 5532 L: 5416 D: 18060 Ptnml(0-2): 355, 2983, 7723, 3077, 366 https://tests.stockfishchess.org/tests/view/5eea88d3563bc7aa75600689 closes https://github.com/official-stockfish/Stockfish/pull/2752 No functional change --- src/endgame.cpp | 384 ++++++++++++++++++++++++------------------------ 1 file changed, 194 insertions(+), 190 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 7b9c145e..d9e76348 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -28,12 +28,14 @@ namespace { // Used to drive the king towards the edge of the board // in KX vs K and KQ vs KR endgames. + // Values range from 27 (center squares) to 90 (in the corners) inline int push_to_edge(Square s) { int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s)); return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2); } // Used to drive the king towards A1H8 corners in KBN vs K endgames. + // Values range from 0 on A8H1 diagonal to 7 in A1H8 corners inline int push_to_corner(Square s) { return abs(7 - rank_of(s) - file_of(s)); } @@ -103,13 +105,13 @@ Value Endgame::operator()(const Position& pos) const { if (pos.side_to_move() == weakSide && !MoveList(pos).size()) return VALUE_DRAW; - Square winnerKSq = pos.square(strongSide); - Square loserKSq = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + Square weakKing = pos.square(weakSide); Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg - + push_to_edge(loserKSq) - + push_close(winnerKSq, loserKSq); + + push_to_edge(weakKing) + + push_close(strongKing, weakKing); if ( pos.count(strongSide) || pos.count(strongSide) @@ -130,16 +132,16 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, KnightValueMg + BishopValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - Square winnerKSq = pos.square(strongSide); - Square loserKSq = pos.square(weakSide); - Square bishopSq = pos.square(strongSide); + Square strongKing = pos.square(strongSide); + Square strongBishop = pos.square(strongSide); + Square weakKing = pos.square(weakSide); // If our bishop does not attack A1/H8, we flip the enemy king square // to drive to opposite corners (A8/H1). Value result = (VALUE_KNOWN_WIN + 3520) - + push_close(winnerKSq, loserKSq) - + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq); + + push_close(strongKing, weakKing) + + 420 * push_to_corner(opposite_colors(strongBishop, SQ_A1) ? flip_file(weakKing) : weakKing); assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; @@ -154,16 +156,16 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.square(weakSide)); - Square psq = normalize(pos, strongSide, pos.square(strongSide)); + Square strongKing = normalize(pos, strongSide, pos.square(strongSide)); + Square strongPawn = normalize(pos, strongSide, pos.square(strongSide)); + Square weakKing = normalize(pos, strongSide, pos.square(weakSide)); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK; - if (!Bitbases::probe(wksq, psq, bksq, us)) + if (!Bitbases::probe(strongKing, strongPawn, weakKing, us)) return VALUE_DRAW; - Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(psq)); + Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(strongPawn)); return strongSide == pos.side_to_move() ? result : -result; } @@ -179,36 +181,35 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Square wksq = relative_square(strongSide, pos.square(strongSide)); - Square bksq = relative_square(strongSide, pos.square(weakSide)); - Square rsq = relative_square(strongSide, pos.square(strongSide)); - Square psq = relative_square(strongSide, pos.square(weakSide)); - - Square queeningSq = make_square(file_of(psq), RANK_1); + Square strongKing = relative_square(strongSide, pos.square(strongSide)); + Square weakKing = relative_square(strongSide, pos.square(weakSide)); + Square strongRook = relative_square(strongSide, pos.square(strongSide)); + Square weakPawn = relative_square(strongSide, pos.square(weakSide)); + Square queeningSquare = make_square(file_of(weakPawn), RANK_1); Value result; // If the stronger side's king is in front of the pawn, it's a win - if (forward_file_bb(WHITE, wksq) & psq) - result = RookValueEg - distance(wksq, psq); + if (forward_file_bb(WHITE, strongKing) & weakPawn) + result = RookValueEg - distance(strongKing, weakPawn); // If the weaker side's king is too far from the pawn and the rook, // it's a win. - else if ( distance(bksq, psq) >= 3 + (pos.side_to_move() == weakSide) - && distance(bksq, rsq) >= 3) - result = RookValueEg - distance(wksq, psq); + else if ( distance(weakKing, weakPawn) >= 3 + (pos.side_to_move() == weakSide) + && distance(weakKing, strongRook) >= 3) + result = RookValueEg - distance(strongKing, weakPawn); // If the pawn is far advanced and supported by the defending king, // the position is drawish - else if ( rank_of(bksq) <= RANK_3 - && distance(bksq, psq) == 1 - && rank_of(wksq) >= RANK_4 - && distance(wksq, psq) > 2 + (pos.side_to_move() == strongSide)) - result = Value(80) - 8 * distance(wksq, psq); + else if ( rank_of(weakKing) <= RANK_3 + && distance(weakKing, weakPawn) == 1 + && rank_of(strongKing) >= RANK_4 + && distance(strongKing, weakPawn) > 2 + (pos.side_to_move() == strongSide)) + result = Value(80) - 8 * distance(strongKing, weakPawn); else - result = Value(200) - 8 * ( distance(wksq, psq + SOUTH) - - distance(bksq, psq + SOUTH) - - distance(psq, queeningSq)); + result = Value(200) - 8 * ( distance(strongKing, weakPawn + SOUTH) + - distance(weakKing, weakPawn + SOUTH) + - distance(weakPawn, queeningSquare)); return strongSide == pos.side_to_move() ? result : -result; } @@ -235,9 +236,9 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, KnightValueMg, 0)); - Square bksq = pos.square(weakSide); - Square bnsq = pos.square(weakSide); - Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq)); + Square weakKing = pos.square(weakSide); + Square weakKnight = pos.square(weakSide); + Value result = Value(push_to_edge(weakKing) + push_away(weakKing, weakKnight)); return strongSide == pos.side_to_move() ? result : -result; } @@ -252,15 +253,15 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, QueenValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Square winnerKSq = pos.square(strongSide); - Square loserKSq = pos.square(weakSide); - Square pawnSq = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + Square weakKing = pos.square(weakSide); + Square weakPawn = pos.square(weakSide); - Value result = Value(push_close(winnerKSq, loserKSq)); + Value result = Value(push_close(strongKing, weakKing)); - if ( relative_rank(weakSide, pawnSq) != RANK_7 - || distance(loserKSq, pawnSq) != 1 - || ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq)) + if ( relative_rank(weakSide, weakPawn) != RANK_7 + || distance(weakKing, weakPawn) != 1 + || ((FileBBB | FileDBB | FileEBB | FileGBB) & weakPawn)) result += QueenValueEg - PawnValueEg; return strongSide == pos.side_to_move() ? result : -result; @@ -277,13 +278,13 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, QueenValueMg, 0)); assert(verify_material(pos, weakSide, RookValueMg, 0)); - Square winnerKSq = pos.square(strongSide); - Square loserKSq = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + Square weakKing = pos.square(weakSide); Value result = QueenValueEg - RookValueEg - + push_to_edge(loserKSq) - + push_close(winnerKSq, loserKSq); + + push_to_edge(weakKing) + + push_close(strongKing, weakKing); return strongSide == pos.side_to_move() ? result : -result; } @@ -297,9 +298,12 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); + Square weakKing = pos.square(weakSide); + Square weakPawn = pos.square(weakSide); + Value result = PawnValueEg - + 2 * push_to_edge(pos.square(weakSide)) - - 10 * relative_rank(weakSide, pos.square(weakSide)); + + 2 * push_to_edge(weakKing) + - 10 * relative_rank(weakSide, weakPawn); return strongSide == pos.side_to_move() ? result : -result; } @@ -325,15 +329,17 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Bitboard strongPawns = pos.pieces(strongSide, PAWN); Bitboard allPawns = pos.pieces(PAWN); + Square strongBishop = pos.square(strongSide); + Square weakKing = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + // All strongSide pawns are on a single rook file? if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB)) { - Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8)); - Square weakKingSq = pos.square(weakSide); + Square queeningSquare = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8)); - if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, weakKingSq) <= 1) + if ( opposite_colors(queeningSquare, strongBishop) + && distance(queeningSquare, weakKing) <= 1) return SCALE_FACTOR_DRAW; } @@ -343,20 +349,16 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && pos.count(weakSide) >= 1) { // Get the least advanced weakSide pawn - Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); - - Square strongKingSq = pos.square(strongSide); - Square weakKingSq = pos.square(weakSide); - Square bishopSq = pos.square(strongSide); + Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left - if ( relative_rank(strongSide, weakPawnSq) == RANK_7 - && (strongPawns & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongPawns))) + if ( relative_rank(strongSide, weakPawn) == RANK_7 + && (strongPawns & (weakPawn + pawn_push(weakSide))) + && (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns))) { - int strongKingDist = distance(weakPawnSq, strongKingSq); - int weakKingDist = distance(weakPawnSq, weakKingSq); + int strongKingDist = distance(weakPawn, strongKing); + int weakKingDist = distance(weakPawn, weakKing); // It's a draw if the weak king is on its back two ranks, within 2 // squares of the blocking pawn and the strong king is not @@ -364,7 +366,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w // and positions where qsearch will immediately correct the // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w) - if ( relative_rank(strongSide, weakKingSq) >= RANK_7 + if ( relative_rank(strongSide, weakKing) >= RANK_7 && weakKingDist <= 2 && weakKingDist <= strongKingDist) return SCALE_FACTOR_DRAW; @@ -384,15 +386,16 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.count(weakSide) == 1); assert(pos.count(weakSide) >= 1); - Square kingSq = pos.square(weakSide); - Square rsq = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + Square weakKing = pos.square(weakSide); + Square weakRook = pos.square(weakSide); - if ( relative_rank(weakSide, kingSq) <= RANK_2 - && relative_rank(weakSide, pos.square(strongSide)) >= RANK_4 - && relative_rank(weakSide, rsq) == RANK_3 + if ( relative_rank(weakSide, weakKing) <= RANK_2 + && relative_rank(weakSide, strongKing) >= RANK_4 + && relative_rank(weakSide, weakRook) == RANK_3 && ( pos.pieces(weakSide, PAWN) - & attacks_bb(kingSq) - & pawn_attacks_bb(strongSide, rsq))) + & attacks_bb(weakKing) + & pawn_attacks_bb(strongSide, weakRook))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -412,89 +415,89 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, RookValueMg, 0)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.square(weakSide)); - Square wrsq = normalize(pos, strongSide, pos.square(strongSide)); - Square wpsq = normalize(pos, strongSide, pos.square(strongSide)); - Square brsq = normalize(pos, strongSide, pos.square(weakSide)); + Square strongKing = normalize(pos, strongSide, pos.square(strongSide)); + Square strongRook = normalize(pos, strongSide, pos.square(strongSide)); + Square strongPawn = normalize(pos, strongSide, pos.square(strongSide)); + Square weakKing = normalize(pos, strongSide, pos.square(weakSide)); + Square weakRook = normalize(pos, strongSide, pos.square(weakSide)); - File f = file_of(wpsq); - Rank r = rank_of(wpsq); - Square queeningSq = make_square(f, RANK_8); + File pawnFile = file_of(strongPawn); + Rank pawnRank = rank_of(strongPawn); + Square queeningSquare = make_square(pawnFile, RANK_8); int tempo = (pos.side_to_move() == strongSide); // If the pawn is not too far advanced and the defending king defends the // queening square, use the third-rank defence. - if ( r <= RANK_5 - && distance(bksq, queeningSq) <= 1 - && wksq <= SQ_H5 - && (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6))) + if ( pawnRank <= RANK_5 + && distance(weakKing, queeningSquare) <= 1 + && strongKing <= SQ_H5 + && (rank_of(weakRook) == RANK_6 || (pawnRank <= RANK_3 && rank_of(strongRook) != RANK_6))) return SCALE_FACTOR_DRAW; // The defending side saves a draw by checking from behind in case the pawn // has advanced to the 6th rank with the king behind. - if ( r == RANK_6 - && distance(bksq, queeningSq) <= 1 - && rank_of(wksq) + tempo <= RANK_6 - && (rank_of(brsq) == RANK_1 || (!tempo && distance(brsq, wpsq) >= 3))) + if ( pawnRank == RANK_6 + && distance(weakKing, queeningSquare) <= 1 + && rank_of(strongKing) + tempo <= RANK_6 + && (rank_of(weakRook) == RANK_1 || (!tempo && distance(weakRook, strongPawn) >= 3))) return SCALE_FACTOR_DRAW; - if ( r >= RANK_6 - && bksq == queeningSq - && rank_of(brsq) == RANK_1 - && (!tempo || distance(wksq, wpsq) >= 2)) + if ( pawnRank >= RANK_6 + && weakKing == queeningSquare + && rank_of(weakRook) == RANK_1 + && (!tempo || distance(strongKing, strongPawn) >= 2)) return SCALE_FACTOR_DRAW; // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7 // and the black rook is behind the pawn. - if ( wpsq == SQ_A7 - && wrsq == SQ_A8 - && (bksq == SQ_H7 || bksq == SQ_G7) - && file_of(brsq) == FILE_A - && (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5)) + if ( strongPawn == SQ_A7 + && strongRook == SQ_A8 + && (weakKing == SQ_H7 || weakKing == SQ_G7) + && file_of(weakRook) == FILE_A + && (rank_of(weakRook) <= RANK_3 || file_of(strongKing) >= FILE_D || rank_of(strongKing) <= RANK_5)) return SCALE_FACTOR_DRAW; // If the defending king blocks the pawn and the attacking king is too far // away, it's a draw. - if ( r <= RANK_5 - && bksq == wpsq + NORTH - && distance(wksq, wpsq) - tempo >= 2 - && distance(wksq, brsq) - tempo >= 2) + if ( pawnRank <= RANK_5 + && weakKing == strongPawn + NORTH + && distance(strongKing, strongPawn) - tempo >= 2 + && distance(strongKing, weakRook) - tempo >= 2) return SCALE_FACTOR_DRAW; // Pawn on the 7th rank supported by the rook from behind usually wins if the // attacking king is closer to the queening square than the defending king, // and the defending king cannot gain tempi by threatening the attacking rook. - if ( r == RANK_7 - && f != FILE_A - && file_of(wrsq) == f - && wrsq != queeningSq - && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo) - && (distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo)) - return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(wksq, queeningSq)); + if ( pawnRank == RANK_7 + && pawnFile != FILE_A + && file_of(strongRook) == pawnFile + && strongRook != queeningSquare + && (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo) + && (distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo)) + return ScaleFactor(SCALE_FACTOR_MAX - 2 * distance(strongKing, queeningSquare)); // Similar to the above, but with the pawn further back - if ( f != FILE_A - && file_of(wrsq) == f - && wrsq < wpsq - && (distance(wksq, queeningSq) < distance(bksq, queeningSq) - 2 + tempo) - && (distance(wksq, wpsq + NORTH) < distance(bksq, wpsq + NORTH) - 2 + tempo) - && ( distance(bksq, wrsq) + tempo >= 3 - || ( distance(wksq, queeningSq) < distance(bksq, wrsq) + tempo - && (distance(wksq, wpsq + NORTH) < distance(bksq, wrsq) + tempo)))) + if ( pawnFile != FILE_A + && file_of(strongRook) == pawnFile + && strongRook < strongPawn + && (distance(strongKing, queeningSquare) < distance(weakKing, queeningSquare) - 2 + tempo) + && (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn + NORTH) - 2 + tempo) + && ( distance(weakKing, strongRook) + tempo >= 3 + || ( distance(strongKing, queeningSquare) < distance(weakKing, strongRook) + tempo + && (distance(strongKing, strongPawn + NORTH) < distance(weakKing, strongPawn) + tempo)))) return ScaleFactor( SCALE_FACTOR_MAX - - 8 * distance(wpsq, queeningSq) - - 2 * distance(wksq, queeningSq)); + - 8 * distance(strongPawn, queeningSquare) + - 2 * distance(strongKing, queeningSquare)); // If the pawn is not far advanced and the defending king is somewhere in // the pawn's path, it's probably a draw. - if (r <= RANK_4 && bksq > wpsq) + if (pawnRank <= RANK_4 && weakKing > strongPawn) { - if (file_of(bksq) == file_of(wpsq)) + if (file_of(weakKing) == file_of(strongPawn)) return ScaleFactor(10); - if ( distance(bksq, wpsq) == 1 - && distance(wksq, bksq) > 2) - return ScaleFactor(24 - 2 * distance(wksq, bksq)); + if ( distance(weakKing, strongPawn) == 1 + && distance(strongKing, weakKing) > 2) + return ScaleFactor(24 - 2 * distance(strongKing, weakKing)); } return SCALE_FACTOR_NONE; } @@ -508,10 +511,11 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Test for a rook pawn if (pos.pieces(PAWN) & (FileABB | FileHBB)) { - Square ksq = pos.square(weakSide); - Square bsq = pos.square(weakSide); - Square psq = pos.square(strongSide); - Rank rk = relative_rank(strongSide, psq); + Square weakKing = pos.square(weakSide); + Square weakBishop = pos.square(weakSide); + Square strongKing = pos.square(strongSide); + Square strongPawn = pos.square(strongSide); + Rank pawnRank = relative_rank(strongSide, strongPawn); Direction push = pawn_push(strongSide); // If the pawn is on the 5th rank and the pawn (currently) is on @@ -519,11 +523,11 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // a fortress. Depending on the king position give a moderate // reduction or a stronger one if the defending king is near the // corner but not trapped there. - if (rk == RANK_5 && !opposite_colors(bsq, psq)) + if (pawnRank == RANK_5 && !opposite_colors(weakBishop, strongPawn)) { - int d = distance(psq + 3 * push, ksq); + int d = distance(strongPawn + 3 * push, weakKing); - if (d <= 2 && !(d == 0 && ksq == pos.square(strongSide) + 2 * push)) + if (d <= 2 && !(d == 0 && weakKing == strongKing + 2 * push)) return ScaleFactor(24); else return ScaleFactor(48); @@ -533,10 +537,10 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // it's drawn if the bishop attacks the square in front of the // pawn from a reasonable distance and the defending king is near // the corner - if ( rk == RANK_6 - && distance(psq + 2 * push, ksq) <= 1 - && (attacks_bb(bsq) & (psq + push)) - && distance(bsq, psq) >= 2) + if ( pawnRank == RANK_6 + && distance(strongPawn + 2 * push, weakKing) <= 1 + && (attacks_bb(weakBishop) & (strongPawn + push)) + && distance(weakBishop, strongPawn) >= 2) return ScaleFactor(8); } @@ -551,22 +555,22 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 2)); assert(verify_material(pos, weakSide, RookValueMg, 1)); - Square wpsq1 = pos.squares(strongSide)[0]; - Square wpsq2 = pos.squares(strongSide)[1]; - Square bksq = pos.square(weakSide); + Square strongPawn1 = pos.squares(strongSide)[0]; + Square strongPawn2 = pos.squares(strongSide)[1]; + Square weakKing = pos.square(weakSide); // Does the stronger side have a passed pawn? - if (pos.pawn_passed(strongSide, wpsq1) || pos.pawn_passed(strongSide, wpsq2)) + if (pos.pawn_passed(strongSide, strongPawn1) || pos.pawn_passed(strongSide, strongPawn2)) return SCALE_FACTOR_NONE; - Rank r = std::max(relative_rank(strongSide, wpsq1), relative_rank(strongSide, wpsq2)); + Rank pawnRank = std::max(relative_rank(strongSide, strongPawn1), relative_rank(strongSide, strongPawn2)); - if ( distance(bksq, wpsq1) <= 1 - && distance(bksq, wpsq2) <= 1 - && relative_rank(strongSide, bksq) > r) + if ( distance(weakKing, strongPawn1) <= 1 + && distance(weakKing, strongPawn2) <= 1 + && relative_rank(strongSide, weakKing) > pawnRank) { - assert(r > RANK_1 && r < RANK_7); - return ScaleFactor(7 * r); + assert(pawnRank > RANK_1 && pawnRank < RANK_7); + return ScaleFactor(7 * pawnRank); } return SCALE_FACTOR_NONE; } @@ -581,12 +585,12 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.count(strongSide) >= 2); assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - Square ksq = pos.square(weakSide); - Bitboard pawns = pos.pieces(strongSide, PAWN); + Square weakKing = pos.square(weakSide); + Bitboard strongPawns = pos.pieces(strongSide, PAWN); // If all pawns are ahead of the king on a single rook file, it's a draw. - if (!((pawns & ~FileABB) || (pawns & ~FileHBB)) && - !(pawns & ~passed_pawn_span(weakSide, ksq))) + if (!((strongPawns & ~FileABB) || (strongPawns & ~FileHBB)) && + !(strongPawns & ~passed_pawn_span(weakSide, weakKing))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -603,19 +607,19 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 1)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Square pawnSq = pos.square(strongSide); - Square strongBishopSq = pos.square(strongSide); - Square weakBishopSq = pos.square(weakSide); - Square weakKingSq = pos.square(weakSide); + Square strongPawn = pos.square(strongSide); + Square strongBishop = pos.square(strongSide); + Square weakBishop = pos.square(weakSide); + Square weakKing = pos.square(weakSide); // Case 1: Defending king blocks the pawn, and cannot be driven away - if ( (forward_file_bb(strongSide, pawnSq) & weakKingSq) - && ( opposite_colors(weakKingSq, strongBishopSq) - || relative_rank(strongSide, weakKingSq) <= RANK_6)) + if ( (forward_file_bb(strongSide, strongPawn) & weakKing) + && ( opposite_colors(weakKing, strongBishop) + || relative_rank(strongSide, weakKing) <= RANK_6)) return SCALE_FACTOR_DRAW; // Case 2: Opposite colored bishops - if (opposite_colors(strongBishopSq, weakBishopSq)) + if (opposite_colors(strongBishop, weakBishop)) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -629,36 +633,36 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 2)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Square wbsq = pos.square(strongSide); - Square bbsq = pos.square(weakSide); + Square strongBishop = pos.square(strongSide); + Square weakBishop = pos.square(weakSide); - if (!opposite_colors(wbsq, bbsq)) + if (!opposite_colors(strongBishop, weakBishop)) return SCALE_FACTOR_NONE; - Square ksq = pos.square(weakSide); - Square psq1 = pos.squares(strongSide)[0]; - Square psq2 = pos.squares(strongSide)[1]; + Square weakKing = pos.square(weakSide); + Square strongPawn1 = pos.squares(strongSide)[0]; + Square strongPawn2 = pos.squares(strongSide)[1]; Square blockSq1, blockSq2; - if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2)) + if (relative_rank(strongSide, strongPawn1) > relative_rank(strongSide, strongPawn2)) { - blockSq1 = psq1 + pawn_push(strongSide); - blockSq2 = make_square(file_of(psq2), rank_of(psq1)); + blockSq1 = strongPawn1 + pawn_push(strongSide); + blockSq2 = make_square(file_of(strongPawn2), rank_of(strongPawn1)); } else { - blockSq1 = psq2 + pawn_push(strongSide); - blockSq2 = make_square(file_of(psq1), rank_of(psq2)); + blockSq1 = strongPawn2 + pawn_push(strongSide); + blockSq2 = make_square(file_of(strongPawn1), rank_of(strongPawn2)); } - switch (distance(psq1, psq2)) + switch (distance(strongPawn1, strongPawn2)) { case 0: // Both pawns are on the same file. It's an easy draw if the defender firmly // controls some square in the frontmost pawn's path. - if ( file_of(ksq) == file_of(blockSq1) - && relative_rank(strongSide, ksq) >= relative_rank(strongSide, blockSq1) - && opposite_colors(ksq, wbsq)) + if ( file_of(weakKing) == file_of(blockSq1) + && relative_rank(strongSide, weakKing) >= relative_rank(strongSide, blockSq1) + && opposite_colors(weakKing, strongBishop)) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; @@ -667,16 +671,16 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // Pawns on adjacent files. It's a draw if the defender firmly controls the // square in front of the frontmost pawn's path, and the square diagonally // behind this square on the file of the other pawn. - if ( ksq == blockSq1 - && opposite_colors(ksq, wbsq) - && ( bbsq == blockSq2 + if ( weakKing == blockSq1 + && opposite_colors(weakKing, strongBishop) + && ( weakBishop == blockSq2 || (attacks_bb(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP)) - || distance(psq1, psq2) >= 2)) + || distance(strongPawn1, strongPawn2) >= 2)) return SCALE_FACTOR_DRAW; - else if ( ksq == blockSq2 - && opposite_colors(ksq, wbsq) - && ( bbsq == blockSq1 + else if ( weakKing == blockSq2 + && opposite_colors(weakKing, strongBishop) + && ( weakBishop == blockSq1 || (attacks_bb(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP)))) return SCALE_FACTOR_DRAW; else @@ -698,14 +702,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, BishopValueMg, 1)); assert(verify_material(pos, weakSide, KnightValueMg, 0)); - Square pawnSq = pos.square(strongSide); - Square strongBishopSq = pos.square(strongSide); - Square weakKingSq = pos.square(weakSide); + Square strongPawn = pos.square(strongSide); + Square strongBishop = pos.square(strongSide); + Square weakKing = pos.square(weakSide); - if ( file_of(weakKingSq) == file_of(pawnSq) - && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq) - && ( opposite_colors(weakKingSq, strongBishopSq) - || relative_rank(strongSide, weakKingSq) <= RANK_6)) + if ( file_of(weakKing) == file_of(strongPawn) + && relative_rank(strongSide, strongPawn) < relative_rank(strongSide, weakKing) + && ( opposite_colors(weakKing, strongBishop) + || relative_rank(strongSide, weakKing) <= RANK_6)) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -724,18 +728,18 @@ ScaleFactor Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); // Assume strongSide is white and the pawn is on files A-D - Square wksq = normalize(pos, strongSide, pos.square(strongSide)); - Square bksq = normalize(pos, strongSide, pos.square(weakSide)); - Square psq = normalize(pos, strongSide, pos.square(strongSide)); + Square strongKing = normalize(pos, strongSide, pos.square(strongSide)); + Square weakKing = normalize(pos, strongSide, pos.square(weakSide)); + Square strongPawn = normalize(pos, strongSide, pos.square(strongSide)); Color us = strongSide == pos.side_to_move() ? WHITE : BLACK; // If the pawn has advanced to the fifth rank or further, and is not a // rook pawn, it's too dangerous to assume that it's at least a draw. - if (rank_of(psq) >= RANK_5 && file_of(psq) != FILE_A) + if (rank_of(strongPawn) >= RANK_5 && file_of(strongPawn) != FILE_A) return SCALE_FACTOR_NONE; // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw, // it's probably at least a draw even with the pawn. - return Bitbases::probe(wksq, psq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; + return Bitbases::probe(strongKing, strongPawn, weakKing, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; } From e9966d9a8ec371477f49bfa0eb69fa756e078fda Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Mon, 22 Jun 2020 12:52:31 +0300 Subject: [PATCH 134/142] Introduce bonus for queen infiltration Idea is that queen feels much better when it can't be kicked away now or later by pawn moves, especially in endgame. Special thanks to Linmiao Xu for the original idea of this patch. passed STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 84008 W: 16271 L: 15958 D: 51779 Ptnml(0-2): 1476, 9688, 19420, 9887, 1533 https://tests.stockfishchess.org/tests/view/5eee7ca0447c5b640047a439 passed LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 11720 W: 1522 L: 1328 D: 8870 Ptnml(0-2): 52, 1021, 3574, 1107, 106 https://tests.stockfishchess.org/tests/view/5eefc588122d6514328d75f9 closes https://github.com/official-stockfish/Stockfish/pull/2759 Bench: 4471740 --- src/evaluate.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3b0891a2..8b4a27bc 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -143,16 +143,17 @@ namespace { constexpr Score ReachableOutpost = S( 31, 22); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); + constexpr Score QueenInfiltration = S( -2, 14); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnKingRing = S( 16, 0); - constexpr Score RookOnQueenFile = S( 5, 9); - constexpr Score SliderOnQueen = S( 59, 18); + constexpr Score RookOnQueenFile = S( 6, 11); + constexpr Score SliderOnQueen = S( 60, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); constexpr Score TrappedRook = S( 55, 13); - constexpr Score WeakQueen = S( 51, 14); - constexpr Score WeakQueenProtection = S( 15, 0); + constexpr Score WeakQueen = S( 56, 15); + constexpr Score WeakQueenProtection = S( 14, 0); #undef S @@ -373,6 +374,10 @@ namespace { Bitboard queenPinners; if (pos.slider_blockers(pos.pieces(Them, ROOK, BISHOP), s, queenPinners)) score -= WeakQueen; + + // Bonus for queen on weak square in enemy camp + if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s)) + score += QueenInfiltration; } } if (T) From bbe98576846ad44ca531cdb6f42bf3eefa7d47c5 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 23 Jun 2020 14:55:52 +0300 Subject: [PATCH 135/142] Do less futility pruning for captures. The idea of this patch is that if capture can be described as "less valuable piece takes more valuable piece" it's not really correct to add only piece value of captured piece to static evaluation since there can be more threats in other places and opponent can't really do much but recapture our capturing piece which leaves us space for more captures thus winning more material and increasing static eval. passed STC https://tests.stockfishchess.org/tests/view/5ef0167b122d6514328d760f LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 24736 W: 4838 L: 4607 D: 15291 Ptnml(0-2): 438, 2812, 5648, 3021, 449 passed LTC https://tests.stockfishchess.org/tests/view/5ef073bc122d6514328d7693 LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 46152 W: 5865 L: 5567 D: 34720 Ptnml(0-2): 312, 4160, 13886, 4354, 364 closes https://github.com/official-stockfish/Stockfish/pull/2761 bench 4789930 --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index 563d1aab..671ac489 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1026,6 +1026,7 @@ moves_loop: // When in check, search starts from here if ( !givesCheck && lmrDepth < 6 && !(PvNode && abs(bestValue) < 2) + && PieceValue[MG][type_of(movedPiece)] >= PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] && !ss->inCheck && ss->staticEval + 267 + 391 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; From 527d832a6de81c455cc8818e85c309fa1443f862 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 23 Jun 2020 10:41:53 +0200 Subject: [PATCH 136/142] Support ARCH=armv8 in Makefile (#2355) Tested with bench run after compiling with - g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 - clang version 3.8.1-24 on ThunderX CN8890. closes https://github.com/official-stockfish/Stockfish/pull/2760 fixes https://github.com/official-stockfish/Stockfish/issues/2355 No functional change. --- src/Makefile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Makefile b/src/Makefile index 41c2aff6..83e0bb14 100644 --- a/src/Makefile +++ b/src/Makefile @@ -133,6 +133,12 @@ ifeq ($(ARCH),armv7) prefetch = yes endif +ifeq ($(ARCH),armv8) + arch = armv8-a + bits = 64 + prefetch = yes +endif + ifeq ($(ARCH),ppc-32) arch = ppc endif @@ -164,7 +170,7 @@ ifeq ($(COMP),gcc) CXX=g++ CXXFLAGS += -pedantic -Wextra -Wshadow - ifeq ($(ARCH),armv7) + ifeq ($(ARCH),$(filter $(ARCH),armv7 armv8)) ifeq ($(OS),Android) CXXFLAGS += -m$(bits) LDFLAGS += -m$(bits) @@ -221,7 +227,7 @@ ifeq ($(COMP),clang) endif endif - ifeq ($(ARCH),armv7) + ifeq ($(ARCH),$(filter $(ARCH),armv7 armv8)) ifeq ($(OS),Android) CXXFLAGS += -m$(bits) LDFLAGS += -m$(bits) @@ -391,6 +397,7 @@ help: @echo "ppc-64 > PPC 64-bit" @echo "ppc-32 > PPC 32-bit" @echo "armv7 > ARMv7 32-bit" + @echo "armv8 > ARMv8 64-bit" @echo "general-64 > unspecified 64-bit" @echo "general-32 > unspecified 32-bit" @echo "" @@ -492,7 +499,8 @@ config-sanity: @test "$(sanitize)" = "undefined" || test "$(sanitize)" = "thread" || test "$(sanitize)" = "address" || test "$(sanitize)" = "no" @test "$(optimize)" = "yes" || test "$(optimize)" = "no" @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ - test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7" + test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || \ + test "$(arch)" = "armv7" || test "$(arch)" = "armv8-a" @test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" From 208c53df0fc289466def7deae58f687957efb734 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 24 Jun 2020 16:23:31 +0200 Subject: [PATCH 137/142] Remove 'Minimum Thinking Time' UCI option. the option was, since at least 2014, not correctly implemented, ignoring all dynamic adjustments to optimum time in search. Instead of fixing it, remove it, no need to expose an option that will influence time management negatively. closes https://github.com/official-stockfish/Stockfish/pull/2765 No functional change. --- src/timeman.cpp | 3 +-- src/ucioption.cpp | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index d27962b7..a61c36d7 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -35,7 +35,6 @@ TimeManagement Time; // Our global time management object void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { - TimePoint minThinkingTime = TimePoint(Options["Minimum Thinking Time"]); TimePoint moveOverhead = TimePoint(Options["Move Overhead"]); TimePoint slowMover = TimePoint(Options["Slow Mover"]); TimePoint npmsec = TimePoint(Options["nodestime"]); @@ -91,7 +90,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { } // Never use more than 80% of the available time for this move - optimumTime = std::max(minThinkingTime, TimePoint(opt_scale * timeLeft)); + optimumTime = TimePoint(opt_scale * timeLeft); maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime)); if (Options["Ponder"]) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 7037ea57..871edb29 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -68,7 +68,6 @@ void init(OptionsMap& o) { o["MultiPV"] << Option(1, 1, 500); o["Skill Level"] << Option(20, 0, 20); o["Move Overhead"] << Option(10, 0, 5000); - o["Minimum Thinking Time"] << Option( 0, 0, 5000); o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); o["UCI_Chess960"] << Option(false); From 11483fe6d942a4fee6fa272f72251d6b6d6d7454 Mon Sep 17 00:00:00 2001 From: UnaiCorzo Date: Tue, 23 Jun 2020 17:56:38 +0200 Subject: [PATCH 138/142] Makefile: support lto on mingw, default to 64bits Clean and organize uppercase and spaces fixes https://github.com/official-stockfish/Stockfish/issues/2731 closes https://github.com/official-stockfish/Stockfish/pull/2763 No functional change --- AUTHORS | 1 + src/Makefile | 34 +++++++++++----------------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/AUTHORS b/AUTHORS index 1cd7ff54..f08d71d3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -155,6 +155,7 @@ Tom Vijlbrief (tomtor) Tomasz Sobczyk (Sopel97) Torsten Franz (torfranz, tfranzer) Tracey Emery (basepr1me) +Unai Corzo (unaiic) Uri Blass (uriblass) Vince Negri (cuddlestmonkey) diff --git a/src/Makefile b/src/Makefile index 83e0bb14..81731e66 100644 --- a/src/Makefile +++ b/src/Makefile @@ -54,7 +54,7 @@ endif ### Section 2. High-level Configuration ### ========================================================================== # -# flag --- Comp switch --- Description +# flag --- Comp switch --- Description # ---------------------------------------------------------------------------- # # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode @@ -77,43 +77,42 @@ endif optimize = yes debug = no sanitize = no -bits = 32 +bits = 64 prefetch = no popcnt = no sse = no pext = no ### 2.2 Architecture specific - ifeq ($(ARCH),general-32) arch = any + bits = 32 endif ifeq ($(ARCH),x86-32-old) arch = i386 + bits = 32 endif ifeq ($(ARCH),x86-32) arch = i386 + bits = 32 prefetch = yes sse = yes endif ifeq ($(ARCH),general-64) arch = any - bits = 64 endif ifeq ($(ARCH),x86-64) arch = x86_64 - bits = 64 prefetch = yes sse = yes endif ifeq ($(ARCH),x86-64-modern) arch = x86_64 - bits = 64 prefetch = yes popcnt = yes sse = yes @@ -121,7 +120,6 @@ endif ifeq ($(ARCH),x86-64-bmi2) arch = x86_64 - bits = 64 prefetch = yes popcnt = yes sse = yes @@ -131,6 +129,7 @@ endif ifeq ($(ARCH),armv7) arch = armv7 prefetch = yes + bits = 32 endif ifeq ($(ARCH),armv8) @@ -141,22 +140,20 @@ endif ifeq ($(ARCH),ppc-32) arch = ppc + bits = 32 endif ifeq ($(ARCH),ppc-64) arch = ppc64 - bits = 64 popcnt = yes prefetch = yes endif - ### ========================================================================== -### Section 3. Low-level configuration +### Section 3. Low-level Configuration ### ========================================================================== ### 3.1 Selecting compiler (default = gcc) - CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++11 $(EXTRACXXFLAGS) DEPENDFLAGS += -std=c++11 LDFLAGS += $(EXTRALDFLAGS) @@ -347,17 +344,10 @@ endif ### needs access to the optimization flags. ifeq ($(optimize),yes) ifeq ($(debug), no) - ifeq ($(comp),$(filter $(comp),gcc clang)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) endif - - ifeq ($(comp),mingw) - ifeq ($(KERNEL),Linux) - CXXFLAGS += -flto - LDFLAGS += $(CXXFLAGS) - endif - endif endif endif @@ -368,9 +358,8 @@ ifeq ($(OS), Android) LDFLAGS += -fPIE -pie endif - ### ========================================================================== -### Section 4. Public targets +### Section 4. Public Targets ### ========================================================================== help: @@ -468,7 +457,7 @@ default: help ### ========================================================================== -### Section 5. Private targets +### Section 5. Private Targets ### ========================================================================== all: $(EXE) .depend @@ -551,4 +540,3 @@ icc-profile-use: -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null -include .depend - From ab5cd8340f2f7f8730aa7c77476edf4a98a166e4 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 24 Jun 2020 22:19:58 +0200 Subject: [PATCH 139/142] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2756 No functional change --- src/bitboard.h | 29 ++++++++++++++++++----------- src/endgame.cpp | 14 +++++++------- src/evaluate.cpp | 26 +++++++++++++++----------- src/material.cpp | 19 +++++++++++-------- src/material.h | 2 +- src/misc.cpp | 21 ++++++++++++--------- src/pawns.cpp | 7 +++++++ src/position.cpp | 4 ++-- src/position.h | 1 + src/psqt.cpp | 11 ++++++----- src/search.cpp | 35 +++++++++++++++++++---------------- src/thread.cpp | 13 ++++++++++--- src/timeman.cpp | 11 ++++++----- src/tt.cpp | 3 ++- src/tt.h | 4 ++-- src/tune.cpp | 2 +- src/types.h | 6 +++--- src/ucioption.cpp | 2 +- 18 files changed, 124 insertions(+), 86 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 0f55810c..1c598108 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -110,6 +110,7 @@ inline Bitboard square_bb(Square s) { return SquareBB[s]; } + /// Overloads of bitwise operators between a Bitboard and a Square for testing /// whether a given bit is set in a bitboard, and for setting and clearing bits. @@ -200,10 +201,11 @@ inline Bitboard adjacent_files_bb(Square s) { return shift(file_bb(s)) | shift(file_bb(s)); } -/// line_bb(Square, Square) returns a Bitboard representing an entire line -/// (from board edge to board edge) that intersects the given squares. -/// If the given squares are not on a same file/rank/diagonal, return 0. -/// Ex. line_bb(SQ_C4, SQ_F7) returns a bitboard with the A2-G8 diagonal. + +/// line_bb(Square, Square) returns a bitboard representing an entire line, +/// from board edge to board edge, that intersects the given squares. If the +/// given squares are not on a same file/rank/diagonal, returns 0. For instance, +/// line_bb(SQ_C4, SQ_F7) will return a bitboard with the A2-G8 diagonal. inline Bitboard line_bb(Square s1, Square s2) { @@ -211,10 +213,11 @@ inline Bitboard line_bb(Square s1, Square s2) { return LineBB[s1][s2]; } -/// between_bb() returns a Bitboard representing squares that are linearly -/// between the given squares (excluding the given squares). -/// If the given squares are not on a same file/rank/diagonal, return 0. -/// Ex. between_bb(SQ_C4, SQ_F7) returns a bitboard with squares D5 and E6. + +/// between_bb() returns a bitboard representing squares that are linearly +/// between the given squares (excluding the given squares). If the given +/// squares are not on a same file/rank/diagonal, return 0. For instance, +/// between_bb(SQ_C4, SQ_F7) will return a bitboard with squares D5 and E6. inline Bitboard between_bb(Square s1, Square s2) { Bitboard b = line_bb(s1, s2) & ((AllSquares << s1) ^ (AllSquares << s2)); @@ -241,8 +244,8 @@ inline Bitboard forward_file_bb(Color c, Square s) { /// pawn_attack_span() returns a bitboard representing all the squares that can -/// be attacked by a pawn of the given color when it moves along its file, -/// starting from the given square. +/// be attacked by a pawn of the given color when it moves along its file, starting +/// from the given square. inline Bitboard pawn_attack_span(Color c, Square s) { return forward_ranks_bb(c, s) & adjacent_files_bb(s); @@ -276,7 +279,9 @@ template<> inline int distance(Square x, Square y) { return SquareDistan inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); } inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } -/// Return the target square bitboard if we do not step off the board, empty otherwise + +/// safe_destination() returns the bitboard of target square for the given step +/// from the given square. If the step is off the board, returns empty bitboard. inline Bitboard safe_destination(Square s, int step) { @@ -284,6 +289,7 @@ inline Bitboard safe_destination(Square s, int step) return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); } + /// attacks_bb(Square) returns the pseudo attacks of the give piece type /// assuming an empty board. @@ -295,6 +301,7 @@ inline Bitboard attacks_bb(Square s) { return PseudoAttacks[Pt][s]; } + /// attacks_bb(Square, Bitboard) returns the attacks by the given piece /// assuming the board is occupied according to the passed Bitboard. /// Sliding piece attacks do not continue passed an occupied square. diff --git a/src/endgame.cpp b/src/endgame.cpp index d9e76348..be0755a8 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -268,7 +268,7 @@ Value Endgame::operator()(const Position& pos) const { } -/// KQ vs KR. This is almost identical to KX vs K: We give the attacking +/// KQ vs KR. This is almost identical to KX vs K: we give the attacking /// king a bonus for having the kings close together, and for forcing the /// defending king towards the edge. If we also take care to avoid null move for /// the defending side in the search, this is usually sufficient to win KQ vs KR. @@ -291,7 +291,7 @@ Value Endgame::operator()(const Position& pos) const { /// KNN vs KP. Very drawish, but there are some mate opportunities if we can -// press the weakSide King to a corner before the pawn advances too much. +/// press the weakSide King to a corner before the pawn advances too much. template<> Value Endgame::operator()(const Position& pos) const { @@ -352,7 +352,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square weakPawn = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); // There's potential for a draw if our pawn is blocked on the 7th rank, - // the bishop cannot attack it or they only have one pawn left + // the bishop cannot attack it or they only have one pawn left. if ( relative_rank(strongSide, weakPawn) == RANK_7 && (strongPawns & (weakPawn + pawn_push(weakSide))) && (opposite_colors(strongBishop, weakPawn) || !more_than_one(strongPawns))) @@ -365,7 +365,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // closer. (I think this rule only fails in practically // unreachable positions such as 5k1K/6p1/6P1/8/8/3B4/8/8 w // and positions where qsearch will immediately correct the - // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w) + // problem such as 8/4k1p1/6P1/1K6/3B4/8/8/8 w). if ( relative_rank(strongSide, weakKing) >= RANK_7 && weakKingDist <= 2 && weakKingDist <= strongKingDist) @@ -576,7 +576,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// K and two or more pawns vs K. There is just a single rule here: If all pawns +/// K and two or more pawns vs K. There is just a single rule here: if all pawns /// are on the same rook file and are blocked by the defending king, it's a draw. template<> ScaleFactor Endgame::operator()(const Position& pos) const { @@ -693,7 +693,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// KBP vs KN. There is a single rule: If the defending king is somewhere along +/// KBP vs KN. There is a single rule: if the defending king is somewhere along /// the path of the pawn, and the square of the king is not of the same color as /// the stronger side's bishop, it's a draw. template<> @@ -717,7 +717,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { /// KP vs KP. This is done by removing the weakest side's pawn and probing the -/// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably +/// KP vs K bitbase: if the weakest side has a draw without the pawn, it probably /// has at least a draw with the pawn as well. The exception is when the stronger /// side's pawn is far advanced and not on a rook file; in this case it is often /// possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1). diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8b4a27bc..60ec9c72 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -127,23 +127,23 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopKingProtector = S( 6, 9); constexpr Score BishopOnKingRing = S( 24, 0); + constexpr Score BishopOutpost = S( 30, 23); + constexpr Score BishopPawns = S( 3, 7); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); - constexpr Score BishopKingProtector = S( 6, 9); constexpr Score KnightKingProtector = S( 8, 9); constexpr Score KnightOnQueen = S( 16, 11); + constexpr Score KnightOutpost = S( 56, 36); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score KnightOutpost = S( 56, 36); - constexpr Score BishopOutpost = S( 30, 23); - constexpr Score ReachableOutpost = S( 31, 22); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score QueenInfiltration = S( -2, 14); + constexpr Score ReachableOutpost = S( 31, 22); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnKingRing = S( 16, 0); constexpr Score RookOnQueenFile = S( 6, 11); @@ -152,8 +152,9 @@ namespace { constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); constexpr Score TrappedRook = S( 55, 13); - constexpr Score WeakQueen = S( 56, 15); constexpr Score WeakQueenProtection = S( 14, 0); + constexpr Score WeakQueen = S( 56, 15); + #undef S @@ -216,6 +217,7 @@ namespace { // Evaluation::initialize() computes king and pawn attacks, and the king ring // bitboard for a given color. This is done at the beginning of the evaluation. + template template void Evaluation::initialize() { @@ -255,6 +257,7 @@ namespace { // Evaluation::pieces() scores pieces of a given color and type + template template Score Evaluation::pieces() { @@ -377,7 +380,7 @@ namespace { // Bonus for queen on weak square in enemy camp if (relative_rank(Us, s) > RANK_4 && (~pe->pawn_attacks_span(Them) & s)) - score += QueenInfiltration; + score += QueenInfiltration; } } if (T) @@ -388,6 +391,7 @@ namespace { // Evaluation::king() assigns bonuses and penalties to a king of a given color + template template Score Evaluation::king() const { @@ -496,6 +500,7 @@ namespace { // Evaluation::threats() assigns bonuses according to the types of the // attacking and the attacked pieces. + template template Score Evaluation::threats() const { @@ -721,8 +726,8 @@ namespace { // Evaluation::winnable() adjusts the mg and eg score components based on the - // known attacking/defending status of the players. - // A single value is derived from the mg and eg values and returned. + // known attacking/defending status of the players. A single value is derived + // by interpolation from the mg and eg values and returned. template Value Evaluation::winnable(Score score) const { @@ -828,12 +833,11 @@ namespace { return pos.side_to_move() == WHITE ? v : -v; // Main evaluation begins here - initialize(); initialize(); // Pieces evaluated first (also populates attackedBy, attackedBy2). - // Note that the order of evaluation of the terms is left unspecified + // Note that the order of evaluation of the terms is left unspecified. score += pieces() - pieces() + pieces() - pieces() + pieces() - pieces() diff --git a/src/material.cpp b/src/material.cpp index 93699f5f..bb25d3ca 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -44,12 +44,12 @@ namespace { constexpr int QuadraticTheirs[][PIECE_TYPE_NB] = { // THEIR PIECES // pair pawn knight bishop rook queen - { 0 }, // Bishop pair - { 36, 0 }, // Pawn - { 9, 63, 0 }, // Knight OUR PIECES - { 59, 65, 42, 0 }, // Bishop - { 46, 39, 24, -24, 0 }, // Rook - { 97, 100, -42, 137, 268, 0 } // Queen + { }, // Bishop pair + { 36, }, // Pawn + { 9, 63, }, // Knight OUR PIECES + { 59, 65, 42, }, // Bishop + { 46, 39, 24, -24, }, // Rook + { 97, 100, -42, 137, 268, } // Queen }; // Endgame evaluation and scaling functions are accessed directly and not through @@ -79,8 +79,10 @@ namespace { && pos.count(~us) >= 1; } + /// imbalance() calculates the imbalance by comparing the piece count of each /// piece type for both colors. + template int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { @@ -94,9 +96,9 @@ namespace { if (!pieceCount[Us][pt1]) continue; - int v = 0; + int v = QuadraticOurs[pt1][pt1] * pieceCount[Us][pt1]; - for (int pt2 = NO_PIECE_TYPE; pt2 <= pt1; ++pt2) + for (int pt2 = NO_PIECE_TYPE; pt2 < pt1; ++pt2) v += QuadraticOurs[pt1][pt2] * pieceCount[Us][pt2] + QuadraticTheirs[pt1][pt2] * pieceCount[Them][pt2]; @@ -110,6 +112,7 @@ namespace { namespace Material { + /// Material::probe() looks up the current position's material configuration in /// the material hash table. It returns a pointer to the Entry if the position /// is found. Otherwise a new Entry is computed and stored there, so we don't diff --git a/src/material.h b/src/material.h index 9ab1d81c..21647f23 100644 --- a/src/material.h +++ b/src/material.h @@ -44,7 +44,7 @@ struct Entry { bool specialized_eval_exists() const { return evaluationFunction != nullptr; } Value evaluate(const Position& pos) const { return (*evaluationFunction)(pos); } - // scale_factor takes a position and a color as input and returns a scale factor + // scale_factor() takes a position and a color as input and returns a scale factor // for the given color. We have to provide the position in addition to the color // because the scale factor may also be a function which should be applied to // the position. For instance, in KBP vs K endgames, the scaling function looks diff --git a/src/misc.cpp b/src/misc.cpp index c6254784..2bc05c5b 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -294,9 +294,10 @@ void prefetch(void* addr) { #endif -/// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages. -/// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free. -/// With c++17 some of this functionality can be simplified. +/// aligned_ttmem_alloc() will return suitably aligned memory, and if possible use large pages. +/// The returned pointer is the aligned one, while the mem argument is the one that needs +/// to be passed to free. With c++17 some of this functionality could be simplified. + #if defined(__linux__) && !defined(__ANDROID__) void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { @@ -336,17 +337,17 @@ static void* aligned_ttmem_alloc_large_pages(size_t allocSize) { tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds, - // we still need to query GetLastError() to ensure that the privileges were actually obtained... + // we still need to query GetLastError() to ensure that the privileges were actually obtained. if (AdjustTokenPrivileges( hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) && GetLastError() == ERROR_SUCCESS) { - // round up size to full pages and allocate + // Round up size to full pages and allocate allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1); mem = VirtualAlloc( NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); - // privilege no longer needed, restore previous state + // Privilege no longer needed, restore previous state AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL); } } @@ -360,7 +361,7 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { static bool firstCall = true; - // try to allocate large pages + // Try to allocate large pages mem = aligned_ttmem_alloc_large_pages(allocSize); // Suppress info strings on the first call. The first call occurs before 'uci' @@ -374,7 +375,7 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { } firstCall = false; - // fall back to regular, page aligned, allocation if necessary + // Fall back to regular, page aligned, allocation if necessary if (!mem) mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); @@ -394,7 +395,9 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { #endif -/// aligned_ttmem_free will free the previously allocated ttmem + +/// aligned_ttmem_free() will free the previously allocated ttmem + #if defined(_WIN64) void aligned_ttmem_free(void* mem) { diff --git a/src/pawns.cpp b/src/pawns.cpp index 597dff2b..d741b2ef 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -66,6 +66,12 @@ namespace { #undef S #undef V + + /// evaluate() calculates a score for the static pawn structure of the given position. + /// We cannot use the location of pieces or king in this function, as the evaluation + /// of the pawn structure will be stored in a small cache for speed reasons, and will + /// be re-used even when the pieces have moved. + template Score evaluate(const Position& pos, Pawns::Entry* e) { @@ -170,6 +176,7 @@ namespace { namespace Pawns { + /// Pawns::probe() looks up the current position's pawns configuration in /// the pawns hash table. It returns a pointer to the Entry if the position /// is found. Otherwise a new Entry is computed and stored there, so we don't diff --git a/src/position.cpp b/src/position.cpp index c9db6224..471ef01f 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -105,8 +105,7 @@ Key cuckoo[8192]; Move cuckooMove[8192]; -/// Position::init() initializes at startup the various arrays used to compute -/// hash keys. +/// Position::init() initializes at startup the various arrays used to compute hash keys void Position::init() { @@ -1112,6 +1111,7 @@ bool Position::see_ge(Move m, Value threshold) const { return bool(res); } + /// Position::is_draw() tests whether the position is drawn by 50-move rule /// or by repetition. It does not detect stalemates. diff --git a/src/position.h b/src/position.h index 8f8c8f7a..8cfa3920 100644 --- a/src/position.h +++ b/src/position.h @@ -56,6 +56,7 @@ struct StateInfo { int repetition; }; + /// A list to keep track of the position states along the setup moves (from the /// start position to the position just before the search starts). Needed by /// 'draw by repetition' detection. Use a std::deque because pointers to diff --git a/src/psqt.cpp b/src/psqt.cpp index 27c7a36f..c5da9785 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -101,9 +101,10 @@ constexpr Score PBonus[RANK_NB][FILE_NB] = Score psq[PIECE_NB][SQUARE_NB]; -// init() initializes piece-square tables: the white halves of the tables are -// copied from Bonus[] adding the piece value, then the black halves of the -// tables are initialized by flipping and changing the sign of the white scores. + +// PSQT::init() initializes piece-square tables: the white halves of the tables are +// copied from Bonus[] and PBonus[], adding the piece value, then the black halves of +// the tables are initialized by flipping and changing the sign of the white scores. void init() { for (Piece pc : {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING}) @@ -113,8 +114,8 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { File f = File(edge_distance(file_of(s))); - psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] - : Bonus[pc][rank_of(s)][f]); + psq[ pc][s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] + : Bonus[pc][rank_of(s)][f]); psq[~pc][flip_rank(s)] = -psq[pc][s]; } } diff --git a/src/search.cpp b/src/search.cpp index 671ac489..1e2980cb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -525,7 +525,7 @@ void Thread::search() { double totalTime = rootMoves.size() == 1 ? 0 : Time.optimum() * fallingEval * reduction * bestMoveInstability; - // Stop the search if we have exceeded the totalTime, at least 1ms search. + // Stop the search if we have exceeded the totalTime, at least 1ms search if (Time.elapsed() > totalTime) { // If we are allowed to ponder do not stop the search now but @@ -627,7 +627,7 @@ namespace { || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) - : value_draw(pos.this_thread()); + : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because @@ -767,9 +767,10 @@ namespace { // Step 6. Static evaluation of the position if (ss->inCheck) { + // Skip early pruning when in check ss->staticEval = eval = VALUE_NONE; improving = false; - goto moves_loop; // Skip early pruning when in check + goto moves_loop; } else if (ttHit) { @@ -1028,7 +1029,8 @@ moves_loop: // When in check, search starts from here && !(PvNode && abs(bestValue) < 2) && PieceValue[MG][type_of(movedPiece)] >= PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] && !ss->inCheck - && ss->staticEval + 267 + 391 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) + && ss->staticEval + 267 + 391 * lmrDepth + + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; // See based pruning @@ -1074,8 +1076,8 @@ moves_loop: // When in check, search starts from here else if (singularBeta >= beta) return singularBeta; - // If the eval of ttMove is greater than beta we try also if there is an other move that - // pushes it over beta, if so also produce a cutoff + // If the eval of ttMove is greater than beta we try also if there is another + // move that pushes it over beta, if so also produce a cutoff. else if (ttValue >= beta) { ss->excludedMove = move; @@ -1153,7 +1155,7 @@ moves_loop: // When in check, search starts from here if (thisThread->ttHitAverage > 473 * TtHitAverageResolution * TtHitAverageWindow / 1024) r--; - // Reduction if other threads are searching this position. + // Reduction if other threads are searching this position if (th.marked()) r++; @@ -1290,7 +1292,7 @@ moves_loop: // When in check, search starts from here rm.pv.push_back(*m); // We record how often the best move has been changed in each - // iteration. This information is used for time management: When + // iteration. This information is used for time management: when // the best move changes frequently, we allocate some more time. if (moveCount > 1) ++thisThread->bestMoveChanges; @@ -1524,7 +1526,7 @@ moves_loop: // When in check, search starts from here } } - // Don't search moves with negative SEE values + // Do not search moves with negative SEE values if ( !ss->inCheck && !pos.see_ge(move)) continue; @@ -1571,7 +1573,7 @@ moves_loop: // When in check, search starts from here } } - // All legal moves have been searched. A special case: If we're in check + // All legal moves have been searched. A special case: if we're in check // and no legal moves were found, it is checkmate. if (ss->inCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root @@ -1588,7 +1590,7 @@ moves_loop: // When in check, search starts from here // value_to_tt() adjusts a mate or TB score from "plies to mate from the root" to - // "plies to mate from the current position". standard scores are unchanged. + // "plies to mate from the current position". Standard scores are unchanged. // The function is called before storing a value in the transposition table. Value value_to_tt(Value v, int ply) { @@ -1600,11 +1602,11 @@ moves_loop: // When in check, search starts from here } - // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate or TB score - // from the transposition table (which refers to the plies to mate/be mated - // from current position) to "plies to mate/be mated (TB win/loss) from the root". - // However, for mate scores, to avoid potentially false mate scores related to the 50 moves rule, - // and the graph history interaction, return an optimal TB score instead. + // value_from_tt() is the inverse of value_to_tt(): it adjusts a mate or TB score + // from the transposition table (which refers to the plies to mate/be mated from + // current position) to "plies to mate/be mated (TB win/loss) from the root". However, + // for mate scores, to avoid potentially false mate scores related to the 50 moves rule + // and the graph history interaction, we return an optimal TB score instead. Value value_from_tt(Value v, int ply, int r50c) { @@ -1764,6 +1766,7 @@ moves_loop: // When in check, search starts from here } // namespace + /// MainThread::check_time() is used to print debug info and, more importantly, /// to detect when we are out of available time and thus stop the search. diff --git a/src/thread.cpp b/src/thread.cpp index a27a60c6..a0ee2b25 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -52,6 +52,7 @@ Thread::~Thread() { stdThread.join(); } + /// Thread::bestMoveCount(Move move) return best move counter for the given root move int Thread::best_move_count(Move move) const { @@ -62,6 +63,7 @@ int Thread::best_move_count(Move move) const { return rm != rootMoves.begin() + pvLast ? rm->bestMoveCount : 0; } + /// Thread::clear() reset histories, usually before a new game void Thread::clear() { @@ -81,6 +83,7 @@ void Thread::clear() { } } + /// Thread::start_searching() wakes up the thread that will start the search void Thread::start_searching() { @@ -158,7 +161,8 @@ void ThreadPool::set(size_t requested) { } } -/// ThreadPool::clear() sets threadPool data to initial values. + +/// ThreadPool::clear() sets threadPool data to initial values void ThreadPool::clear() { @@ -170,6 +174,7 @@ void ThreadPool::clear() { main()->previousTimeReduction = 1.0; } + /// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and /// returns immediately. Main thread will wake up other threads and start the search. @@ -250,7 +255,8 @@ Thread* ThreadPool::get_best_thread() const { return bestThread; } -/// Start non-main threads. + +/// Start non-main threads void ThreadPool::start_searching() { @@ -259,7 +265,8 @@ void ThreadPool::start_searching() { th->start_searching(); } -/// Wait for non-main threads. + +/// Wait for non-main threads void ThreadPool::wait_for_search_finished() const { diff --git a/src/timeman.cpp b/src/timeman.cpp index a61c36d7..546eadd2 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -28,10 +28,11 @@ TimeManagement Time; // Our global time management object -/// init() is called at the beginning of the search and calculates the bounds -/// of time allowed for the current game ply. We currently support: -// 1) x basetime (+z increment) -// 2) x moves in y seconds (+z increment) + +/// TimeManagement::init() is called at the beginning of the search and calculates +/// the bounds of time allowed for the current game ply. We currently support: +// 1) x basetime (+ z increment) +// 2) x moves in y seconds (+ z increment) void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { @@ -60,7 +61,7 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { startTime = limits.startTime; - //Maximum move horizon of 50 moves + // Maximum move horizon of 50 moves int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; // Make sure timeLeft is > 0 since we may use it as a divisor diff --git a/src/tt.cpp b/src/tt.cpp index d0a5d4e0..34590903 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -30,7 +30,7 @@ TranspositionTable TT; // Our global transposition table -/// TTEntry::save populates the TTEntry with a new node's data, possibly +/// TTEntry::save() populates the TTEntry with a new node's data, possibly /// overwriting an old position. Update is not atomic and can be racy. void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { @@ -107,6 +107,7 @@ void TranspositionTable::clear() { th.join(); } + /// TranspositionTable::probe() looks up the current position in the transposition /// table. It returns true and a pointer to the TTEntry if the position is found. /// Otherwise, it returns false and a pointer to an empty or least valuable TTEntry diff --git a/src/tt.h b/src/tt.h index 3e1d0e99..e18db8ce 100644 --- a/src/tt.h +++ b/src/tt.h @@ -60,8 +60,8 @@ private: /// A TranspositionTable is an array of Cluster, of size clusterCount. Each /// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry /// contains information on exactly one position. The size of a Cluster should -/// divide the size of a cache line for best performance, -/// as the cacheline is prefetched when possible. +/// divide the size of a cache line for best performance, as the cacheline is +/// prefetched when possible. class TranspositionTable { diff --git a/src/tune.cpp b/src/tune.cpp index 696b4cb8..c1b1c76b 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -70,7 +70,7 @@ static void make_option(const string& n, int v, const SetRange& r) { Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune); LastOption = &Options[n]; - // Print formatted parameters, ready to be copy-pasted in fishtest + // Print formatted parameters, ready to be copy-pasted in Fishtest std::cout << n << "," << v << "," << r(v).first << "," << r(v).second << "," diff --git a/src/types.h b/src/types.h index 969d4e65..0c512f5b 100644 --- a/src/types.h +++ b/src/types.h @@ -349,16 +349,16 @@ constexpr Color operator~(Color c) { return Color(c ^ BLACK); // Toggle color } -constexpr Square flip_rank(Square s) { +constexpr Square flip_rank(Square s) { // Swap A1 <-> A8 return Square(s ^ SQ_A8); } -constexpr Square flip_file(Square s) { +constexpr Square flip_file(Square s) { // Swap A1 <-> H1 return Square(s ^ SQ_H1); } constexpr Piece operator~(Piece pc) { - return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT + return Piece(pc ^ 8); // Swap color of piece B_KNIGHT <-> W_KNIGHT } constexpr CastlingRights operator&(Color c, CastlingRights cr) { diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 871edb29..c268c975 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -52,7 +52,7 @@ bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const } -/// init() initializes the UCI options to their hard-coded default values +/// UCI::init() initializes the UCI options to their hard-coded default values void init(OptionsMap& o) { From a84e3ac287fa2c2db5ee58faabdb31943acc78d0 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 24 Jun 2020 23:03:00 +0200 Subject: [PATCH 140/142] Simplify use_time_management() and allow composing like other `go` commands wtime/btime can now be composed. `go depth 10 wtime 100` will let the engine use standard time management but stop if depth 10 is reached. fixes https://github.com/official-stockfish/Stockfish/issues/2767 closes https://github.com/official-stockfish/Stockfish/pull/2768 No functional change --- src/search.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.h b/src/search.h index 1653ce92..3e855c8b 100644 --- a/src/search.h +++ b/src/search.h @@ -91,7 +91,7 @@ struct LimitsType { } bool use_time_management() const { - return !(mate | movetime | depth | nodes | perft | infinite); + return time[WHITE] || time[BLACK]; } std::vector searchmoves; From aecfca2dc2d760df257e18cd6b29d266a3c3e68a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 25 Jun 2020 12:42:25 +0200 Subject: [PATCH 141/142] support popcnt on armv8 * Supports popcnt (thanks @daylen) * bits = 64 is now the default Tested with g++ (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0 on ThunderX CN8890, yields about 9% speedup. Also tested with clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final). closes https://github.com/official-stockfish/Stockfish/pull/2770 No functional change. --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 81731e66..492403d3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -134,8 +134,8 @@ endif ifeq ($(ARCH),armv8) arch = armv8-a - bits = 64 prefetch = yes + popcnt = yes endif ifeq ($(ARCH),ppc-32) @@ -322,7 +322,7 @@ endif ### 3.6 popcnt ifeq ($(popcnt),yes) - ifeq ($(arch),ppc64) + ifeq ($(arch),$(filter $(arch),ppc64 armv8-a)) CXXFLAGS += -DUSE_POPCNT else ifeq ($(comp),icc) CXXFLAGS += -msse3 -DUSE_POPCNT From ca41ee6632368676a2fb98fd2970ac9b183f0aa9 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 27 Jun 2020 08:23:46 +0200 Subject: [PATCH 142/142] Revert LTO for mingw on windows. LTO with static linking is still only working with the latest versions of gcc, causing problems for some devs. on a modern mingw toolchain LTO optimizations can still be enabled as: ``` CXXFLAGS='-flto' make -j ARCH=x86-64-modern COMP=mingw profile-build ``` fixes https://github.com/official-stockfish/Stockfish/issues/2769 closes https://github.com/official-stockfish/Stockfish/pull/2774 No functional change. --- src/Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 492403d3..c3660a20 100644 --- a/src/Makefile +++ b/src/Makefile @@ -344,10 +344,20 @@ endif ### needs access to the optimization flags. ifeq ($(optimize),yes) ifeq ($(debug), no) - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang)) CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) endif + +# To use LTO and static linking on windows, the tool chain requires a recent gcc: +# gcc version 10.1 in msys2 or TDM-GCC version 9.2 are know to work, older might not. +# So, only enable it for a cross from Linux by default. + ifeq ($(comp),mingw) + ifeq ($(KERNEL),Linux) + CXXFLAGS += -flto + LDFLAGS += $(CXXFLAGS) + endif + endif endif endif