From 215cd19108d97376284192c29790b42a0b0e618a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 21 Oct 2019 08:05:14 +0200 Subject: [PATCH 01/59] Avoid crashing on Log File opening Stockfish crashes immediately if users enter a wrong file name (or even an existing folder name) for debug log file. It may be hard for users to find out since it prints nothing. If they enter the string via a chess GUI, the chess GUI may remember and auto-send to Stockfish next time, makes Stockfish crashes all the time. Bug report by Nguyen Hong Pham in this issue: https://github.com/official-stockfish/Stockfish/issues/2365 This patch avoids the crash and instead prefers to exit gracefully with a error message on std:cerr, like we do with the fenFile for instance. Closes https://github.com/official-stockfish/Stockfish/pull/2366 No functional change. --- src/misc.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/misc.cpp b/src/misc.cpp index 17644eed..6f908fd2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -102,6 +102,13 @@ public: if (!fname.empty() && !l.file.is_open()) { l.file.open(fname, ifstream::out); + + if (!l.file.is_open()) + { + cerr << "Unable to open debug log file " << fname << endl; + exit(EXIT_FAILURE); + } + cin.rdbuf(&l.in); cout.rdbuf(&l.out); } From 7e89a71624e07c735c2230dbbf2c7dbae864916e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 21 Oct 2019 22:21:50 +0200 Subject: [PATCH 02/59] Simplify reductions on singular extension Current master employs a scheme to adjust reductions on singular nodes that is somewhat controversial, see https://github.com/official-stockfish/Stockfish/pull/2167 This patch removes this use of a search result outside of [a,b], by observing that the main effect of this code is to adjust the reduction by an average of ~2 (1.7) rather than 1. Claims the first blue at STC and LTC: STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 30142 W: 6547 L: 6442 D: 17153 http://tests.stockfishchess.org/tests/view/5daf16c40ebc5902c06da566 LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 45715 W: 7380 L: 7298 D: 31037 http://tests.stockfishchess.org/tests/view/5daf2f3c0ebc5902c06da6c7 Closes https://github.com/official-stockfish/Stockfish/pull/2367 Bench: 5115841 --- src/search.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6e59bb54..c70fbf60 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -595,16 +595,16 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; - int moveCount, captureCount, quietCount, singularLMR; + int moveCount, captureCount, quietCount; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = singularLMR = ss->moveCount = 0; + moveCount = captureCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; @@ -917,7 +917,7 @@ moves_loop: // When in check, search starts from here ss->killers); value = bestValue; - moveCountPruning = false; + singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); // Mark this node as being searched @@ -980,10 +980,7 @@ moves_loop: // When in check, search starts from here if (value < singularBeta) { extension = 1; - singularLMR++; - - if (value < singularBeta - std::min(4 * depth, 36)) - singularLMR++; + singularLMR = true; } // Multi-cut pruning @@ -1106,7 +1103,8 @@ moves_loop: // When in check, search starts from here r--; // Decrease reduction if ttMove has been singularly extended - r -= singularLMR; + if (singularLMR) + r -= 2; if (!captureOrPromotion) { From 90c0385724a0d9b6c0737bc2711ad77e315d17ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sat, 19 Oct 2019 02:20:38 +0200 Subject: [PATCH 03/59] Assorted trivial cleanups - Cleanups by Alain - Group king attacks and king defenses - Signature of futility_move_count() - Use is_discovery_check_on_king() - Simplify backward definition - Use static asserts in move generator - Factor a statement in move generator No functional change --- src/Makefile | 2 +- src/evaluate.cpp | 17 ++++++++--------- src/movegen.cpp | 9 +++------ src/pawns.cpp | 2 +- src/position.h | 3 ++- src/search.cpp | 12 ++++++------ src/syzygy/tbprobe.cpp | 8 +++----- src/thread.cpp | 10 +++++----- src/types.h | 2 +- 9 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/Makefile b/src/Makefile index 70246f56..679eb8d9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -290,7 +290,7 @@ ifeq ($(optimize),yes) CXXFLAGS += -fno-gcse -mthumb -march=armv7-a -mfloat-abi=softfp endif endif - + ifeq ($(comp),$(filter $(comp),gcc clang icc)) ifeq ($(KERNEL),Darwin) CXXFLAGS += -mdynamic-no-pic diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a0ad09f0..6bbd72a7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -448,16 +448,16 @@ namespace { int kingFlankAttacks = popcount(b1) + popcount(b2); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 69 * kingAttacksCount[Them] + 185 * popcount(kingRing[Us] & weak) - - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) - - 873 * !pos.count(Them) - - 6 * mg_value(score) / 8 - + mg_value(mobility[Them] - mobility[Us]) + + 69 * kingAttacksCount[Them] + 3 * kingFlankAttacks * kingFlankAttacks / 8 + + mg_value(mobility[Them] - mobility[Us]) + - 873 * !pos.count(Them) + - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) + - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) + - 6 * mg_value(score) / 8 - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation @@ -596,7 +596,6 @@ namespace { assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); int r = relative_rank(Us, s); - File f = file_of(s); Score bonus = PassedRank[r]; @@ -646,7 +645,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * map_to_queenside(f); + score += bonus - PassedFile * map_to_queenside(file_of(s)); } if (T) @@ -755,7 +754,7 @@ namespace { else sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); - sf = std::max(0, sf - (pos.rule50_count() - 12) / 4 ); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); diff --git a/src/movegen.cpp b/src/movegen.cpp index fc99ec26..ef7821e0 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -60,6 +60,7 @@ namespace { constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); + const Square ksq = pos.square(Them); Bitboard emptySquares; Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; @@ -84,8 +85,6 @@ namespace { if (Type == QUIET_CHECKS) { - Square ksq = pos.square(Them); - b1 &= pos.attacks_from(ksq, Them); b2 &= pos.attacks_from(ksq, Them); @@ -130,8 +129,6 @@ namespace { Bitboard b2 = shift(pawnsOn7) & enemies; Bitboard b3 = shift(pawnsOn7) & emptySquares; - Square ksq = pos.square(Them); - while (b1) moveList = make_promotions(moveList, pop_lsb(&b1), ksq); @@ -187,7 +184,7 @@ namespace { ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, Bitboard target) { - assert(Pt != KING && Pt != PAWN); + static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); const Square* pl = pos.squares(us); @@ -261,7 +258,7 @@ namespace { template ExtMove* generate(const Position& pos, ExtMove* moveList) { - assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS); + static_assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS, "Unsupported type in generate()"); assert(!pos.checkers()); Color us = pos.side_to_move(); diff --git a/src/pawns.cpp b/src/pawns.cpp index 1825b6e2..84f3d977 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -108,7 +108,7 @@ namespace { // 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)) - && (stoppers & (leverPush | blocked)); + && (leverPush | blocked); // Compute additional span if pawn is not backward nor blocked if (!backward && !blocked) diff --git a/src/position.h b/src/position.h index a0a9a306..e6c901ea 100644 --- a/src/position.h +++ b/src/position.h @@ -286,7 +286,8 @@ inline Square Position::castling_rook_square(CastlingRights cr) const { template inline Bitboard Position::attacks_from(Square s) const { - assert(Pt != PAWN); + static_assert(Pt != PAWN, "Pawn attacks need color"); + return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, byTypeBB[ALL_PIECES]) : Pt == QUEEN ? attacks_from(s) | attacks_from(s) : PseudoAttacks[Pt][s]; diff --git a/src/search.cpp b/src/search.cpp index c70fbf60..e0dcc4d1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -75,7 +75,7 @@ namespace { return (r + 520) / 1024 + (!i && r > 999); } - constexpr int futility_move_count(bool improving, int depth) { + constexpr int futility_move_count(bool improving, Depth depth) { return (5 + depth * depth) * (1 + improving) / 2; } @@ -594,7 +594,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR, priorCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -1151,17 +1151,17 @@ moves_loop: // When in check, search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && d != newDepth), doLMR = true; + doFullDepthSearch = (value > alpha && d != newDepth), didLMR = true; } else - doFullDepthSearch = !PvNode || moveCount > 1, doLMR = false; + doFullDepthSearch = !PvNode || moveCount > 1, didLMR = false; // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); - if (doLMR && !captureOrPromotion) + if (didLMR && !captureOrPromotion) { int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); @@ -1466,7 +1466,7 @@ moves_loop: // When in check, search starts from here // Don't search moves with negative SEE values if ( (!inCheck || evasionPrunable) - && (!givesCheck || !(pos.blockers_for_king(~pos.side_to_move()) & from_sq(move))) + && !(givesCheck && pos.is_discovery_check_on_king(~pos.side_to_move(), move)) && !pos.see_ge(move)) continue; diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index c7d20788..a9378b4b 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -706,9 +706,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 = file_of(squares[0]); - if (tbFile > FILE_D) - tbFile = file_of(squares[0] ^ 7); // Horizontal flip: SQ_H1 -> SQ_A1 + tbFile = map_to_queenside(file_of(squares[0])); } // DTZ tables are one-sided, i.e. they store positions only for white to @@ -1062,8 +1060,8 @@ void set(T& e, uint8_t* data) { enum { Split = 1, HasPawns = 2 }; - assert(e.hasPawns == !!(*data & HasPawns)); - assert((e.key != e.key2) == !!(*data & Split)); + assert(e.hasPawns == bool(*data & HasPawns)); + assert((e.key != e.key2) == bool(*data & Split)); data++; // First byte stores flags diff --git a/src/thread.cpp b/src/thread.cpp index 476f1d64..680cd3ad 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -71,13 +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 (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 }) + for (StatsType c : { NoCaptures, Captures }) continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); } diff --git a/src/types.h b/src/types.h index cc4008b3..5197e9fb 100644 --- a/src/types.h +++ b/src/types.h @@ -341,7 +341,7 @@ inline Score operator*(Score s, int i) { return result; } -/// Multiplication of a Score by an boolean +/// Multiplication of a Score by a boolean inline Score operator*(Score s, bool b) { return Score(int(s) * int(b)); } From 648c7ec25db2040c0af34dd846dfa3f57af5ad0a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 23 Oct 2019 08:26:47 +0200 Subject: [PATCH 04/59] Refactor final stats updates. This PR refactors update_quiet_stats, update_capture_stats and search to more clearly reflect what is actually done. Effectively, all stat updates that need to be done after search is finished and a bestmove is found, are collected in a new function ```final_stats_update()```. This shortens our main search routine, and simplifies ```update_quiet_stats```. The latter function is now more easily reusable with fewer arguments, as the handling of ```quietsSearched``` is only needed in ```final_stats_update```. ```update_capture_stats```, which was only called once is now integrated in ```final_stats_update```, which allows for removing a branch and reusing some ```stat_bonus``` calls. The need for refactoring was also suggested by the fact that the comments of ```update_quiet_stats``` and ```update_capture_stats``` were incorrect (e.g. ```update_capture_stats``` was called, correctly, also when the bestmove was a quiet and not a capture). passed non-regression STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 75196 W: 16364 L: 16347 D: 42485 http://tests.stockfishchess.org/tests/view/5db004ec0ebc5902c06db9e1 The diff is most easily readable as ```git diff master --patience``` No functional change --- src/search.cpp | 102 ++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e0dcc4d1..086761a3 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -153,8 +153,9 @@ namespace { Value value_from_tt(Value v, int ply); 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, Move* quiets, int quietCount, int bonus); - void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, 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); // 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. @@ -679,7 +680,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); + 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) @@ -1276,21 +1277,11 @@ moves_loop: // When in check, search starts from here if (!moveCount) bestValue = excludedMove ? alpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW; + else if (bestMove) - { - // Quiet best move: update move sorting heuristics - if (!pos.capture_or_promotion(bestMove)) - update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount, - stat_bonus(depth + (bestValue > beta + PawnValueMg))); + update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, + quietsSearched, quietCount, capturesSearched, captureCount, depth); - update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + 1)); - - // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted - if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) - && !priorCapture) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); - - } // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) && !priorCapture) @@ -1564,6 +1555,51 @@ 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) { + + int bonus1, bonus2; + Color us = pos.side_to_move(); + Thread* thisThread = pos.this_thread(); + CapturePieceToHistory& captureHistory = thisThread->captureHistory; + Piece moved_piece = pos.moved_piece(bestMove); + 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 + + if (!pos.capture_or_promotion(bestMove)) + { + update_quiet_stats(pos, ss, bestMove, bonus2); + + // Decrease all the non-best quiet moves + for (int i = 0; i < quietCount; ++i) + { + thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2; + update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2); + } + } + else + captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1; + + // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted + if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) + && !pos.captured_piece()) + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -bonus1); + + // Decrease all the non-best capture moves + for (int i = 0; i < captureCount; ++i) + { + moved_piece = pos.moved_piece(capturesSearched[i]); + captured = type_of(pos.piece_on(to_sq(capturesSearched[i]))); + captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1; + } + } + + // update_continuation_histories() updates histories of the move pairs formed // by moves at ply -1, -2, and -4 with current move. @@ -1575,32 +1611,9 @@ moves_loop: // When in check, search starts from here } - // update_capture_stats() updates move sorting heuristics when a new capture best move is found + // update_quiet_stats() updates move sorting heuristics - void update_capture_stats(const Position& pos, Move move, - Move* captures, int captureCount, int bonus) { - - CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; - Piece moved_piece = pos.moved_piece(move); - PieceType captured = type_of(pos.piece_on(to_sq(move))); - - if (pos.capture_or_promotion(move)) - captureHistory[moved_piece][to_sq(move)][captured] << bonus; - - // Decrease all the other played capture moves - for (int i = 0; i < captureCount; ++i) - { - moved_piece = pos.moved_piece(captures[i]); - captured = type_of(pos.piece_on(to_sq(captures[i]))); - captureHistory[moved_piece][to_sq(captures[i])][captured] << -bonus; - } - } - - - // update_quiet_stats() updates move sorting heuristics when a new quiet best move is found - - void update_quiet_stats(const Position& pos, Stack* ss, Move move, - Move* quiets, int quietCount, int bonus) { + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) { if (ss->killers[0] != move) { @@ -1621,13 +1634,6 @@ moves_loop: // When in check, search starts from here Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } - - // Decrease all the other played quiet moves - for (int i = 0; i < quietCount; ++i) - { - thisThread->mainHistory[us][from_to(quiets[i])] << -bonus; - update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); - } } // When playing with strength handicap, choose best move among a set of RootMoves From 1725ed39adcc4aa6d96117a7b83e1552b37a6baa Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 29 Oct 2019 10:35:56 +0100 Subject: [PATCH 05/59] Tweak dynamic contempt (the birthday patch) Make dynamic contempt weight factor dependent on static contempt so that higher static contempt implies less dynamic contempt and vice versa. For default contempt 24 this is a non-functional change. But tests with contempt 0 shows an elo gain. Also today is my birthday so i have already give to myself a gift with this patch :-)! Further proceedings: in the past we checked for default contempt that it doesn't regress against contempt 0. Now that the later is stronger and the former is the same strength this should be rechecked. Perhaps the default contempt have to be lowered. It would be interesting to get some idea of the impact of this patch outside of the 0-24 contempt range. STC: (both with contempt=0) LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 21912 W: 3898 L: 3740 D: 14274 http://tests.stockfishchess.org/tests/view/5db74b6f0ebc5902d1f37405 LTC: (both with contempt=0) LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 27172 W: 3350 L: 3126 D: 20696 http://tests.stockfishchess.org/tests/view/5db760020ebc5902d1f375d0 Closes https://github.com/official-stockfish/Stockfish/pull/2382 No functional change (for current default contempt 24). --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 086761a3..b571cdf1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -418,7 +418,7 @@ void Thread::search() { beta = std::min(previousScore + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + 86 * previousScore / (abs(previousScore) + 176); + int dct = ct + (111 - ct / 2) * previousScore / (abs(previousScore) + 176); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); From 6f3796adaf44c48cf1353181d386a61a57859b67 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 31 Oct 2019 17:17:46 +0100 Subject: [PATCH 06/59] Consolidate pawn_push and up This is a non-functional simplification. Pawn_push and Up are redundant. If we make up pawn_push, we can use it for all of the Up's and Down's. In this version, I've also left the Up and Down constants so that there is no worse readability. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23878 W: 5202 L: 5085 D: 13591 http://tests.stockfishchess.org/tests/view/5db5569a0ebc5902d6b14de4 Closes https://github.com/official-stockfish/Stockfish/pull/2378 No functional change --- src/evaluate.cpp | 12 ++++++------ src/movegen.cpp | 2 +- src/pawns.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 6bbd72a7..c1640d94 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -213,8 +213,8 @@ namespace { void Evaluation::initialize() { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); const Square ksq = pos.square(Us); @@ -258,7 +258,7 @@ namespace { Score Evaluation::pieces() { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); const Square* pl = pos.squares(Us); @@ -484,7 +484,7 @@ namespace { Score Evaluation::threats() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; @@ -578,7 +578,7 @@ namespace { Score Evaluation::passed() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); auto king_proximity = [&](Color c, Square s) { return std::min(distance(pos.square(c), s), 5); @@ -669,7 +669,7 @@ namespace { return SCORE_ZERO; constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = -pawn_push(Us); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); diff --git a/src/movegen.cpp b/src/movegen.cpp index ef7821e0..0b91582e 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -56,7 +56,7 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); diff --git a/src/pawns.cpp b/src/pawns.cpp index 84f3d977..3ddf7030 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -69,7 +69,7 @@ namespace { Score evaluate(const Position& pos, Pawns::Entry* e) { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); Bitboard neighbours, stoppers, support, phalanx, opposed; Bitboard lever, leverPush, blocked; From e8fca713424e814756e2db4a7195f69fdb669c2a Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 31 Oct 2019 09:01:33 -0600 Subject: [PATCH 07/59] Simplify kingRing Simplify the king ring initialization and make it more regular, by just moving the king square off the edges and using PseudoAttacks by king from this new square. There is a small functional difference from the previous master, as the old master excludes the original ksq square while this patch always includes the nine squares block (after moving the king from the edges). Additionally, master does not adjust the kingRing down if we are on relative rank 8, while this patch treats all of the edges the same. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 13263 W: 2968 L: 2830 D: 7465 http://tests.stockfishchess.org/tests/view/5db872830ebc5902d1f388aa LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 72996 W: 11819 L: 11780 D: 49397 http://tests.stockfishchess.org/tests/view/5db899c20ebc5902d1f38b5e Closes https://github.com/official-stockfish/Stockfish/pull/2384 Bench: 4959244 --- src/evaluate.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c1640d94..959ccd84 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -235,15 +235,9 @@ namespace { attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); // Init our king safety tables - kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, ksq) == RANK_1) - kingRing[Us] |= shift(kingRing[Us]); - - if (file_of(ksq) == FILE_H) - kingRing[Us] |= shift(kingRing[Us]); - - else if (file_of(ksq) == FILE_A) - kingRing[Us] |= shift(kingRing[Us]); + Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G), + clamp(rank_of(ksq), RANK_2, RANK_7)); + kingRing[Us] = PseudoAttacks[KING][s] | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; From 474d133565564146ec28878afca54739cc4e22d2 Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Fri, 1 Nov 2019 13:58:11 +0800 Subject: [PATCH 08/59] Combo of Parameter Tweaks This patch is a combo of the following tweaks: Complexity parameters Knight PSQT Bishop PSQT King PSQT Piece Values Passed STC: LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 56527 W: 12326 L: 12052 D: 32149 http://tests.stockfishchess.org/tests/view/5dbbca3f0ebc5925b64ee6d6 Passed LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 64010 W: 10549 L: 10199 D: 43262 http://tests.stockfishchess.org/tests/view/5dbc30dc0ebc5925b64eee0c Closes https://github.com/official-stockfish/Stockfish/pull/2390 Bench: 4312945 --- AUTHORS | 2 +- src/evaluate.cpp | 8 ++++---- src/psqt.cpp | 48 ++++++++++++++++++++++++------------------------ src/types.h | 8 ++++---- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8317f545..979410ae 100644 --- a/AUTHORS +++ b/AUTHORS @@ -64,7 +64,7 @@ Jean Gauthier (QuaisBla) Jean-Francois Romang (jromang) Jerry Donald Watson (jerrydonaldwatson) Jonathan Calovski (Mysseno) -Jonathan D. (SFisGOD) +Jonathan Dumale (SFisGOD) Joost VandeVondele (vondele) Jörg Oster (joergoster) Joseph Ellis (jhellis3) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 959ccd84..ea54e271 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -713,10 +713,10 @@ namespace { int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking - + 18 * pawnsOnBothFlanks - + 49 * !pos.non_pawn_material() - - 36 * almostUnwinnable - -103 ; + + 21 * pawnsOnBothFlanks + + 51 * !pos.non_pawn_material() + - 43 * almostUnwinnable + - 95 ; // 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 diff --git a/src/psqt.cpp b/src/psqt.cpp index 655eb993..60d17ad2 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -39,24 +39,24 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { }, { }, { // Knight - { S(-169,-105), S(-96,-74), S(-80,-46), S(-79,-18) }, - { S( -79, -70), S(-39,-56), S(-24,-15), S( -9, 6) }, - { S( -64, -38), S(-20,-33), S( 4, -5), S( 19, 27) }, - { S( -28, -36), S( 5, 0), S( 41, 13), S( 47, 34) }, - { S( -29, -41), S( 13,-20), S( 42, 4), S( 52, 35) }, - { S( -11, -51), S( 28,-38), S( 63,-17), S( 55, 19) }, - { S( -67, -64), S(-21,-45), S( 6,-37), S( 37, 16) }, - { S(-200, -98), S(-80,-89), S(-53,-53), S(-32,-16) } + { S(-175, -96), S(-92,-65), S(-74,-49), S(-73,-21) }, + { S( -77, -67), S(-41,-54), S(-27,-18), S(-15, 8) }, + { S( -61, -40), S(-17,-27), S( 6, -8), S( 12, 29) }, + { S( -35, -35), S( 8, -2), S( 40, 13), S( 49, 28) }, + { S( -34, -45), S( 13,-16), S( 44, 9), S( 51, 39) }, + { S( -9, -51), S( 22,-44), S( 58,-16), S( 53, 17) }, + { S( -67, -69), S(-27,-50), S( 4,-51), S( 37, 12) }, + { S(-201,-100), S(-83,-88), S(-56,-56), S(-26,-17) } }, { // Bishop - { S(-44,-63), S( -4,-30), S(-11,-35), S(-28, -8) }, - { S(-18,-38), S( 7,-13), S( 14,-14), S( 3, 0) }, - { S( -8,-18), S( 24, 0), S( -3, -7), S( 15, 13) }, - { S( 1,-26), S( 8, -3), S( 26, 1), S( 37, 16) }, - { S( -7,-24), S( 30, -6), S( 23,-10), S( 28, 17) }, - { S(-17,-26), S( 4, 2), S( -1, 1), S( 8, 16) }, - { S(-21,-34), S(-19,-18), S( 10, -7), S( -6, 9) }, - { S(-48,-51), S( -3,-40), S(-12,-39), S(-25,-20) } + { S(-53,-57), S( -5,-30), S( -8,-37), S(-23,-12) }, + { S(-15,-37), S( 8,-13), S( 19,-17), S( 4, 1) }, + { S( -7,-16), S( 21, -1), S( -5, -2), S( 17, 10) }, + { S( -5,-20), S( 11, -6), S( 25, 0), S( 39, 17) }, + { S(-12,-17), S( 29, -1), S( 22,-14), S( 31, 15) }, + { S(-16,-30), S( 6, 6), S( 1, 4), S( 11, 6) }, + { S(-17,-31), S(-14,-20), S( 5, -1), S( 0, 1) }, + { S(-48,-46), S( 1,-42), S(-14,-37), S(-23,-24) } }, { // Rook { S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) }, @@ -79,14 +79,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } }, { // King - { S(272, 0), S(325, 41), S(273, 80), S(190, 93) }, - { S(277, 57), S(305, 98), S(241,138), S(183,131) }, - { S(198, 86), S(253,138), S(168,165), S(120,173) }, - { S(169,103), S(191,152), S(136,168), S(108,169) }, - { S(145, 98), S(176,166), S(112,197), S( 69,194) }, - { S(122, 87), S(159,164), S( 85,174), S( 36,189) }, - { S( 87, 40), S(120, 99), S( 64,128), S( 25,141) }, - { S( 64, 5), S( 87, 60), S( 49, 75), S( 0, 75) } + { S(271, 1), S(327, 45), S(270, 85), S(192, 76) }, + { S(278, 53), S(303,100), S(230,133), S(174,135) }, + { S(195, 88), S(258,130), S(169,169), S(120,175) }, + { S(164,103), S(190,156), S(138,172), S( 98,172) }, + { S(154, 96), S(179,166), S(105,199), S( 70,199) }, + { S(123, 92), S(145,172), S( 81,184), S( 31,191) }, + { S( 88, 47), S(120,121), S( 65,116), S( 33,131) }, + { S( 59, 11), S( 89, 59), S( 45, 73), S( -1, 78) } } }; diff --git a/src/types.h b/src/types.h index 5197e9fb..13c3bbf2 100644 --- a/src/types.h +++ b/src/types.h @@ -180,10 +180,10 @@ enum Value : int { VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, - KnightValueMg = 782, KnightValueEg = 865, - BishopValueMg = 830, BishopValueEg = 918, - RookValueMg = 1289, RookValueEg = 1378, - QueenValueMg = 2529, QueenValueEg = 2687, + KnightValueMg = 781, KnightValueEg = 854, + BishopValueMg = 825, BishopValueEg = 915, + RookValueMg = 1276, RookValueEg = 1380, + QueenValueMg = 2538, QueenValueEg = 2682, MidgameLimit = 15258, EndgameLimit = 3915 }; From cff9a8672c1da7d36bc54d168d10ea2b1ce5c728 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Fri, 1 Nov 2019 00:27:19 -0400 Subject: [PATCH 09/59] Make Square and Bitboard operators commutative As Stockfish developers, we aim to make our code as legible and as close to simple English as possible. However, one of the more notable exceptions to this rule concerns operations between Squares and Bitboards. Prior to this pull request, AND, OR, and XOR were only defined when the Bitboard was the first operand, and the Square the second. For example, for a Bitboard b and Square s, "b & s" would be valid but "s & b" would not. This conflicts with natural reasoning about logical operators, both mathematically and intuitively, which says that logical operators should commute. More dangerously, however, both Square and Bitboard are defined as integers "under the hood." As a result, code like "s & b" would still compile and give reasonable bench values. This trap occasionally ensnares even experienced Stockfish developers, but it is especially dangerous for new developers not aware of this peculiarity. Because there is no compilation or runtime error, and a reasonable bench, only a close review by approvers can spot this error when a test has been submitted--and many times, these bugs have slipped past review. This is by far the most common logical error on Fishtest, and has wasted uncountable STC games over the years. However, it can be fixed by adding three non-functional lines of code. In this patch, we define the operators when the operands are provided in the opposite order, i.e., we make AND, OR, and XOR commutative for Bitboards and Squares. Because these are inline methods and implemented identically, the executable does not change at all. This patch has the small side-effect of requiring Squares to be explicitly cast to integers before AND, OR, or XOR with integers. This is only performed twice in Stockfish's source code, and again does not change the executable at all (since Square is an enum defined as an integer anyway). For demonstration purposes, this pull request also inverts the order of one AND and one OR, to show that neither the bench nor the executable change. (This change can be removed before merging, if preferred.) I hope that this pull request significantly lowers the barrier-of-entry for new developer to join the Stockfish project. I also hope that this change will improve our efficiency in using our generous CPU donors' machines, since it will remove one of the most common causes of buggy tests. Following helpful review and comments by Michael Stembera (@mstembera), we add a further clean-up by implementing OR for two Squares, to anticipate additional traps developers may encounter and handle them cleanly. Closes https://github.com/official-stockfish/Stockfish/pull/2387 No functional change. --- src/bitbase.cpp | 2 +- src/bitboard.h | 6 ++++++ src/endgame.cpp | 2 +- src/evaluate.cpp | 4 ++-- src/position.h | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 2b1a5517..9301dcfa 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -44,7 +44,7 @@ namespace { // 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 wksq | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); + return int(wksq) | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); } enum Result { diff --git a/src/bitboard.h b/src/bitboard.h index 477b1655..8d748eee 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -119,6 +119,12 @@ inline Bitboard operator^( Bitboard b, Square s) { return b ^ square_bb(s); } inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= square_bb(s); } inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= square_bb(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, Bitboard b) { return b ^ s; } + +inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | square_bb(s2); } + constexpr bool more_than_one(Bitboard b) { return b & (b - 1); } diff --git a/src/endgame.cpp b/src/endgame.cpp index e10f8d5d..ca38a662 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -74,7 +74,7 @@ namespace { assert(pos.count(strongSide) == 1); if (file_of(pos.square(strongSide)) >= FILE_E) - sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1 + sq = Square(int(sq) ^ 7); // Mirror SQ_H1 -> SQ_A1 return strongSide == WHITE ? sq : ~sq; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ea54e271..cefd9db4 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -237,7 +237,7 @@ namespace { // 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)); - kingRing[Us] = PseudoAttacks[KING][s] | s; + kingRing[Us] = s | PseudoAttacks[KING][s]; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -291,7 +291,7 @@ 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) + if (s & bb) score += Outpost * (Pt == KNIGHT ? 2 : 1); else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) diff --git a/src/position.h b/src/position.h index e6c901ea..2ec2729c 100644 --- a/src/position.h +++ b/src/position.h @@ -430,7 +430,7 @@ inline void Position::move_piece(Piece pc, 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. - Bitboard fromTo = square_bb(from) | square_bb(to); + Bitboard fromTo = from | to; byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo; From ef38046e734490499e4b6254dbf4fc434bf37fc9 Mon Sep 17 00:00:00 2001 From: MichaelB7 Date: Sat, 2 Nov 2019 20:04:05 -0400 Subject: [PATCH 10/59] Remove shuffle extension It was noted in an earlier patch that all of the positions below needed the Shuffle Detection idea to be solved: 3r4/p3r1pk/PpBb1pRp/1KpPpP1P/2P1P1R1/8/8/8 b - - 32 86 8/8/8/1k6/2p5/p1K5/N2B2r1/8 b - - 59 109 1r4k1/1r1bq3/4p1p1/3pPpPp/pNpN1P1P/P1PnQ3/1PK5/1R3R2 b - - 13 82 5k2/3b4/5p2/p1p1pPp1/PpPpP1Pp/1P1P3P/8/3R1K2 w - - 20 1 But Stockfish has envolved a bit since the Shuffle Detection patch introduction, and this patch proves Stockfish is able to solves these drawn positions without it, even on single core without EGTB. Passed STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 14231 W: 3114 L: 2978 D: 8139 http://tests.stockfishchess.org/tests/view/5dbe1a610ebc5925b64f09d9 Passed LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 42781 W: 6917 L: 6831 D: 29033 http://tests.stockfishchess.org/tests/view/5dbe24c20ebc5925b64f0a7a Passed VLTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 32556 W: 4573 L: 4469 D: 23514 http://tests.stockfishchess.org/tests/view/5dbec3830ebc5925b64f11aa Closes https://github.com/official-stockfish/Stockfish/pull/2394 Bench: 4362323 ---------------------------- Example of search by Michael Byrne for the FEN position: q1B5/1P1q4/8/8/8/6R1/8/1K1k4 w - - 0 1 This position is win for white and the only moves that wins is Rg1 - all other moves either draw or lose. With single core and 1024M hash, it is solved without shuffle detection in 38 seconds on my machine (with no EGTB). This was the position that was locked in a loop in the initial shuffle detection patch! ``` dep score nodes time (not shown: tbhits knps seldep) 50 +1.71 298.9M 2:43.63 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Qe5+ Kb1 Qe4+ Ka2 Qd5+ Rb3 Qd2+ Ka3 Qc1+ Kb4 Qc7 Ka4 Qb8 Rb6 Ke5 Kb3 Qg8+ Kb4 Qf8+ Ka5 Qb8 Bb3 Kd4 Kb4 Qf8+ Ka4 Qb8 Ka5 K 49 +1.68 288.5M 2:38.35 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Qe5+ Kb1 Qe4+ Ka2 Qd5+ Rb3 Qd2+ Ka3 Qc1+ Kb4 Qc7 Ka4 Qb8 Rb6 Ke5 Kb3 Qg8+ Kb4 Qf8+ Ka5 Qb8 Bb3 Kd4 Kb4 Ke3 Be6 Ke4 Bc4 Ke 48 +1.78 228.5M 2:01.93 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Qe5+ Kb1 Qe4+ Ka2 Qd5+ Rb3 Qd2+ Ka3 Qa5+ Kb2 Qe5+ Ka2 Qb8 Rb5 Ke3 Kb1 Ke4 Bb3 Kf4 Be6 Ke3 Rb4 Kd3 Kb2 Ke3 Bd5 Qe5+ Kc2 Qh 46 +1.49 198.4M 1:44.89 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Qe5+ Kb1 Qe4+ Ka2 Qd5+ Rb3 Qd2+ Ka3 Qc1+ Kb4 Qc7 Ka4 Qb8 Rb6 Qe8+ Rb5 Qb8 Bc2 Qa7+ Kb3 Qe3+ Kc4 Qe6+ Kb4 Qd6+ Kb3 Qb8 Rb4 45 +1.45 154.5M 1:20.75 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke3 Bg2 Kd4 Rb5 Kc4 Bf1+ Kd4 Kb2 Qh2+ Kb3 Qg3+ Ka4 Qb8 Be2 Ke3 Bc4 Kf4 Kb4 Qd6+ Kc3 Qb8 Kc2 Ke4 Be6 Qh2+ Kb3 Qg3+ Ka4 Qb8 Bb3 Kd4 Bd5 Ke3 44 +1.36 141.9M 1:14.40 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Qd6 Rc2+ Kd3 Be2+ Ke3 Rb2 Qb8 Bd1 Ke4 Rb5 Kd4 Bf3 Kc4 Be2+ Kc3 Rb6 Kd2 Bc4 Kc3 Bd5 Kd4 Bg2 Ke5 Kb2 Kd4 Rb5 Kc4 Bf1+ Kd4 Be2 Ke4 Bc4 Qh2+ Kb3 Qg3+ Ka4 Qb8 Bd5+ Kd4 Be6 Ke4 43 +1.36 134.1M 1:10.46 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Qd6 Rc2+ Kd3 Be2+ Ke3 Rb2 Qb8 Bd1 Ke4 Rb5 Kd4 Bf3 Kc4 Be2+ Kc3 Rb6 Kd2 Bc4 Kc3 Be6 Kd4 Rb5 Kc3 Bf7 Kd4 Kb2 Ke4 Kb3 Kf4 Kc3 Ke4 Kb2 Qh2+ Kb3 Qg3+ Ka4 Qb8 Rb4+ Ke5 Rb6 Kf4 42 +1.36 118.7M 1:01.60 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Qd6 Rc2+ Kd3 Be2+ Ke3 Rb2 Qb8 Bd1 Ke4 Rb5 Kd4 Bf3 Kc4 Be2+ Kc3 Rb6 Kd2 Bc4 Kc3 Be6 Kd4 Rb5 Kc3 Bf7 Kd4 Kb2 Ke4 Bc4 Qh2+ Kb3 Qg3+ Ka4 Qb8 Bd5+ Kd4 Bb3 Qa7+ Kb4 Qb8 Bc4 Ke4 41 +1.38 110.3M 0:56.80 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Qd6 Rc2+ Kd3 Be2+ Ke3 Rb2 Qb8 Bd1 Ke4 Rb5 Kd4 Bf3 Kc4 Be2+ Kc3 Rb6 Kd2 Bc4 Kc3 Be6 Kd4 Rb5 Kc3 Bd5 Kd4 Ba2 Ke4 Be6 Kd4 Kb2 Qh2+ Kb3 Qb8 Bc4 Ke3 Kc3 Qh8+ Kb4 Qb2+ Ka4 Qa1+ 39 +1.25 87.3M 0:44.48 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Kg5 Kb1 Kf5 Bb3 Ke5 Kb2 Kd4 Rb5 Qh2+ Bc2 Qb8 Bd1 Kc4 Be2+ Kd4 Kc2 Ke3 Bd1 Kd4 Kb3 Qg3+ Ka4 Qb8 Bb3 Kc3 Rb6 Kd4 Kb5 Ke5 K 38 +1.25 82.0M 0:41.90 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kd4 Rb5 Kc4 Be2+ Kc3 Rb6 Kd4 Bf3 Ke5 Kb2 Kf4 Bd1 Kg5 Kb1 Kf5 Bb3 Ke5 Kb2 Kd4 Rb5 Qh2+ Bc2 Qb8 Kb3 Qg3+ Ka4 Qb8 Bb3 Kc3 Rb6 Kd4 Kb5 Ke5 Kb4 Kd4 Be6 Kd3 Bd5 Kd4 Bf3 Ke5 Be 37 +0.13 79.3M 0:40.44 Rg1+ Kd2 Rg2+ Kc3 Rc2+ Kb3 Rb2+ Kc3 Bxd7 Qf8 Ba4 Qb8 Bd1 Kc4 Bf3 Kd4 Rb5 Kc4 Rb6 Kd4 Rb2 Ke5 Rb3 Kd6 Rb5 Ke6 Rb4 Kd6 Kc2 Kc5 Kb3 Kd6 Be4 Ke7 Kc3 Qc7+ Kd3 Qg3+ Kc2 Qf2+ Kb3 Qe3+ Ka2 Qa7+ Kb2 Qb8 Kb3 Kd6 Bf3 Qg8+ Ka3 Kc7 b8=R Qx 37 +0.67! 78.3M 0:39.90 Rg1+! 37 +0.47! 77.0M 0:39.18 Rg1+! 37 +0.32! 76.8M 0:39.11 Rg1+! 37 +0.23! 76.8M 0:39.07 Rg1+! 36 +0.57! 76.1M 0:38.72 Rg1+! 36 +0.37! 75.8M 0:38.59 Rg1+! 36 +0.23! 75.7M 0:38.51 Rg1+! 36 +0.13! 75.6M 0:38.49 Rg1+! 35 +0.03? 58.0M 0:29.84 bxa8=Q Qb5+? ``` --- src/search.cpp | 7 ------- src/thread.cpp | 2 +- src/thread.h | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b571cdf1..4b90ab1c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -999,13 +999,6 @@ moves_loop: // When in check, search starts from here && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))) extension = 1; - // Shuffle extension - else if ( PvNode - && pos.rule50_count() > 18 - && depth < 3 - && ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions - extension = 1; - // Passed pawn extension else if ( move == ss->killers[0] && pos.advanced_pawn_push(move) diff --git a/src/thread.cpp b/src/thread.cpp index 680cd3ad..6eb00d63 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -207,7 +207,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, for (Thread* th : *this) { - th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0; + th->nodes = th->tbHits = th->nmpMinPly = 0; th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); diff --git a/src/thread.h b/src/thread.h index 0517afc5..087ed382 100644 --- a/src/thread.h +++ b/src/thread.h @@ -60,7 +60,7 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; - size_t pvIdx, pvLast, shuffleExts; + size_t pvIdx, pvLast; int selDepth, nmpMinPly; Color nmpColor; std::atomic nodes, tbHits, bestMoveChanges; From 3804effb341b3008326a1613923177eb83d02826 Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Tue, 5 Nov 2019 03:06:41 +0800 Subject: [PATCH 11/59] Rook PSQT Tuned This patch uses about half the changes of the SPSA tuning run: http://tests.stockfishchess.org/tests/view/5dba93d30ebc5925b64ed3bf About a month ago, xoto10's patch raised the mg value of the third rank center files from -1 to 7 to encourage rook lifts to the third rank. About three days later, Rocky's patch lowered this value from 7 to 3. This patch raises that again from 3 to 12 and ends up greater than the original rook lift patch. Passed STC: LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 104094 W: 22573 L: 22161 D: 59360 http://tests.stockfishchess.org/tests/view/5dbc77f20ebc5925b64ef1d0 Passed LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 168291 W: 27410 L: 26777 D: 114104 http://tests.stockfishchess.org/tests/view/5dbd9f1e0ebc5925b64f0647 Bench: 4707799 --- src/psqt.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/psqt.cpp b/src/psqt.cpp index 60d17ad2..6469c43a 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -59,14 +59,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-48,-46), S( 1,-42), S(-14,-37), S(-23,-24) } }, { // Rook - { S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) }, - { S(-21,-12), S(-13, -9), S( -8, -1), S( 6, -2) }, - { S(-25, 6), S(-11, -8), S( -1, -2), S( 3, -6) }, - { S(-13, -6), S( -5, 1), S( -4, -9), S(-6, 7) }, - { S(-27, -5), S(-15, 8), S( -4, 7), S( 3, -6) }, - { S(-22, 6), S( -2, 1), S( 6, -7), S(12, 10) }, - { S( -2, 4), S( 12, 5), S( 16, 20), S(18, -5) }, - { S(-17, 18), S(-19, 0), S( -1, 19), S( 9, 13) } + { S(-26, -7), S(-19,-15), S( -8,-10), S(-1,-10) }, + { S(-21,-19), S(-24, -7), S( -6, 0), S( 5, -1) }, + { S(-29, -1), S(-20, -4), S( 6, 8), S(12,-19) }, + { S(-14, -1), S( -1, -3), S(-12, -8), S(-7, 10) }, + { S(-37, 1), S( -6, 13), S( 0, 14), S(10, 4) }, + { S(-16, 9), S( -1, 15), S( 4, -8), S( 1, 16) }, + { S( -1, 2), S( 10, 4), S( 13, 23), S(23, -4) }, + { S( -2, 21), S(-21, -3), S( 4, 26), S(-1, 20) } }, { // Queen { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, From 9f312c80d918c6f669dcf83df3d4332e02bfa1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 6 Nov 2019 11:06:53 +0100 Subject: [PATCH 12/59] Revert "Rook PSQT Tuned" This reverts the previous commit. The PSQT changes in this previous commit originated from tests against quite an old version of master which did not include the other PSQT changes of 474d133 for the other pieces, and there might be some unknown interactions between the PSQT tables. So we made a non-regression test of the last commit against the last-but-one commit. This test failed, leading to the revert decision. Failed non-regression test: LLR: -2.96 (-2.94,2.94) [-3.00,1.00] Total: 95536 W: 15047 L: 15347 D: 65142 http://tests.stockfishchess.org/tests/view/5dc0ba1d0ebc5904493b0112 Closes https://github.com/official-stockfish/Stockfish/pull/2395 Bench: 4362323 --- src/psqt.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/psqt.cpp b/src/psqt.cpp index 6469c43a..60d17ad2 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -59,14 +59,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-48,-46), S( 1,-42), S(-14,-37), S(-23,-24) } }, { // Rook - { S(-26, -7), S(-19,-15), S( -8,-10), S(-1,-10) }, - { S(-21,-19), S(-24, -7), S( -6, 0), S( 5, -1) }, - { S(-29, -1), S(-20, -4), S( 6, 8), S(12,-19) }, - { S(-14, -1), S( -1, -3), S(-12, -8), S(-7, 10) }, - { S(-37, 1), S( -6, 13), S( 0, 14), S(10, 4) }, - { S(-16, 9), S( -1, 15), S( 4, -8), S( 1, 16) }, - { S( -1, 2), S( 10, 4), S( 13, 23), S(23, -4) }, - { S( -2, 21), S(-21, -3), S( 4, 26), S(-1, 20) } + { S(-31, -9), S(-20,-13), S(-14,-10), S(-5, -9) }, + { S(-21,-12), S(-13, -9), S( -8, -1), S( 6, -2) }, + { S(-25, 6), S(-11, -8), S( -1, -2), S( 3, -6) }, + { S(-13, -6), S( -5, 1), S( -4, -9), S(-6, 7) }, + { S(-27, -5), S(-15, 8), S( -4, 7), S( 3, -6) }, + { S(-22, 6), S( -2, 1), S( 6, -7), S(12, 10) }, + { S( -2, 4), S( 12, 5), S( 16, 20), S(18, -5) }, + { S(-17, 18), S(-19, 0), S( -1, 19), S( 9, 13) } }, { // Queen { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, From 5ae195ee7e3ccac01b8145f9b7022e352a288f07 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 26 Oct 2019 16:34:19 +0200 Subject: [PATCH 13/59] Fix incorrect mate score. Current master 648c7ec25db2040c0af34dd846dfa3f57af5ad0a will generate an incorrect mate score for: ``` setoption name Hash value 8 setoption name Threads value 1 position fen 8/1p2KP2/1p4q1/1Pp5/2P5/N1Pp1k2/3P4/1N6 b - - 76 40 go depth 49 ``` even though the position is a draw. Generally, SF tries to display only proven mate scores, so this is a bug. This was posted http://www.talkchess.com/forum3/viewtopic.php?f=2&t=72166 by Uri Blass, with the correct analysis that this must be related to the 50 moves draw rule being ignored somewhere. Indeed, this is possible as positions and there eval are stored in the TT, without reference to the 50mr counter. Depending on the search path followed a position can thus be mate or draw in the TT (GHI or Graph history interaction). Therefore, to prove mate lines, the TT content has to be used with care. Rather than ignoring TT content in general or for mate scores (which impact search or mate finding), it is possible to be more selective. In particular, @WOnder93 suggested to only ignore the TT if the 50mr draw ply is closer than the mate ply. This patch implements this idea, by clamping the eval in the TT to +-VALUE_MATED_IN_MAX_PLY. This retains the TTmove, but causes a research of these lines (with the current 50mr counter) as needed. This patch hardly ever affects search (as indicated by the unchanged bench), but fixes the testcase. As the conditions are very specific, also mate finding will almost never be less efficient (testing welcome). It was also shown to pass STC and LTC non-regression testing, in a form using if/then/else instead of ternary operators: STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 93605 W: 15346 L: 15340 D: 62919 http://tests.stockfishchess.org/tests/view/5db45bb00ebc5908127538d4 LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 33873 W: 7359 L: 7261 D: 19253 http://tests.stockfishchess.org/tests/view/5db4c8940ebc5902d6b146fc closes https://github.com/official-stockfish/Stockfish/issues/2370 Bench: 4362323 --- src/search.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4b90ab1c..be296443 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -150,7 +150,7 @@ namespace { Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = 0); Value value_to_tt(Value v, int ply); - Value value_from_tt(Value v, int ply); + 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); @@ -661,7 +661,7 @@ namespace { excludedMove = ss->excludedMove; posKey = pos.key() ^ Key(excludedMove << 16); // Isn't a very good hash tte = TT.probe(posKey, ttHit); - ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; + ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); @@ -899,7 +899,7 @@ namespace { search(pos, ss, alpha, beta, depth - 7, cutNode); tte = TT.probe(posKey, ttHit); - ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; + ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; } @@ -1344,7 +1344,7 @@ moves_loop: // When in check, search starts from here // Transposition table lookup posKey = pos.key(); tte = TT.probe(posKey, ttHit); - ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; + ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; pvHit = ttHit && tte->is_pv(); @@ -1530,11 +1530,11 @@ moves_loop: // When in check, search starts from here // 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". - Value value_from_tt(Value v, int ply) { + Value value_from_tt(Value v, int ply, int r50c) { return v == VALUE_NONE ? VALUE_NONE - : v >= VALUE_MATE_IN_MAX_PLY ? v - ply - : v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v; + : 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; } From 9b8b259388f15d9f669cfc526a2bb7c5a5b1ee71 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sun, 27 Oct 2019 16:16:26 -0400 Subject: [PATCH 14/59] Sequencing tweak in tbprobe() Followup of "issue" #2372, which was in fact a small speed-up proposal by user @d3vv for the probing code of tablebases. See comments on this issue where it was proven by Alin Savard that the proposed change is more efficient on average than master on all type of sequences it will usually be called. Note that on gcc 4.3, this will produce a bogus warning which was solved with ulterior gcc versions: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949 Closes https://github.com/official-stockfish/Stockfish/issues/2372 Closes https://github.com/official-stockfish/Stockfish/pull/2379 Non functional change --- src/syzygy/tbprobe.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index a9378b4b..c0453492 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -730,8 +730,8 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // Then we reorder the pieces to have the same sequence as the one stored // in pieces[i]: the sequence that ensures the best compression. - for (int i = leadPawnsCnt; i < size; ++i) - for (int j = i; j < size; ++j) + for (int i = leadPawnsCnt; i < size - 1; ++i) + for (int j = i + 1; j < size; ++j) if (d->pieces[i] == pieces[j]) { std::swap(pieces[i], pieces[j]); From 44b6697f19ed45a6fb3f542acc83fc5d7111f375 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 9 Nov 2019 06:56:18 +0100 Subject: [PATCH 15/59] Remove explicit moveCount pruning The removed lines approximately duplicate equivalent logic in the movePicker. Adjust the futility_move_count to componsate for some difference (the movePicker prunes one iteration of the move loop later). Passed STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 8114 W: 1810 L: 1663 D: 4641 http://tests.stockfishchess.org/tests/view/5dc6afe60ebc5902562bd318 Passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 89956 W: 14473 L: 14460 D: 61023 http://tests.stockfishchess.org/tests/view/5dc6bdcf0ebc5902562bd3c0 Closes https://github.com/official-stockfish/Stockfish/pull/2407 Bench: 4256440 --------------------- How to continue from there? It would be interesting to see if we can extract some Elo gain from the new futility_move_count formula, for instance by somehow incorporating the final -1 in the 5 constant, or adding a linear term to the quadratics... ``` futility_move_count = (5 + depth * depth) * (1 + improving) / 2 - 1 ``` --- src/search.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index be296443..f9579ae0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -76,7 +76,7 @@ namespace { } constexpr int futility_move_count(bool improving, Depth depth) { - return (5 + depth * depth) * (1 + improving) / 2; + return (5 + depth * depth) * (1 + improving) / 2 - 1; } // History and stats update bonus, based on depth @@ -1024,10 +1024,6 @@ moves_loop: // When in check, search starts from here && !givesCheck && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) { - // Move count based pruning - if (moveCountPruning) - continue; - // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); From 9ab2590963b029092a378c7a69d1c80c43999db8 Mon Sep 17 00:00:00 2001 From: Miguel Lahoz Date: Sun, 10 Nov 2019 17:49:06 +0800 Subject: [PATCH 16/59] Shallow depth pruning on NonPV advanced pawn push Usually advanced pawn pushes are not considered in shallow depth pruning because it is risky to do so with possible promotions near the horizon. However, this heuristic is not also beneficial on NonPV nodes since we can afford to take slightly more risk on less important nodes. STC: LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 54530 W: 11955 L: 11686 D: 30889 http://tests.stockfishchess.org/tests/view/5dc7dda30ebc5902ea57efd0 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 77336 W: 12786 L: 12399 D: 52151 http://tests.stockfishchess.org/tests/view/5dc8050d0ebc5902ea57f491 Closes https://github.com/official-stockfish/Stockfish/pull/2408 Bench: 4422068 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f9579ae0..b484dcbe 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1022,7 +1022,7 @@ moves_loop: // When in check, search starts from here if ( !captureOrPromotion && !givesCheck - && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) + && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) { // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); From a1319751700272055e0cf5649292ea4bbaabd6ca Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Tue, 12 Nov 2019 09:22:09 +0800 Subject: [PATCH 17/59] Rank-based outposts Introduce OutpostRank[RANK_NB] which contains a bonus according to the rank of the outpost. We use it for the primary Outpost bonus. The values are based on the trends of the SPSA tuning run with some manual tweaks. Passed STC: LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 27454 W: 6059 L: 5869 D: 15526 http://tests.stockfishchess.org/tests/view/5dcadba20ebc590256922f09 Passed LTC: LLR: 2.94 (-2.94,2.94) [0.00,3.50] Total: 57950 W: 9443 L: 9112 D: 39395 http://tests.stockfishchess.org/tests/view/5dcaea880ebc5902569230bc Bench: 4778405 ---------------------------- The inspiration for this patch came from Stefan Geschwentner's attempt of modifying BishopPawns into a rank-based penalty. Michael Stembera suggested that maybe the S(0, 0) ranks (3rd, 7th and also maybe 8th) can still be tuned. This would expand our definition of Outpost and OutpostRanks would be removed altogether. Special thanks to Mark Tenzer for all the help and excellent suggestions. --- src/evaluate.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cefd9db4..07bacf8d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -125,6 +125,11 @@ namespace { constexpr Score PassedRank[RANK_NB] = { S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; + + // OutpostRank[Rank] contains a bonus according to the rank of the outpost + constexpr Score OutpostRank[RANK_NB] = { + S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19) + }; // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); @@ -292,7 +297,7 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (s & bb) - score += Outpost * (Pt == KNIGHT ? 2 : 1); + score += OutpostRank[relative_rank(Us, s)] * (Pt == KNIGHT ? 2 : 1); else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) score += Outpost; From a00a336946fa9e6dcfa39f8b656413d2de032a89 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 12 Nov 2019 18:36:12 +0100 Subject: [PATCH 18/59] Prune before extension Switch execution order in search: do move pruning before extension detection. STC: LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 5762 W: 1307 L: 1181 D: 3274 http://tests.stockfishchess.org/tests/view/5dcc56e90ebc59025bcbb833 LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 72956 W: 11959 L: 11585 D: 49412 http://tests.stockfishchess.org/tests/view/5dcc62840ebc59025bcbb96f Closes https://github.com/official-stockfish/Stockfish/pull/2413 Bench: 4532366 --- src/evaluate.cpp | 2 +- src/search.cpp | 80 +++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 07bacf8d..dbd2d6d8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -125,7 +125,7 @@ namespace { constexpr Score PassedRank[RANK_NB] = { S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; - + // OutpostRank[Rank] contains a bonus according to the rank of the outpost constexpr Score OutpostRank[RANK_NB] = { S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19) diff --git a/src/search.cpp b/src/search.cpp index b484dcbe..e75db243 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -955,7 +955,45 @@ moves_loop: // When in check, search starts from here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - // Step 13. Extensions (~70 Elo) + // Calculate new depth for this move + newDepth = depth - 1; + + // Step 13. Pruning at shallow depth (~170 Elo) + if ( !rootNode + && pos.non_pawn_material(us) + && bestValue > VALUE_MATED_IN_MAX_PLY) + { + // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold + moveCountPruning = moveCount >= futility_move_count(improving, depth); + + if ( !captureOrPromotion + && !givesCheck + && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) + { + // 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 + && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) + continue; + + // Futility pruning: parent node (~2 Elo) + if ( lmrDepth < 6 + && !inCheck + && ss->staticEval + 250 + 211 * lmrDepth <= alpha) + continue; + + // Prune moves with negative SEE (~10 Elo) + if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + continue; + } + else if (!pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) + continue; + } + + // Step 14. Extensions (~70 Elo) // Singular extension search (~60 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), @@ -1009,44 +1047,8 @@ moves_loop: // When in check, search starts from here if (type_of(move) == CASTLING) extension = 1; - // Calculate new depth for this move - newDepth = depth - 1 + extension; - - // Step 14. Pruning at shallow depth (~170 Elo) - if ( !rootNode - && pos.non_pawn_material(us) - && bestValue > VALUE_MATED_IN_MAX_PLY) - { - // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth); - - if ( !captureOrPromotion - && !givesCheck - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) - { - // 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 - && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) - continue; - - // Futility pruning: parent node (~2 Elo) - if ( lmrDepth < 6 - && !inCheck - && ss->staticEval + 250 + 211 * lmrDepth <= alpha) - continue; - - // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) - continue; - } - else if ( !(givesCheck && extension) - && !pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) - continue; - } + // Add extension to new depth + newDepth += extension; // Speculative prefetch as early as possible prefetch(TT.first_entry(pos.key_after(move))); From 3468138210cacdf46051e9d5bde6e28effee2cdc Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 16 Nov 2019 14:53:11 +0300 Subject: [PATCH 19/59] Introduce king flank defenders This patch implements what we have been trying for quite some time - dependance of kingdanger on balance of attackers and defenders of king flank, to avoid overestimate attacking power if the opponent has enough defenders of king position. We already have some form of it in bishop and knight defenders - this is further work in this direction. What to do based on this? 1) constant 4 is arbitrary, maybe it is not optimal 2) maybe we can use quadratic formula as in kingflankattack 3) simplification into alrealy existing terms is always a possibility :) 4) overall kingdanger tuning always can be done. passed STC: http://tests.stockfishchess.org/tests/view/5dcf40560ebc590256325f30 LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 26298 W: 5819 L: 5632 D: 14847 passed LTC: http://tests.stockfishchess.org/tests/view/5dcfa5760ebc590256326464 LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 30600 W: 5042 L: 4784 D: 20774 Closes https://github.com/official-stockfish/Stockfish/pull/2415 Bench: 4496847 --- src/evaluate.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index dbd2d6d8..2b7ab396 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -380,7 +380,7 @@ namespace { constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); - Bitboard weak, b1, b2, safe, unsafeChecks = 0; + Bitboard weak, b1, b2, b3, safe, unsafeChecks = 0; Bitboard rookChecks, queenChecks, bishopChecks, knightChecks; int kingDanger = 0; const Square ksq = pos.square(Us); @@ -439,19 +439,22 @@ namespace { else unsafeChecks |= knightChecks; - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. + // Find the squares that opponent attacks in our king flank, the squares + // which they attack twice in that flank, and the squares that we defend. b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; b2 = b1 & attackedBy2[Them]; + b3 = attackedBy[Us][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; - int kingFlankAttacks = popcount(b1) + popcount(b2); + int kingFlankAttack = popcount(b1) + popcount(b2); + int kingFlankDefense = popcount(b3); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] + 185 * popcount(kingRing[Us] & weak) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) + 69 * kingAttacksCount[Them] - + 3 * kingFlankAttacks * kingFlankAttacks / 8 + + 4 * (kingFlankAttack - kingFlankDefense) + + 3 * kingFlankAttack * kingFlankAttack / 8 + mg_value(mobility[Them] - mobility[Us]) - 873 * !pos.count(Them) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) @@ -468,7 +471,7 @@ namespace { score -= PawnlessFlank; // Penalty if king flank is under attack, potentially moving toward the king - score -= FlankAttacks * kingFlankAttacks; + score -= FlankAttacks * kingFlankAttack; if (T) Trace::add(KING, Us, score); From fe124896b241b4791454fd151da10101ad48f6d7 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 15 Nov 2019 18:16:27 +0100 Subject: [PATCH 20/59] Use exploration rate for reductions This patch measures how frequently search is exploring new configurations. This is done be computing a running average of ttHit. The ttHitAverage rate is somewhat low (e.g. 30% for startpos) in the normal case, while it can be very high if no progress is made (e.g. 90% for the fortress I used for testing). This information can be used to influence search. In this patch, by adjusting reductions if the rate > 50%. A first version (using a low ttHitAverageResolution and this 50% threshold) passed testing: STC LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 26425 W: 5837 L: 5650 D: 14938 http://tests.stockfishchess.org/tests/view/5dcede8b0ebc5902563258fa LTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 32313 W: 5392 L: 5128 D: 21793 http://tests.stockfishchess.org/tests/view/5dcefb1f0ebc590256325c0e However, as discussed in pull request 2414, using a larger ttHitAverageResolution gives a better approximation of the underlying distributions. This needs a slight adjustment for the threshold as the new distributions are shifted a bit compared to the older ones, and this threshold seemingly is sensitive (we used 0.53125 here). https://github.com/official-stockfish/Stockfish/pull/2414 This final version also passed testing, and is used for the patch: STC LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 16025 W: 3555 L: 3399 D: 9071 http://tests.stockfishchess.org/tests/view/5dd070b90ebc5902579e20c2 LTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 37576 W: 6277 L: 5998 D: 25301 http://tests.stockfishchess.org/tests/view/5dd0f58e6f544e798086f224 Closes https://github.com/official-stockfish/Stockfish/pull/2414 Bench: 4989584 --- src/search.cpp | 11 +++++++++++ src/thread.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index e75db243..24bcb9ad 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -61,6 +61,9 @@ namespace { // Different node types, used as a template parameter enum NodeType { NonPV, PV }; + constexpr uint64_t ttHitAverageWindow = 4096; + constexpr uint64_t ttHitAverageResolution = 1024; + // Razor and futility margins constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { @@ -363,6 +366,7 @@ void Thread::search() { multiPV = std::max(multiPV, (size_t)4); multiPV = std::min(multiPV, rootMoves.size()); + ttHitAverage = ttHitAverageWindow * ttHitAverageResolution / 2; int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns @@ -665,6 +669,9 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + // thisThread->ttHitAverage can be used to approximate the running average of ttHit + thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow + + ttHitAverageResolution * ttHit; // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -1082,6 +1089,10 @@ moves_loop: // When in check, search starts from here { Depth r = reduction(improving, depth, moveCount); + // Decrease reduction if the ttHit running average is large + if (thisThread->ttHitAverage > 544 * ttHitAverageResolution * ttHitAverageWindow / 1024) + r--; + // Reduction if other threads are searching this position. if (th.marked()) r++; diff --git a/src/thread.h b/src/thread.h index 087ed382..2b1f92b2 100644 --- a/src/thread.h +++ b/src/thread.h @@ -61,6 +61,7 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; size_t pvIdx, pvLast; + uint64_t ttHitAverage; int selDepth, nmpMinPly; Color nmpColor; std::atomic nodes, tbHits, bestMoveChanges; From e0f42aa956e731b5faae0585f5cc47da23fbe53c Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 17 Nov 2019 21:47:17 +0300 Subject: [PATCH 21/59] Simplify advanced pawn push pruning This patch simplifies away all conditions related to advanced pawn pushes in shallow depth pruning. Idea is based on fact that in master we have advanced pawn pushes not being pruned what we are only in PV node and when non-pawn material of opponent is > Bishop, so pretty rarely. With this patch we will have all pruning heuristics working for this moves as for every other move. STC LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 159143 W: 34271 L: 34418 D: 90454 http://tests.stockfishchess.org/tests/view/5dcdb3110ebc5902563249d7 LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 63900 W: 10375 L: 10322 D: 43203 http://tests.stockfishchess.org/tests/view/5dd05e820ebc5902579e1fb8 Closes https://github.com/official-stockfish/Stockfish/pull/2416 bench 4897149 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 24bcb9ad..b54ff196 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -974,8 +974,7 @@ moves_loop: // When in check, search starts from here moveCountPruning = moveCount >= futility_move_count(improving, depth); if ( !captureOrPromotion - && !givesCheck - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) + && !givesCheck) { // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); From 37698b0396e26a0f1364912dd1feae5dae5892ef Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 16 Nov 2019 14:42:47 -0500 Subject: [PATCH 22/59] Outpost Endgame values Remove the recent rank based Outpost array by using a weighted average value computed using a frequency analysis by rank from a large set of middle game positions. The higher eg values introduced by the new Outpost array (which were about twice the previous masters) are thus preserved. STC http://tests.stockfishchess.org/tests/view/5dd05c870ebc5902579e1f7f LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 42466 W: 9232 L: 9151 D: 24083 LTC http://tests.stockfishchess.org/tests/view/5dd146e342928ff08153dab1 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 66968 W: 10921 L: 10873 D: 45174 Closes https://github.com/official-stockfish/Stockfish/pull/2418 Bench: 5103360 --- src/evaluate.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2b7ab396..7760f705 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -126,11 +126,6 @@ namespace { S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; - // OutpostRank[Rank] contains a bonus according to the rank of the outpost - constexpr Score OutpostRank[RANK_NB] = { - S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19) - }; - // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); constexpr Score CorneredBishop = S( 50, 50); @@ -140,10 +135,11 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 32, 10); + 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 ReachableOutpost = S( 32, 10); constexpr Score RookOnQueenFile = S( 7, 6); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); @@ -242,7 +238,7 @@ namespace { // 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)); - kingRing[Us] = s | PseudoAttacks[KING][s]; + kingRing[Us] = PseudoAttacks[KING][s] | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -296,11 +292,11 @@ namespace { { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); - if (s & bb) - score += OutpostRank[relative_rank(Us, s)] * (Pt == KNIGHT ? 2 : 1); + if (bb & s) + score += Outpost * (Pt == KNIGHT ? 2 : 1); else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) - score += Outpost; + score += ReachableOutpost; // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) From 3f4191392c18f08011294aab880c31b15fc6f61c Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 20 Nov 2019 23:20:20 +0300 Subject: [PATCH 23/59] Do lmr for more captures Based on machinery introduced by vondele. Logic behind patch if relatively simple - if we reduce less with high hit rate of transposition table somewhat logical is to reduce more with low hit rate. For example enable all captures for LMR. Threshold 0.375 is arbitrary and can be tweaked :) STC http://tests.stockfishchess.org/tests/view/5dd4d51df531e81cf278eaac LLR: 2.97 (-2.94,2.94) [-1.50,4.50] Total: 16495 W: 3591 L: 3434 D: 9470 LTC http://tests.stockfishchess.org/tests/view/5dd52265f531e81cf278eace LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 23598 W: 3956 L: 3716 D: 15926 Closes https://github.com/official-stockfish/Stockfish/pull/2420 Bench: 5067870 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b54ff196..d3f38aae 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1084,7 +1084,8 @@ moves_loop: // When in check, search starts from here && ( !captureOrPromotion || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha - || cutNode)) + || cutNode + || thisThread->ttHitAverage < 384 * ttHitAverageResolution * ttHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); From 1fdf1f1ff5800bd8b1b1c33fc281b9731d40583d Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Thu, 21 Nov 2019 03:31:23 +0800 Subject: [PATCH 24/59] Simplify endgame factor for opposite colored bishops Stockfish is continually improving. Patches that gain elo in the past may no longer be needed as stockfish improved elsewhere. This patch removes passed pawns count dependence in opposite colored bishops scale factor. We used the mean of passed count pawns (~1.4) to compensate, and changed the base value from 16 to 22. Passed STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 57879 W: 12657 L: 12607 D: 32615 http://tests.stockfishchess.org/tests/view/5dd1644f42928ff08153dc1e Passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 121648 W: 19622 L: 19659 D: 82367 http://tests.stockfishchess.org/tests/view/5dd24572ccb823d41d4b47bb Closes https://github.com/official-stockfish/Stockfish/pull/2419 Bench: 5067864 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7760f705..eb5719bd 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -748,7 +748,7 @@ namespace { { if ( pos.opposite_bishops() && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 16 + 4 * pe->passed_count(); + sf = 22 ; else sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); From 87ed9facf16bc9d0af9daf8680801759ce1d8662 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sat, 23 Nov 2019 04:03:51 -0500 Subject: [PATCH 25/59] King danger: retire attacked-by-bishop defense In a recent commit, "Introduce king flank defenders," a term was introduced by Michael Chaly (@Vizvezdenec) to reduce king danger based on king defenders, i.e., friendly attacks on our King Flank and Camp. This is a powerful idea and broadly applicable to all of our pieces. An earlier, but narrower, version of a similar idea was already coded into king danger, with a term reducing king danger simply if we had a bishop and king attacking the same square -- there is also a similar term for knights, but roughly three times larger. I had attempted to tweak this term's coefficient fairly recently, in a series of tests in early September which increased this coefficient. All failed STC with significantly negative scores. Now that the king flank defenders term has been introduced, it appears that the bishop-defense term can be simplified away without compensation or significant Elo loss. Where do we go from here? This PR is a natural follow-up to "Introduce king flank defenders," which proposed simplification with existing and overlapping terms, such as this one. That PR also mentioned that the coefficient it introduced appeared arbitrary, so perhaps this PR can facilitate a tweak to increase king flank defenders' coefficient. Additionally, this pull request is extremely similar to https://github.com/official-stockfish/Stockfish/pull/1821, which was (coincidentally) merged a year ago, to the day (November 23, 2018). That patch also simplified away a linear king danger tropism term, which was soon after replaced with a quadratic term by @Vizvezdenec (which would not have passed without the simplification). @Vizvezdenec, again by coincidence, has recently been trying to implement a quadratic term, this time for defenders rather than attackers. This history of this evaluation code suggests that this simplification might be enough to help a patch for quadratic king-flank defenders pass. Bench: 4959670 STC: LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 22209 W: 4920 L: 4800 D: 12489 https://tests.stockfishchess.org/tests/view/5dd444d914339111b9b6bed7 LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 152107 W: 24658 L: 24743 D: 102706 https://tests.stockfishchess.org/tests/view/5dd4be31f531e81cf278ea9d Interesting discussion on Github about this pull request: https://github.com/official-stockfish/Stockfish/pull/2424 --- This pull request was opened less than one week before the holiday of Thanksgiving here in the United States. In keeping with the holiday tradition of expressing gratitude, I would like to thank our generous CPU donors, talented forum contributors, innovative developers, speedy fishtest approvers, and especially our hardworking server maintainers (@ppigazzini and @tomtor). Thank you all for a year of great Stockfish progress! --- src/evaluate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index eb5719bd..4c876820 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -454,7 +454,6 @@ namespace { + mg_value(mobility[Them] - mobility[Us]) - 873 * !pos.count(Them) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - 6 * mg_value(score) / 8 - 7; From 53125902e461ae129b408a81ada07aaf44810c6c Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 24 Nov 2019 21:57:09 +0100 Subject: [PATCH 26/59] Extend last non-pawn captures Extend last non-pawn captures at principal variation nodes because they are in general decisive moves with clear endgame result. STC http://tests.stockfishchess.org/tests/view/5ddafc86e75c0005326d2140 LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 9892 W: 2238 L: 2099 D: 5555 LTC http://tests.stockfishchess.org/tests/view/5ddb0401e75c0005326d2150 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 30369 W: 5013 L: 4756 D: 20600 Closes https://github.com/official-stockfish/Stockfish/pull/2425 Bench: 5059526 --- src/search.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index d3f38aae..e976274f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1049,6 +1049,12 @@ moves_loop: // When in check, search starts from here && pos.pawn_passed(us, to_sq(move))) extension = 1; + // Last captures extension + else if ( PvNode + && PieceValue[EG][pos.captured_piece()] > PawnValueEg + && pos.non_pawn_material() <= 2 * RookValueMg) + extension = 1; + // Castling extension if (type_of(move) == CASTLING) extension = 1; From df340a839c4d223c3053dc95dca02547ed83acee Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 26 Nov 2019 02:56:53 +0300 Subject: [PATCH 27/59] Simplify king danger This patch is a cleanup/simplification of king flank defenders patch, removing king flanks attacks linear dependance in kingdanger. Result of experiments with quadratic kingflank defenders scaling. Rebased on the latest master. passed STC http://tests.stockfishchess.org/tests/view/5ddc2b99e0b4af579302bacf LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 19660 W: 4309 L: 4184 D: 11167 passed LTC http://tests.stockfishchess.org/tests/view/5ddc3168e0b4af579302bade LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 24362 W: 3974 L: 3859 D: 16529 Closes https://github.com/official-stockfish/Stockfish/pull/2428 bench 5742013 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4c876820..116d5d66 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -449,13 +449,13 @@ namespace { + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) + 69 * kingAttacksCount[Them] - + 4 * (kingFlankAttack - kingFlankDefense) + 3 * kingFlankAttack * kingFlankAttack / 8 + mg_value(mobility[Them] - mobility[Us]) - 873 * !pos.count(Them) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 6 * mg_value(score) / 8 - - 7; + - 4 * kingFlankDefense + + 37; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 100) From 54253bcce69a0ebc3e6bc4c35dfa76f8ff46521e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 27 Nov 2019 19:03:23 +0100 Subject: [PATCH 28/59] Extend bench to static evaluations this patch extends bench to print static evaluations. ./stockfish bench 16 1 1 filename eval will now print the evaluations for all fens in the file. This complements the various 'go' flavors for bench and might be useful for debugging and/or tuning. No functional change. --- src/benchmark.cpp | 2 +- src/evaluate.cpp | 3 +++ src/uci.cpp | 15 ++++++++++----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 8f30bee4..58f05e66 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -117,7 +117,7 @@ vector setup_bench(const Position& current, istream& is) { string fenFile = (is >> token) ? token : "default"; string limitType = (is >> token) ? token : "depth"; - go = "go " + limitType + " " + limit; + go = limitType == "eval" ? "eval" : "go " + limitType + " " + limit; if (fenFile == "default") fens = Defaults; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 116d5d66..e42b4f38 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -847,6 +847,9 @@ Value Eval::evaluate(const Position& pos) { std::string Eval::trace(const Position& pos) { + if (pos.checkers()) + return "Total evaluation: none (in check)"; + std::memset(scores, 0, sizeof(scores)); pos.this_thread()->contempt = SCORE_ZERO; // Reset any dynamic contempt diff --git a/src/uci.cpp b/src/uci.cpp index 99bf1a13..6f0bdd76 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -146,7 +146,7 @@ namespace { uint64_t num, nodes = 0, cnt = 1; vector list = setup_bench(pos, args); - num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0; }); + num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0 || s.find("eval") == 0; }); TimePoint elapsed = now(); @@ -155,12 +155,17 @@ namespace { istringstream is(cmd); is >> skipws >> token; - if (token == "go") + if (token == "go" || token == "eval") { cerr << "\nPosition: " << cnt++ << '/' << num << endl; - go(pos, is, states); - Threads.main()->wait_for_search_finished(); - nodes += Threads.nodes_searched(); + if (token == "go") + { + go(pos, is, states); + Threads.main()->wait_for_search_finished(); + nodes += Threads.nodes_searched(); + } + else + sync_cout << "\n" << Eval::trace(pos) << sync_endl; } else if (token == "setoption") setoption(is); else if (token == "position") position(pos, is, states); From f0047ce08e655e61ca07508cb9793405f75286f9 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 30 Nov 2019 09:47:43 -0500 Subject: [PATCH 29/59] King proximity tweak for passed pawns Decrease slightly the penalty for opponent king distance to passed pawn. Instead of 5:2 ratio (or 20:8) we now have 19:8 STC http://tests.stockfishchess.org/tests/view/5de281b2727dc1d26718a673 LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 28638 W: 6297 L: 6104 D: 16237 LTC http://tests.stockfishchess.org/tests/view/5de2a2ff727dc1d26718a67b LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 59586 W: 9766 L: 9429 D: 40391 Where to go from here: Further tests will try a similar tweak on the friendly king proximity penalty, because recent experiments indicate that this penalty is quite sensitive, but I wanted to try first on the larger term. Closes https://github.com/official-stockfish/Stockfish/pull/2435 bench: 5258928 --------------- Increasing the penalty ratio to 21:8 was neutral. http://tests.stockfishchess.org/tests/view/5de2814d727dc1d26718a671 Decreasing the penalty ratio a bit more to 9:4 seems less promising http://tests.stockfishchess.org/tests/view/5de2f4c2727dc1d26718a691 http://tests.stockfishchess.org/tests/view/5de32ecc727dc1d26718a6b0 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e42b4f38..1988e20e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -602,8 +602,8 @@ namespace { Square blockSq = s + Up; // Adjust bonus based on the king's proximity - bonus += make_score(0, ( king_proximity(Them, blockSq) * 5 - - king_proximity(Us, blockSq) * 2) * w); + bonus += make_score(0, ( (king_proximity(Them, blockSq) * 19) / 4 + - king_proximity(Us, blockSq) * 2) * w); // If blockSq is not the queening square then consider also a second push if (r != RANK_7) From 97a0e4e8170df33b927c48d734e0132e9ef8a22f Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 29 Nov 2019 19:15:21 +0200 Subject: [PATCH 30/59] UnblockedStorm tuned STC http://tests.stockfishchess.org/tests/view/5de155980294ec4750cba9bd LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 60206 W: 13295 L: 12895 D: 34016 LTC http://tests.stockfishchess.org/tests/view/5de22f6f0294ec4750cba9e7 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 182005 W: 29571 L: 28902 D: 123532 VLTC http://tests.stockfishchess.org/tests/view/5de4adca5e868d334be516c1 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 42101 W: 6068 L: 5978 D: 30055 Bench: 5122362 --- src/pawns.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 3ddf7030..04222a2a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -56,10 +56,10 @@ namespace { // is behind our king. Note that UnblockedStorm[0][1-2] accommodate opponent pawn // on edge, likely blocked by our king. constexpr Value UnblockedStorm[int(FILE_NB) / 2][RANK_NB] = { - { V( 89), V(-285), V(-185), V(93), V(57), V( 45), V( 51) }, - { V( 44), V( -18), V( 123), V(46), V(39), V( -7), V( 23) }, - { V( 4), V( 52), V( 162), V(37), V( 7), V(-14), V( -2) }, - { V(-10), V( -14), V( 90), V(15), V( 2), V( -7), V(-16) } + { V( 85), V(-289), V(-166), V(97), V(50), V( 45), V( 50) }, + { V( 46), V( -25), V( 122), V(45), V(37), V(-10), V( 20) }, + { V( -6), V( 51), V( 168), V(34), V(-2), V(-22), V(-14) }, + { V(-15), V( -11), V( 101), V( 4), V(11), V(-15), V(-29) } }; #undef S From 6a6fc28551b84719868df99950584b878199d0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Mon, 9 Dec 2019 00:00:34 +0100 Subject: [PATCH 31/59] The sudo tag is deprecated in Travis CI Reported by Christian Clauss. Thanks! No functional change --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a59ea425..e2b42e6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: cpp -sudo: required dist: xenial matrix: From 0256416bb7b3ba7e96a487062104a9379c0c3a82 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 12 Nov 2019 16:12:09 +0100 Subject: [PATCH 32/59] Remove unneeded & incorrect check. the removed line is not needed, since with the conditions on SE, eval equals ttValue (except inCheck), which must be larger than beta if the second condition is true. The removed line is also incorrect as eval might be VALUE_NONE at this location if inCheck. This removal addresses part of https://github.com/official-stockfish/Stockfish/pull/2406#issuecomment-552642608 No functional change. --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e976274f..26010108 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1033,8 +1033,7 @@ moves_loop: // When in check, search starts from here // search without the ttMove. So we assume this expected Cut-node is not singular, // that multiple moves fail high, and we can prune the whole subtree by returning // a soft bound. - else if ( eval >= beta - && singularBeta >= beta) + else if (singularBeta >= beta) return singularBeta; } From 20484ccdd5876deee4138d8badea4ef44b73341f Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sun, 8 Dec 2019 11:06:19 +0000 Subject: [PATCH 33/59] Tweak time management (failing eval) Adjust fallingEval with score change in last 5 iterations. FallingEval adjusts the time used on a move depending on whether the position score is better or worse than on the previous move. This change adds a dependency on the score change in the last 5 iterations of the current search. Tests with original code: STC : LLR: 2.97 (-2.94,2.94) [-1.50,4.50] Total: 18728 W: 4170 L: 4005 D: 10553 https://tests.stockfishchess.org/tests/view/5de68a5bb407ee7bfda68a94 LTC : LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 180217 W: 29214 L: 28551 D: 122452 https://tests.stockfishchess.org/tests/view/5de690a4b407ee7bfda68a9a Revised code using a simple array instead of a deque and different values gave a slightly quicker pass at LTC. The merged patch now uses this: STC : LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 18616 W: 4114 L: 3950 D: 10552 https://tests.stockfishchess.org/tests/view/5debb790b7bdefd50db28d14 LTC : LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 134151 W: 21729 L: 21191 D: 91231 https://tests.stockfishchess.org/tests/view/5debc13fb7bdefd50db28d19 No functional change --- src/search.cpp | 17 ++++++++++++++++- src/thread.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 26010108..e8ca5c58 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -335,6 +335,7 @@ void Thread::search() { MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); double timeReduction = 1, totBestMoveChanges = 0; Color us = rootPos.side_to_move(); + int iterIdx = 0; std::memset(ss-7, 0, 10 * sizeof(Stack)); for (int i = 7; i > 0; i--) @@ -345,6 +346,16 @@ void Thread::search() { bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; + if (mainThread) + { + if (mainThread->previousScore == 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; + } + size_t multiPV = Options["MultiPV"]; // Pick integer skill levels, but non-deterministically round up or down @@ -520,7 +531,8 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (354 + 10 * (mainThread->previousScore - bestValue)) / 692.0; + double fallingEval = (354 + 6 * (mainThread->previousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 692.0; fallingEval = clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly @@ -547,6 +559,9 @@ void Thread::search() { Threads.stop = true; } } + + mainThread->iterValue[iterIdx] = bestValue; + iterIdx = (iterIdx + 1) & 3; } if (!mainThread) diff --git a/src/thread.h b/src/thread.h index 2b1f92b2..a1545072 100644 --- a/src/thread.h +++ b/src/thread.h @@ -88,6 +88,7 @@ struct MainThread : public Thread { double previousTimeReduction; Value previousScore; + Value iterValue[4]; int callsCnt; bool stopOnPonderhit; std::atomic_bool ponder; From a6b5ba1b6404ce8aec8a2be8b7354dcb89cfda3f Mon Sep 17 00:00:00 2001 From: joergoster Date: Fri, 6 Dec 2019 10:11:45 +0100 Subject: [PATCH 34/59] Fix output of PV lines with invalid scores #2439 As reported on the forum it is possible, on very rare occasions, that we are trying to print a PV line with an invalid previousScore, although this line has a valid actual score. This patch fixes output of PV lines with invalid scores in a MultiPV search. This is a follow-up patch to 8b15961 and makes the fix finally complete. The reason is the i <= pvIdx condition which probably is a leftover from the times there was a special root search function. This check is no longer needed today and prevents PV lines past the current one (current pvIdx) to be flagged as updated even though they do have a valid score. https://github.com/official-stockfish/Stockfish/commit/8b15961349e18a9ba113973c53f53913d0cd0fad https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/PrnoDLvMvro No functional change. --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e8ca5c58..a6c93b43 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1741,7 +1741,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { for (size_t i = 0; i < multiPV; ++i) { - bool updated = (i <= pvIdx && rootMoves[i].score != -VALUE_INFINITE); + bool updated = rootMoves[i].score != -VALUE_INFINITE; if (depth == 1 && !updated) continue; From 78eeba29a20e007a5bd940e65569a594ee6d6324 Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 6 Dec 2019 08:56:17 -0700 Subject: [PATCH 35/59] Simplify pruning moves with negative SEE This patch simplifies pruning moves with negative SEE values. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 18847 W: 4211 L: 4084 D: 10552 http://tests.stockfishchess.org/tests/view/5de983f2caa7c610e4d1866e LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 25556 W: 4200 L: 4087 D: 17269 http://tests.stockfishchess.org/tests/view/5de99e21caa7c610e4d18676 Bench 5390930 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index a6c93b43..f39f1de1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1478,9 +1478,7 @@ moves_loop: // When in check, search starts from here && !pos.capture(move); // Don't search moves with negative SEE values - if ( (!inCheck || evasionPrunable) - && !(givesCheck && pos.is_discovery_check_on_king(~pos.side_to_move(), move)) - && !pos.see_ge(move)) + if ( (!inCheck || evasionPrunable) && !pos.see_ge(move)) continue; // Speculative prefetch as early as possible From d00b2ec6bdd63bd88f5553b81b5da88bb298cb4f Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 7 Dec 2019 17:56:33 +0300 Subject: [PATCH 36/59] Do last capture extensions for every single node This patch simplifies latest @MJZ1977 elo gainer. Seems like PvNode check in condition of last capture extension is not needed. Note - even if this is a simplification it actually causes this extension to be applied more often, thus strengthening effect of @MJZ1977's patch. passed STC http://tests.stockfishchess.org/tests/view/5deb9a3eb7bdefd50db28d0e LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 80244 W: 17421 L: 17414 D: 45409 passed LTC http://tests.stockfishchess.org/tests/view/5deba860b7bdefd50db28d11 LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 21506 W: 3565 L: 3446 D: 14495 Bench: 5097036 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f39f1de1..21c36f50 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1064,8 +1064,7 @@ moves_loop: // When in check, search starts from here extension = 1; // Last captures extension - else if ( PvNode - && PieceValue[EG][pos.captured_piece()] > PawnValueEg + else if ( PieceValue[EG][pos.captured_piece()] > PawnValueEg && pos.non_pawn_material() <= 2 * RookValueMg) extension = 1; From 764b9adda6cf59719b5c9c8a75d2a2e696395709 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 8 Dec 2019 17:10:14 +0300 Subject: [PATCH 37/59] Exclude blockers for king from mobility area This patch excludes blockers for king from mobility area. It was tried a couple of times by now but now it passed. Performance is not enormously good but this patch makes a lot of sence - blockers for king can't really move until king moves (in most cases) so logic behind it is the same as behind excluding king square from mobility area. STC http://tests.stockfishchess.org/tests/view/5dec388651219d7befdc76be LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 6155 W: 1428 L: 1300 D: 3427 LTC http://tests.stockfishchess.org/tests/view/5dec4a3151219d7befdc76d3 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 120800 W: 19636 L: 19134 D: 82030 Bench: 5173081 --- src/evaluate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 1988e20e..20d1059e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -225,9 +225,9 @@ namespace { // Find our pawns that are blocked or on the first two ranks Bitboard b = pos.pieces(Us, PAWN) & (shift(pos.pieces()) | LowRanks); - // Squares occupied by those pawns, by our king or queen or controlled by - // enemy pawns are excluded from the mobility area. - mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); + // Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king + // or controlled by enemy pawns are excluded from the mobility area. + 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); From 3ef0c3c34a00e6b13d6c96d8c2f0d8d7a6cc25a6 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Mon, 9 Dec 2019 21:38:57 +0000 Subject: [PATCH 38/59] TrappedRook value and King positional tables Small tweak to increase the TrappedRook penalty. Nice idea by Alain Savard! STC LLR: 2.96 (-2.94,2.94) [-1.50,4.50] Total: 36977 W: 8212 L: 7993 D: 20772 https://tests.stockfishchess.org/tests/view/5dee1c1e3cff9a249bb9e46d LTC LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 36395 W: 6070 L: 5795 D: 24530 https://tests.stockfishchess.org/tests/view/5dee90153cff9a249bb9e479 Closes https://github.com/official-stockfish/Stockfish/pull/2447 Bench: 5176990 ------------------------- Comments by Alain Savard: For the record, the idea was to run an experimental tuning with disabled castling in the hope to get more hits on the TrappedRook and the king in the c1- f1-f2-c2 area http://tests.stockfishchess.org/tests/view/5dec57be51219d7befdc76e1 A first interpretation of that tuning was green STC (0, 4) and yellow LTC (0, 4): http://tests.stockfishchess.org/tests/view/5ded04bc51219d7befdc773a http://tests.stockfishchess.org/tests/view/5ded1e7a51219d7befdc7760 Thank you @xoto for trying this. Indeed, because the tuned Kc2 and Kf2 values were quite different, it was a good idea to try something more neutral. --- src/evaluate.cpp | 2 +- src/psqt.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 20d1059e..e7d30825 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( 47, 4); + constexpr Score TrappedRook = S( 52, 10); constexpr Score WeakQueen = S( 49, 15); #undef S diff --git a/src/psqt.cpp b/src/psqt.cpp index 60d17ad2..c11dc5ba 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -79,8 +79,8 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } }, { // King - { S(271, 1), S(327, 45), S(270, 85), S(192, 76) }, - { S(278, 53), S(303,100), S(230,133), S(174,135) }, + { S(271, 1), S(327, 45), S(271, 85), S(198, 76) }, + { S(278, 53), S(303,100), S(234,133), S(179,135) }, { S(195, 88), S(258,130), S(169,169), S(120,175) }, { S(164,103), S(190,156), S(138,172), S( 98,172) }, { S(154, 96), S(179,166), S(105,199), S( 70,199) }, From 443787b0d1dceb6186e217ea2b2224e76806ea15 Mon Sep 17 00:00:00 2001 From: lantonov Date: Mon, 9 Dec 2019 20:50:47 +0200 Subject: [PATCH 39/59] Tuned razor and futility margins Tuning was done with Bayesian optimisation with the following parameters: Acquisition function: Expected Improvement alpha: 0.05 xi: 1e-4 TC: 60+0.6 Number of iterations: 100 Initial points: 5 Batch size: 20 games STC http://tests.stockfishchess.org/tests/view/5dee291e3cff9a249bb9e470 LLR: 2.97 (-2.94,2.94) [-1.50,4.50] Total: 19586 W: 4382 L: 4214 D: 10990 LTC http://tests.stockfishchess.org/tests/view/5dee4e273cff9a249bb9e473 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 38840 W: 6315 L: 6036 D: 26489 Bench: 5033242 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 21c36f50..c856980b 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 = 661; + constexpr int RazorMargin = 594; Value futility_margin(Depth d, bool improving) { - return Value(198 * (d - improving)); + return Value(232 * (d - improving)); } // Reductions lookup table, initialized at startup From b6482472a03833287dc21bdaa783f156978ac63e Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Tue, 10 Dec 2019 08:07:34 +0100 Subject: [PATCH 40/59] Refine improving-logic Don't rely on the assumption that we are improving after surviving a check. Instead, compare with the static eval of 2 moves before. STC https://tests.stockfishchess.org/tests/view/5dedfd7f3cff9a249bb9e44d LLR: 2.95 (-2.94,2.94) [-1.50,4.50] Total: 38859 W: 8621 L: 8397 D: 21841 LTC https://tests.stockfishchess.org/tests/view/5dee1b5a3cff9a249bb9e465 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 51130 W: 8308 L: 7996 D: 34826 Bench: 5371271 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c856980b..55e04ec3 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -812,8 +812,8 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); - improving = ss->staticEval >= (ss-2)->staticEval - || (ss-2)->staticEval == VALUE_NONE; + 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 (~30 Elo) if ( !PvNode From 13f70d0392ca3ce7f1c8e34dd0a10c3537d2fbab Mon Sep 17 00:00:00 2001 From: xoto10 Date: Fri, 13 Dec 2019 04:59:06 +0000 Subject: [PATCH 41/59] Tune search constants STC failed red : LLR: -2.95 (-2.94,2.94) [0.00,3.50] Total: 41667 W: 9094 L: 9138 D: 23435 https://tests.stockfishchess.org/tests/view/5df7bb566932658fe9b45253 LTC failed yellow : LLR: -2.96 (-2.94,2.94) [0.00,3.50] Total: 113667 W: 18330 L: 18196 D: 77141 https://tests.stockfishchess.org/tests/view/5df562386932658fe9b451c7 VLTC turned green : LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 128630 W: 17747 L: 17273 D: 93610 https://tests.stockfishchess.org/tests/view/5df9054dcde01bf360ab78db Bench 5180012 --- src/search.cpp | 52 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 55e04ec3..b0bcc57a 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 = 594; + constexpr int RazorMargin = 531; Value futility_margin(Depth d, bool improving) { - return Value(232 * (d - improving)); + return Value(217 * (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 + 520) / 1024 + (!i && r > 999); + return (r + 511) / 1024 + (!i && r > 1007); } 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 > 17 ? -8 : 22 * d * d + 151 * d - 140; + return d > 15 ? -8 : 19 * d * d + 155 * d - 132; } // 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((23.4 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((24.8 + std::log(Threads.size()) / 2) * std::log(i)); } @@ -428,12 +428,12 @@ void Thread::search() { if (rootDepth >= 4) { Value previousScore = rootMoves[pvIdx].previousScore; - delta = Value(21 + abs(previousScore) / 128); + delta = Value(21 + abs(previousScore) / 256); alpha = std::max(previousScore - delta,-VALUE_INFINITE); beta = std::min(previousScore + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + (111 - ct / 2) * previousScore / (abs(previousScore) + 176); + int dct = ct + (102 - ct / 2) * previousScore / (abs(previousScore) + 157); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -531,13 +531,13 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (354 + 6 * (mainThread->previousScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 692.0; + double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; fallingEval = clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.97 : 0.98; - double reduction = (1.36 + mainThread->previousTimeReduction) / (2.29 * timeReduction); + timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.94 : 0.91; + double reduction = (1.41 + mainThread->previousTimeReduction) / (2.27 * timeReduction); // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) @@ -817,7 +817,7 @@ namespace { // Step 8. Futility pruning: child node (~30 Elo) if ( !PvNode - && depth < 7 + && depth < 6 && eval - futility_margin(depth, improving) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; @@ -825,10 +825,10 @@ namespace { // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 22661 + && (ss-1)->statScore < 23405 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 33 * depth + 299 - improving * 30 + && ss->staticEval >= beta - 32 * depth + 317 - improving * 30 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -836,7 +836,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); + Depth R = (854 + 68 * depth) / 258 + std::min(int(eval - beta) / 192, 3); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -879,7 +879,7 @@ namespace { && depth >= 5 && abs(beta) < VALUE_MATE_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE); + Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); int probCutCount = 0; @@ -1003,14 +1003,14 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~2 Elo) if ( lmrDepth < 6 && !inCheck - && ss->staticEval + 250 + 211 * lmrDepth <= alpha) + && ss->staticEval + 255 + 182 * lmrDepth <= alpha) continue; // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) + else if (!pos.see_ge(move, Value(-194) * depth)) // (~20 Elo) continue; } @@ -1104,12 +1104,12 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || thisThread->ttHitAverage < 384 * 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 > 544 * ttHitAverageResolution * ttHitAverageWindow / 1024) + if (thisThread->ttHitAverage > 500 * ttHitAverageResolution * ttHitAverageWindow / 1024) r--; // Reduction if other threads are searching this position. @@ -1121,7 +1121,7 @@ moves_loop: // When in check, search starts from here r -= 2; // Decrease reduction if opponent's move count is high (~10 Elo) - if ((ss-1)->moveCount > 15) + if ((ss-1)->moveCount > 14) r--; // Decrease reduction if ttMove has been singularly extended @@ -1149,7 +1149,7 @@ 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)] - - 4729; + - 4926; // Reset statScore to zero if negative and most stats shows >= 0 if ( ss->statScore < 0 @@ -1159,10 +1159,10 @@ moves_loop: // When in check, search starts from here ss->statScore = 0; // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) - if (ss->statScore >= -99 && (ss-1)->statScore < -116) + if (ss->statScore >= -102 && (ss-1)->statScore < -114) r--; - else if ((ss-1)->statScore >= -117 && ss->statScore < -144) + else if ((ss-1)->statScore >= -116 && ss->statScore < -154) r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) @@ -1421,7 +1421,7 @@ moves_loop: // When in check, search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 153; + futilityBase = bestValue + 154; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From 44f56e04e22bb449d44475eb054b67c1c22d27ef Mon Sep 17 00:00:00 2001 From: ppigazzini Date: Sat, 4 Jan 2020 02:48:32 +0100 Subject: [PATCH 42/59] Update Readme.md Update fishtest server URL, fix a broken wiki link, fix a typo. --- Readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 10ffdeae..5b807ee6 100644 --- a/Readme.md +++ b/Readme.md @@ -162,12 +162,12 @@ community effort. There are a few ways to help contribute to its growth. ### Donating hardware Improving Stockfish requires a massive amount of testing. You can donate -your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker) -and view the current tests on [Fishtest](http://tests.stockfishchess.org/tests). +your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker:-overview) +and view the current tests on [Fishtest](https://tests.stockfishchess.org/tests). ### Improving the code -If you want to help improve the code, there are several valuable ressources: +If you want to help improve the code, there are several valuable resources: * [In this wiki,](https://www.chessprogramming.org) many techniques used in Stockfish are explained with a lot of background information. @@ -179,7 +179,7 @@ Nevertheless, a helpful resource. * The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish). Discussions about Stockfish take place in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) -group and engine testing is done on [Fishtest](http://tests.stockfishchess.org/tests). +group and engine testing is done on [Fishtest](https://tests.stockfishchess.org/tests). If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test) first, where the basics of Stockfish development are explained. From 83ecfa7c33ab3e89fcbc506f0f4d5312baa26aeb Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 4 Jan 2020 13:54:35 -0500 Subject: [PATCH 43/59] Use a faster implementation of Static Exchange Evaluation SEE (Static Exchange Evaluation) is a critical component, so we might indulge some tricks to make it faster. Another pull request #2469 showed some speedup by removing templates, this version uses Ronald de Man (@syzygy1) SEE implementation which also unrolls the for loop by suppressing the min_attacker() helper function and exits as soon as the last swap is conclusive. See Ronald de Man version there: https://github.com/syzygy1/Cfish/blob/master/src/position.c Patch testes against pull request #2469: LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 19365 W: 3771 L: 3634 D: 11960 Ptnml(0-2): 241, 1984, 5099, 2092, 255 http://tests.stockfishchess.org/tests/view/5e10eb135e5436dd91b27ba3 And since we are using new SPRT statistics, and that both pull requests finished with less than 20000 games I also tested against master as a speed-up: LLR: 2.99 (-2.94,2.94) {-1.00,3.00} Total: 18878 W: 3674 L: 3539 D: 11665 Ptnml(0-2): 193, 1999, 4966, 2019, 250 http://tests.stockfishchess.org/tests/view/5e10febf12ef906c8b388745 Non functional change --- src/position.cpp | 162 +++++++++++++++++++++-------------------------- 1 file changed, 73 insertions(+), 89 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 6336a5ed..9644e02c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -50,41 +50,6 @@ const string PieceToChar(" PNBRQK pnbrqk"); constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING, B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING }; - -// min_attacker() is a helper function used by see_ge() to locate the least -// valuable attacker for the side to move, remove the attacker we just found -// from the bitboards and scan for new X-ray attacks behind it. - -template -PieceType min_attacker(const Bitboard* byTypeBB, Square to, Bitboard stmAttackers, - Bitboard& occupied, Bitboard& attackers) { - - Bitboard b = stmAttackers & byTypeBB[Pt]; - if (!b) - return min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); - - occupied ^= lsb(b); // Remove the attacker from occupied - - // Add any X-ray attack behind the just removed piece. For instance with - // rooks in a8 and a7 attacking a1, after removing a7 we add rook in a8. - // Note that new added attackers can be of any color. - if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) - attackers |= attacks_bb(to, occupied) & (byTypeBB[BISHOP] | byTypeBB[QUEEN]); - - if (Pt == ROOK || Pt == QUEEN) - attackers |= attacks_bb(to, occupied) & (byTypeBB[ROOK] | byTypeBB[QUEEN]); - - // X-ray may add already processed pieces because byTypeBB[] is constant: in - // the rook example, now attackers contains _again_ rook in a7, so remove it. - attackers &= occupied; - return Pt; -} - -template<> -PieceType min_attacker(const Bitboard*, Square, Bitboard, Bitboard&, Bitboard&) { - return KING; // No need to update bitboards: it is the last cycle -} - } // namespace @@ -1052,77 +1017,96 @@ bool Position::see_ge(Move m, Value threshold) const { if (type_of(m) != NORMAL) return VALUE_ZERO >= threshold; - Bitboard stmAttackers; Square from = from_sq(m), to = to_sq(m); - PieceType nextVictim = type_of(piece_on(from)); - Color us = color_of(piece_on(from)); - Color stm = ~us; // First consider opponent's move - Value balance; // Values of the pieces taken by us minus opponent's ones - // The opponent may be able to recapture so this is the best result - // we can hope for. - balance = PieceValue[MG][piece_on(to)] - threshold; - - if (balance < VALUE_ZERO) + int swap = PieceValue[MG][piece_on(to)] - threshold; + if (swap < 0) return false; - // Now assume the worst possible result: that the opponent can - // capture our piece for free. - balance -= PieceValue[MG][nextVictim]; - - // If it is enough (like in PxQ) then return immediately. Note that - // in case nextVictim == KING we always return here, this is ok - // if the given move is legal. - if (balance >= VALUE_ZERO) + swap = PieceValue[MG][piece_on(from)] - swap; + if (swap <= 0) return true; - // Find all attackers to the destination square, with the moving piece - // removed, but possibly an X-ray attacker added behind it. - Bitboard occupied = pieces() ^ from ^ to; - Bitboard attackers = attackers_to(to, occupied) & occupied; + Bitboard occ = pieces() ^ from ^ to; + Color stm = color_of(piece_on(from)); + Bitboard attackers = attackers_to(to, occ); + Bitboard stmAttackers, bb; + int res = 1; while (true) { - stmAttackers = attackers & pieces(stm); - - // Don't allow pinned pieces to attack (except the king) as long as - // any pinners are on their original square. - if (st->pinners[~stm] & occupied) - stmAttackers &= ~st->blockersForKing[stm]; + stm = ~stm; + attackers &= occ; // If stm has no more attackers then give up: stm loses + if (!(stmAttackers = attackers & pieces(stm))) + break; + + // Don't allow pinned pieces to attack (except the king) as long as + // there are pinners on their original square. + if (st->pinners[~stm] & occ) + stmAttackers &= ~st->blockersForKing[stm]; + if (!stmAttackers) break; + res ^= 1; + // Locate and remove the next least valuable attacker, and add to - // the bitboard 'attackers' the possibly X-ray attackers behind it. - nextVictim = min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); - - stm = ~stm; // Switch side to move - - // Negamax the balance with alpha = balance, beta = balance+1 and - // add nextVictim's value. - // - // (balance, balance+1) -> (-balance-1, -balance) - // - assert(balance < VALUE_ZERO); - - balance = -balance - 1 - PieceValue[MG][nextVictim]; - - // If balance is still non-negative after giving away nextVictim then we - // win. The only thing to be careful about it is that we should revert - // stm if we captured with the king when the opponent still has attackers. - if (balance >= VALUE_ZERO) + // the bitboard 'attackers' any X-ray attackers behind it. + if ((bb = stmAttackers & pieces(PAWN))) { - if (nextVictim == KING && (attackers & pieces(stm))) - stm = ~stm; - break; - } - assert(nextVictim != KING); - } - return us != stm; // We break the above loop when stm loses -} + if ((swap = PawnValueMg - swap) < res) + break; + occ ^= lsb(bb); + attackers |= attacks_bb(to, occ) & pieces(BISHOP, QUEEN); + } + + else if ((bb = stmAttackers & pieces(KNIGHT))) + { + if ((swap = KnightValueMg - swap) < res) + break; + + occ ^= lsb(bb); + } + + else if ((bb = stmAttackers & pieces(BISHOP))) + { + if ((swap = BishopValueMg - swap) < res) + break; + + occ ^= lsb(bb); + attackers |= attacks_bb(to, occ) & pieces(BISHOP, QUEEN); + } + + else if ((bb = stmAttackers & pieces(ROOK))) + { + if ((swap = RookValueMg - swap) < res) + break; + + occ ^= lsb(bb); + attackers |= attacks_bb(to, occ) & pieces(ROOK, QUEEN); + } + + else if ((bb = stmAttackers & pieces(QUEEN))) + { + if ((swap = QueenValueMg - swap) < res) + break; + + occ ^= lsb(bb); + attackers |= (attacks_bb(to, occ) & pieces(BISHOP, QUEEN)) + | (attacks_bb(to, occ) & pieces(ROOK , QUEEN)); + } + + else // KING + // If we "capture" with the king but opponent still has attackers, + // reverse the result. + return (attackers & ~pieces(stm)) ? res ^ 1 : res; + } + + return res; +} /// Position::is_draw() tests whether the position is drawn by 50-move rule /// or by repetition. It does not detect stalemates. From 56d5504f6548b69ce6faaa271a8b55f3773db70c Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 3 Jan 2020 11:49:25 +0100 Subject: [PATCH 44/59] Tweak futility pruning Exclude moves with a good history total from futility pruning. This adds a condition for quiet futility pruning: history total has to be low. STC: LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 20095 W: 4503 L: 4342 D: 11250 Ptnml(0-2): 362, 2380, 4422, 2486, 388 http://tests.stockfishchess.org/tests/view/5e0d7c5387585b1706b68370 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 53016 W: 8587 L: 8302 D: 36127 Ptnml(0-2): 353, 5397, 14751, 5545, 423 http://tests.stockfishchess.org/tests/view/5e0e30d062fb773bb7047e95 Closes https://github.com/official-stockfish/Stockfish/pull/2472 Bench: 5215200 --- src/search.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b0bcc57a..57316d85 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1003,7 +1003,11 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~2 Elo) if ( lmrDepth < 6 && !inCheck - && ss->staticEval + 255 + 182 * lmrDepth <= alpha) + && ss->staticEval + 255 + 182 * lmrDepth <= alpha + && thisThread->mainHistory[us][from_to(move)] + + (*contHist[0])[movedPiece][to_sq(move)] + + (*contHist[1])[movedPiece][to_sq(move)] + + (*contHist[3])[movedPiece][to_sq(move)] < 30000) continue; // Prune moves with negative SEE (~10 Elo) From de4e1cb88d9d5a6b4bf6e47bdc2a71e025bf8f46 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 3 Jan 2020 05:53:59 +0300 Subject: [PATCH 45/59] Introduce king infiltration bonus Add king infiltration bonus to initiative calculation. Idea is somewhat similar to outflanking - endgames are hard to win if each king is on it side of the board. So this adds extra bonus for one of kings crossing the middle line. STC LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 10533 W: 2372 L: 2242 D: 5919 Ptnml(0-2): 196, 1198, 2352, 1316, 202 http://tests.stockfishchess.org/tests/view/5e0e6fd1e97ea42ea89da9b3 LTC LLR: 2.96 (-2.94,2.94) {0.00,2.00} Total: 15074 W: 2563 L: 2381 D: 10130 Ptnml(0-2): 118, 1500, 4111, 1663, 129 http://tests.stockfishchess.org/tests/view/5e0e857ae97ea42ea89da9cc Closes https://github.com/official-stockfish/Stockfish/pull/2471 Bench: 5146339 --- src/evaluate.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e7d30825..27fcd477 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -705,6 +705,9 @@ 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); @@ -716,10 +719,11 @@ namespace { int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking + + 12 * infiltration + 21 * pawnsOnBothFlanks + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 95 ; + - 100 ; // 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 From 44f79bdf5a092c3acec0a8bf8f2c1440e5a9da90 Mon Sep 17 00:00:00 2001 From: lantonov Date: Wed, 1 Jan 2020 10:10:39 +0200 Subject: [PATCH 46/59] Tuned nullmove search Tuning was done with Bayesian optimisation and sequential use of gaussian process regressor and gaussian process classifier. The latter is used in lieu of ordinal categorical modelling. Details will be given in Fishcooking forum topic: https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/b3uhBBJcJG4 STC: LLR: 2.96 (-2.94,2.94) {-1.00,3.00} Total: 10248 W: 2361 L: 2233 D: 5654 Ptnml(0-2): 191, 1153, 2303, 1276, 194 http://tests.stockfishchess.org/tests/view/5e0ba4159d3fbe26f672d4e6 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 16003 W: 2648 L: 2458 D: 10897 Ptnml(0-2): 121, 1595, 4394, 1718, 153 http://tests.stockfishchess.org/tests/view/5e0bb8519d3fbe26f672d4fd Closes https://github.com/official-stockfish/Stockfish/pull/2468 Bench 4747984 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 57316d85..25a7cf44 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -825,10 +825,10 @@ namespace { // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23405 + && (ss-1)->statScore < 23397 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 32 * depth + 317 - improving * 30 + && ss->staticEval >= beta - 32 * depth + 292 - improving * 30 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) From 09bef14c76e119103cc1a9404cbde7e249205deb Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Tue, 7 Jan 2020 15:35:47 -0500 Subject: [PATCH 47/59] Update lists of authors and contributors Preparing for version 11 of Stockfish: update lists of authors, contributors giving CPU time to the fishtest framework, etc. No functional change --- AUTHORS | 50 ++++--- Top CPU Contributors.txt | 296 ++++++++++++++++++++------------------- src/benchmark.cpp | 2 +- src/bitbase.cpp | 2 +- src/bitboard.cpp | 2 +- src/bitboard.h | 2 +- src/endgame.cpp | 2 +- src/endgame.h | 2 +- src/evaluate.cpp | 2 +- src/evaluate.h | 2 +- src/main.cpp | 2 +- src/material.cpp | 2 +- src/material.h | 2 +- src/misc.cpp | 2 +- src/misc.h | 2 +- src/movegen.cpp | 2 +- src/movegen.h | 2 +- src/movepick.cpp | 2 +- src/movepick.h | 2 +- src/pawns.cpp | 2 +- src/pawns.h | 2 +- src/position.cpp | 2 +- src/position.h | 2 +- src/psqt.cpp | 2 +- src/search.cpp | 2 +- src/search.h | 2 +- src/syzygy/tbprobe.cpp | 2 +- src/syzygy/tbprobe.h | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- src/thread_win32_osx.h | 2 +- src/timeman.cpp | 2 +- src/timeman.h | 2 +- src/tt.cpp | 2 +- src/tt.h | 2 +- src/types.h | 2 +- src/uci.cpp | 2 +- src/uci.h | 2 +- src/ucioption.cpp | 2 +- 39 files changed, 222 insertions(+), 198 deletions(-) diff --git a/AUTHORS b/AUTHORS index 979410ae..4638b41a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# List of authors for Stockfish, updated for version 10 +# List of authors for Stockfish, as of January 7, 2020 Tord Romstad (romstad) Marco Costalba (mcostalba) @@ -22,18 +22,23 @@ Auguste Pop Balint Pfliegel Ben Koshy (BKSpurgeon) Bill Henry (VoyagerOne) +Bojun Guo (noobpwnftw, Nooby) braich -Bojun Guo (noobpwnftw) -Brian Sheppard (SapphireBrand) +Brian Sheppard (SapphireBrand, briansheppard-toast) Bryan Cross (crossbr) +candirufish +Chess13234 Chris Cain (ceebo) -Dan Schmidt +Dan Schmidt (dfannius) +Daniel Axtens (daxtens) Daniel Dugovic (ddugovic) Dariusz Orzechowski David Zar Daylen Yang (daylen) DiscanX -Eelco de Groot +double-beep +Eduardo Cáceres (eduherminio) +Eelco de Groot (KingDefender) Elvin Liu (solarlight2) erbsenzaehler Ernesto Gatti @@ -60,8 +65,9 @@ Jacques B. (Timshel) Jan Ondruš (hxim) Jared Kish (Kurtbusch) Jarrod Torriero (DU-jdto) -Jean Gauthier (QuaisBla) +Jean Gauthier (OuaisBla) Jean-Francois Romang (jromang) +Jekaa Jerry Donald Watson (jerrydonaldwatson) Jonathan Calovski (Mysseno) Jonathan Dumale (SFisGOD) @@ -70,7 +76,7 @@ Jörg Oster (joergoster) Joseph Ellis (jhellis3) Joseph R. Prostko jundery -Justin Blanchard +Justin Blanchard (UncombedCoconut) Kelly Wilson Ken Takusagawa kinderchocolate @@ -78,23 +84,26 @@ Kiran Panditrao (Krgp) Kojirion Leonardo Ljubičić (ICCF World Champion) Leonid Pechenik (lp--) -Linus Arver +Linus Arver (listx) loco-loco Lub van den Berg (ElbertoOne) Luca Brivio (lucabrivio) Lucas Braesch (lucasart) Lyudmil Antonov (lantonov) Maciej Żenczykowski (zenczykowski) -Matthew Lai (matthewlai) -Matthew Sullivan Mark Tenzer (31m059) +marotear +Matthew Lai (matthewlai) +Matthew Sullivan (Matt14916) +Michael An (man) Michael Byrne (MichaelB7) -Michael Stembera (mstembera) Michael Chaly (Vizvezdenec) +Michael Stembera (mstembera) +Michael Whiteley (protonspring) Michel Van den Bergh (vdbergh) Miguel Lahoz (miguel-l) Mikael Bäckman (mbootsector) -Michael Whiteley (protonspring) +Mira Miroslav Fontán (Hexik) Moez Jellouli (MJZ1977) Mohammed Li (tthsqe12) @@ -102,9 +111,11 @@ Nathan Rugg (nmrugg) Nick Pelling (nickpelling) Nicklas Persson (NicklasPersson) Niklas Fiekas (niklasf) +Nikolay Kostov (NikolayIT) Ondrej Mosnáček (WOnder93) Oskar Werkelin Ahlin Pablo Vazquez +Panthee Pascal Romaret Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) @@ -117,23 +128,28 @@ Reuven Peleg Richard Lloyd Rodrigo Exterckötter Tjäder Ron Britvich (Britvich) -Ronald de Man (syzygy1) +Ronald de Man (syzygy1, syzygy) Ryan Schmitt Ryan Takker +Sami Kiminki (skiminki) Sebastian Buchwald (UniQP) Sergei Antonov (saproj) +Sergei Ivanov (svivanov72) sf-x -shane31 -Steinar Gunderson (sesse) +Shane Booth (shane31) Stefan Geschwentner (locutus2) Stefano Cardanobile (Stefano80) +Steinar Gunderson (sesse) Stéphane Nicolet (snicolet) Thanar2 thaspel +theo77186 +Tom Truscott Tom Vijlbrief (tomtor) -Torsten Franz (torfranz) +Torsten Franz (torfranz, tfranzer) +Tracey Emery (basepr1me) Uri Blass (uriblass) -Vince Negri +Vince Negri (cuddlestmonkey) # Additionally, we acknowledge the authors of fishtest, # an essential framework for the development of Stockfish: diff --git a/Top CPU Contributors.txt b/Top CPU Contributors.txt index e882aa43..0ea5ac72 100644 --- a/Top CPU Contributors.txt +++ b/Top CPU Contributors.txt @@ -1,146 +1,154 @@ -Contributors with >10,000 CPU hours as of November 4, 2018 +Contributors with >10,000 CPU hours as of January 7, 2020 Thank you! -Username CPU Hours Games played -noobpwnftw 3730975 292309380 -mibere 535242 43333774 -crunchy 375564 29121434 -cw 371664 28748719 -fastgm 318178 22283584 -JojoM 295354 20958931 -dew 215476 17079219 -ctoks 214031 17312035 -glinscott 204517 13932027 -bking_US 187568 12233168 -velislav 168404 13336219 -CSU_Dynasty 168069 14417712 -Thanar 162373 13842179 -spams 149531 10940322 -Fisherman 141137 12099359 -drabel 134441 11180178 -leszek 133658 9812120 -marrco 133566 10115202 -sqrt2 128420 10022279 -vdbergh 123230 9200516 -tvijlbrief 123007 9498831 -vdv 120381 8555423 -malala 117291 8126488 -dsmith 114010 7622414 -BrunoBanani 104938 7448565 -CoffeeOne 100042 4593596 -Data 94621 8433010 -mgrabiak 92248 7787406 -bcross 89440 8506568 -brabos 81868 6647613 -BRAVONE 80811 5341681 -psk 77195 6156031 -nordlandia 74833 6231930 -robal 72818 5969856 -TueRens 72523 6383294 -sterni1971 71049 5647590 -sunu 65855 5360884 -mhoram 65034 5192880 -davar 64794 5457564 -nssy 64607 5371952 -Pking_cda 64499 5704075 -biffhero 63557 5480444 -teddybaer 62147 5585620 -solarlight 61278 5402642 -ElbertoOne 60156 5504304 -jromang 58854 4704502 -dv8silencer 57421 3961325 -tinker 56039 4204914 -Freja 50331 3808121 -renouve 50318 3544864 -robnjr 47504 4131742 -grandphish2 47377 4110003 -eva42 46857 4075716 -ttruscott 46802 3811534 -finfish 46244 3481661 -rap 46201 3219490 -ronaldjerum 45641 3964331 -xoto 44998 4170431 -gvreuls 44359 3902234 -bigpen0r 41780 3448224 -Bobo1239 40767 3657490 -Antihistamine 39218 2792761 -mhunt 38991 2697512 -racerschmacer 38929 3756111 -VoyagerOne 35896 3378887 -homyur 35561 3012398 -rkl 33217 2978536 -pb00067 33034 2803485 -speedycpu 32043 2531964 -SC 31954 2848432 -EthanOConnor 31638 2143255 -oryx 30962 2899534 -gri 30108 2429137 -csnodgrass 29396 2808611 -Garf 28887 2873564 -Pyafue 28885 1986098 -jkiiski 28014 1923255 -slakovv 27017 2031279 -Prcuvu 26300 2307154 -hyperbolic.tom 26248 2200777 -jbwiebe 25663 2129063 -anst 25525 2279159 -Patrick_G 24222 1835674 -nabildanial 23524 1586321 -achambord 23495 1942546 -Sharaf_DG 22975 1790697 -chriswk 22876 1947731 -ncfish1 22689 1830009 -cuistot 22201 1383031 -Zirie 21171 1493227 -Isidor 20634 1736219 -JanErik 20596 1791991 -xor12 20535 1819280 -team-oh 20364 1653708 -nesoneg 20264 1493435 -dex 20110 1682756 -rstoesser 19802 1335177 -Vizvezdenec 19750 1695579 -eastorwest 19531 1841839 -sg4032 18913 1720157 -horst.prack 18425 1708197 -cisco2015 18408 1793774 -ianh2105 18133 1668562 -MazeOfGalious 18022 1644593 -ville 17900 1539130 -j3corre 17607 975954 -eudhan 17502 1424648 -jmdana 17351 1287546 -iisiraider 17175 1118788 -jundery 17172 1115855 -wei 16852 1822582 -SFTUser 16635 1363975 -purplefishies 16621 1106850 -DragonLord 16599 1252348 -chris 15274 1575333 -IgorLeMasson 15201 1364148 -dju 15074 914278 -Flopzee 14700 1331632 -OssumOpossum 14149 1029265 -enedene 13762 935618 -ako027ako 13442 1250249 -AdrianSA 13324 924980 -bpfliegel 13318 886523 -Nikolay.IT 13260 1155612 -jpulman 12776 854815 -joster 12438 988413 -fatmurphy 12015 901134 -Nesa92 11711 1132245 -Adrian.Schmidt123 11542 898699 -modolief 11228 926456 -Dark_wizzie 11214 1017910 -mschmidt 10973 818594 -Andrew Grant 10780 947859 -infinity 10762 746397 -SapphireBrand 10692 1024604 -Thomas A. Anderson 10553 736094 -basepi 10434 935168 -lantonov 10325 972610 -pgontarz 10294 878746 -Spprtr 10189 823246 -crocogoat 10115 1017325 -stocky 10083 718114 \ No newline at end of file +Username CPU Hours Games played +-------------------------------------------------- +noobpwnftw 9305707 695548021 +mlang 780050 61648867 +dew 621626 43921547 +mibere 524702 42238645 +crunchy 354587 27344275 +cw 354495 27274181 +fastgm 332801 22804359 +JojoM 295750 20437451 +CSU_Dynasty 262015 21828122 +Fisherman 232181 18939229 +ctoks 218866 17622052 +glinscott 201989 13780820 +tvijlbrief 201204 15337115 +velislav 188630 14348485 +gvreuls 187164 15149976 +bking_US 180289 11876016 +nordlandia 172076 13467830 +leszek 157152 11443978 +Thanar 148021 12365359 +spams 141975 10319326 +drabel 138073 11121749 +vdv 137850 9394330 +mgrabiak 133578 10454324 +TueRens 132485 10878471 +bcross 129683 11557084 +marrco 126078 9356740 +sqrt2 125830 9724586 +robal 122873 9593418 +vdbergh 120766 8926915 +malala 115926 8002293 +CoffeeOne 114241 5004100 +dsmith 113189 7570238 +BrunoBanani 104644 7436849 +Data 92328 8220352 +mhoram 89333 6695109 +davar 87924 7009424 +xoto 81094 6869316 +ElbertoOne 80899 7023771 +grandphish2 78067 6160199 +brabos 77212 6186135 +psk 75733 5984901 +BRAVONE 73875 5054681 +sunu 70771 5597972 +sterni1971 70605 5590573 +MaZePallas 66886 5188978 +Vizvezdenec 63708 4967313 +nssy 63462 5259388 +jromang 61634 4940891 +teddybaer 61231 5407666 +Pking_cda 60099 5293873 +solarlight 57469 5028306 +dv8silencer 56913 3883992 +tinker 54936 4086118 +renouve 49732 3501516 +Freja 49543 3733019 +robnjr 46972 4053117 +rap 46563 3219146 +Bobo1239 46036 3817196 +ttruscott 45304 3649765 +racerschmacer 44881 3975413 +finfish 44764 3370515 +eva42 41783 3599691 +biffhero 40263 3111352 +bigpen0r 39817 3291647 +mhunt 38871 2691355 +ronaldjerum 38820 3240695 +Antihistamine 38785 2761312 +pb00067 38038 3086320 +speedycpu 37591 3003273 +rkl 37207 3289580 +VoyagerOne 37050 3441673 +jbwiebe 35320 2805433 +cuistot 34191 2146279 +homyur 33927 2850481 +manap 32873 2327384 +gri 32538 2515779 +oryx 31267 2899051 +EthanOConnor 30959 2090311 +SC 30832 2730764 +csnodgrass 29505 2688994 +jmdana 29458 2205261 +strelock 28219 2067805 +jkiiski 27832 1904470 +Pyafue 27533 1902349 +Garf 27515 2747562 +eastorwest 27421 2317535 +slakovv 26903 2021889 +Prcuvu 24835 2170122 +anst 24714 2190091 +hyperbolic.tom 24319 2017394 +Patrick_G 23687 1801617 +Sharaf_DG 22896 1786697 +nabildanial 22195 1519409 +chriswk 21931 1868317 +achambord 21665 1767323 +Zirie 20887 1472937 +team-oh 20217 1636708 +Isidor 20096 1680691 +ncfish1 19931 1520927 +nesoneg 19875 1463031 +Spprtr 19853 1548165 +JanErik 19849 1703875 +agg177 19478 1395014 +SFTUser 19231 1567999 +xor12 19017 1680165 +sg4032 18431 1641865 +rstoesser 18118 1293588 +MazeOfGalious 17917 1629593 +j3corre 17743 941444 +cisco2015 17725 1690126 +ianh2105 17706 1632562 +dex 17678 1467203 +jundery 17194 1115855 +iisiraider 17019 1101015 +horst.prack 17012 1465656 +Adrian.Schmidt123 16563 1281436 +purplefishies 16342 1092533 +wei 16274 1745989 +ville 16144 1384026 +eudhan 15712 1283717 +OuaisBla 15581 972000 +DragonLord 15559 1162790 +dju 14716 875569 +chris 14479 1487385 +0xB00B1ES 14079 1001120 +OssumOpossum 13776 1007129 +enedene 13460 905279 +bpfliegel 13346 884523 +Ente 13198 1156722 +IgorLeMasson 13087 1147232 +jpulman 13000 870599 +ako027ako 12775 1173203 +Nikolay.IT 12352 1068349 +Andrew Grant 12327 895539 +joster 12008 950160 +AdrianSA 11996 804972 +Nesa92 11455 1111993 +fatmurphy 11345 853210 +Dark_wizzie 11108 1007152 +modolief 10869 896470 +mschmidt 10757 803401 +infinity 10594 727027 +mabichito 10524 749391 +Thomas A. Anderson 10474 732094 +thijsk 10431 719357 +Flopzee 10339 894821 +crocogoat 10104 1013854 +SapphireBrand 10104 969604 +stocky 10017 699440 diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 58f05e66..f906e731 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 9301dcfa..78614fa2 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 2afd3766..45d51504 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/bitboard.h b/src/bitboard.h index 8d748eee..440de1ea 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/endgame.cpp b/src/endgame.cpp index ca38a662..276b942e 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/endgame.h b/src/endgame.h index e29f8777..4642e448 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 27fcd477..3a4adef3 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/evaluate.h b/src/evaluate.h index cccdd25d..077de70c 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/main.cpp b/src/main.cpp index 40081e8d..148bf248 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/material.cpp b/src/material.cpp index 11d4c687..0e130878 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/material.h b/src/material.h index b472c3fd..9ab1d81c 100644 --- a/src/material.h +++ b/src/material.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/misc.cpp b/src/misc.cpp index 6f908fd2..2a5bc603 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/misc.h b/src/misc.h index ddd05e4e..b1385c2f 100644 --- a/src/misc.h +++ b/src/misc.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/movegen.cpp b/src/movegen.cpp index 0b91582e..8f6edffb 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/movegen.h b/src/movegen.h index aeba93ad..c2e7c3f1 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/movepick.cpp b/src/movepick.cpp index e39f2afa..025f5b82 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/movepick.h b/src/movepick.h index 105c95d7..cdedc9b6 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/pawns.cpp b/src/pawns.cpp index 04222a2a..c3f7872f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/pawns.h b/src/pawns.h index 4c041716..bd17618f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/position.cpp b/src/position.cpp index 9644e02c..7c226dee 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/position.h b/src/position.h index 2ec2729c..783bb4a3 100644 --- a/src/position.h +++ b/src/position.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/psqt.cpp b/src/psqt.cpp index c11dc5ba..647bd864 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/search.cpp b/src/search.cpp index 25a7cf44..f357db5e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/search.h b/src/search.h index c77ca3ad..a900d094 100644 --- a/src/search.h +++ b/src/search.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index c0453492..99f1834b 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (c) 2013 Ronald de Man - Copyright (C) 2016-2019 Marco Costalba, Lucas Braesch + Copyright (C) 2016-2020 Marco Costalba, Lucas Braesch Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/syzygy/tbprobe.h b/src/syzygy/tbprobe.h index 264f6e84..df3ca4fe 100644 --- a/src/syzygy/tbprobe.h +++ b/src/syzygy/tbprobe.h @@ -1,7 +1,7 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (c) 2013 Ronald de Man - Copyright (C) 2016-2019 Marco Costalba, Lucas Braesch + Copyright (C) 2016-2020 Marco Costalba, Lucas Braesch Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread.cpp b/src/thread.cpp index 6eb00d63..f55bcb22 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/thread.h b/src/thread.h index a1545072..4de30edb 100644 --- a/src/thread.h +++ b/src/thread.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index f8cb466b..0ef5c981 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/timeman.cpp b/src/timeman.cpp index 484aaa65..0848be42 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/timeman.h b/src/timeman.h index 41befff0..9301dc94 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/tt.cpp b/src/tt.cpp index d3cd094e..0b4a59de 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/tt.h b/src/tt.h index d087cc38..98b054d3 100644 --- a/src/tt.h +++ b/src/tt.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/types.h b/src/types.h index 13c3bbf2..902c2cfc 100644 --- a/src/types.h +++ b/src/types.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/uci.cpp b/src/uci.cpp index 6f0bdd76..9c84ade3 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/uci.h b/src/uci.h index 31b63e2f..b845889b 100644 --- a/src/uci.h +++ b/src/uci.h @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 23c0c480..26fcf302 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -2,7 +2,7 @@ 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-2019 Marco Costalba, Joona Kiiski, Gary Linscott, 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 From bae019b53e5c2bfcf0d69b4ebfc52b4f4de762eb Mon Sep 17 00:00:00 2001 From: joergoster Date: Thu, 12 Dec 2019 12:53:47 +0100 Subject: [PATCH 48/59] 50-moves rule improvement for transposition table User "adentong" reported recently of a game where Stockfish blundered a game in a tournament because during a search there was an hash-table issue for positions inside the tree very close to the 50-moves draw rule. This is part of a problem which is commonly referred to as the Graph History Interaction (GHI), and is difficult to solve in computer chess because storing the 50-moves counter in the hash-table loses Elo in general. Links: Issue 2451 : https://github.com/official-stockfish/Stockfish/issues/2451 About the GHI : https://www.chessprogramming.org/Graph_History_Interaction This patch tries to address the issue in this particular game and similar reported games: it prevents that values from the transposition table are getting used when the 50-move counter is close to reaching 100 (). The idea is that in such cases values from previous searches, with a much lower 50-move count, become less and less reliable. More precisely, the heuristic we use in this patch is that we don't take the transposition table cutoff when we have reached a 45-moves limit, but let the search continue doing its job. There is a possible slowdown involved, but it will also help to find either a draw when it thought to be losing, or a way to avoid the draw by 50-move rule. This heuristics probably will not fix all possible cases, but seems to be working reasonably well in practice while not losing too much Elo. Passed non-regression tests: STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 274452 W: 59700 L: 60075 D: 154677 http://tests.stockfishchess.org/tests/view/5df546116932658fe9b451bf LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 95235 W: 15297 L: 15292 D: 64646 http://tests.stockfishchess.org/tests/view/5df69c926932658fe9b4520e Closes https://github.com/official-stockfish/Stockfish/pull/2453 Bench: 4586187 --- src/search.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f357db5e..dfc0e5bf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -716,7 +716,9 @@ namespace { update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } } - return ttValue; + + if (pos.rule50_count() < 90) + return ttValue; } // Step 5. Tablebases probe From 384bff4264f199ded8fa28d241ce0e7dc021a97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 9 Jan 2020 20:49:13 +0100 Subject: [PATCH 49/59] Assorted trivial cleanups January 2020 Assorted trivial cleanups. No functional change --- src/endgame.cpp | 4 ++-- src/evaluate.cpp | 25 ++++++++++++------------- src/position.cpp | 34 +++++++++++++++++----------------- src/position.h | 6 +++++- src/syzygy/tbprobe.cpp | 4 ++-- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 276b942e..2ed6ebc2 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -155,7 +155,7 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.square(weakSide); Square bishopSq = pos.square(strongSide); - // If our Bishop does not attack A1/H8, we flip the enemy king square + // 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 @@ -167,7 +167,7 @@ Value Endgame::operator()(const Position& pos) const { } -/// KP vs K. This endgame is evaluated with the help of a bitbase. +/// KP vs K. This endgame is evaluated with the help of a bitbase template<> Value Endgame::operator()(const Position& pos) const { diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3a4adef3..7c7ce95c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -317,20 +317,19 @@ namespace { // 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; - } - // An important Chess960 pattern: A cornered bishop blocked by a friendly - // pawn diagonally in front of it is a very serious problem, especially - // when that pawn is also blocked. - if ( Pt == BISHOP - && pos.is_chess960() - && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) - { - Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); - if (pos.piece_on(s + d) == make_piece(Us, PAWN)) - score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 - : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 - : CorneredBishop; + // An important Chess960 pattern: a cornered bishop blocked by a friendly + // pawn diagonally in front of it is a very serious problem, especially + // when that pawn is also blocked. + if ( pos.is_chess960() + && (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1))) + { + Direction d = pawn_push(Us) + (file_of(s) == FILE_A ? EAST : WEST); + if (pos.piece_on(s + d) == make_piece(Us, PAWN)) + score -= !pos.empty(s + d + pawn_push(Us)) ? CorneredBishop * 4 + : pos.piece_on(s + d + d) == make_piece(Us, PAWN) ? CorneredBishop * 2 + : CorneredBishop; + } } } diff --git a/src/position.cpp b/src/position.cpp index 7c226dee..53d9b64e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -817,7 +817,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { st->nonPawnMaterial[us] += PieceValue[MG][promotion]; } - // Update pawn hash key and prefetch access to pawnsTable + // Update pawn hash key st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; // Reset rule 50 draw counter @@ -944,7 +944,7 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ } -/// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips +/// Position::do(undo)_null_move() is used to do(undo) a "null move": it flips /// the side to move without executing any move on the board. void Position::do_null_move(StateInfo& newSt) { @@ -1027,16 +1027,16 @@ bool Position::see_ge(Move m, Value threshold) const { if (swap <= 0) return true; - Bitboard occ = pieces() ^ from ^ to; + Bitboard occupied = pieces() ^ from ^ to; Color stm = color_of(piece_on(from)); - Bitboard attackers = attackers_to(to, occ); + Bitboard attackers = attackers_to(to, occupied); Bitboard stmAttackers, bb; int res = 1; while (true) { stm = ~stm; - attackers &= occ; + attackers &= occupied; // If stm has no more attackers then give up: stm loses if (!(stmAttackers = attackers & pieces(stm))) @@ -1044,7 +1044,7 @@ bool Position::see_ge(Move m, Value threshold) const { // Don't allow pinned pieces to attack (except the king) as long as // there are pinners on their original square. - if (st->pinners[~stm] & occ) + if (st->pinners[~stm] & occupied) stmAttackers &= ~st->blockersForKing[stm]; if (!stmAttackers) @@ -1059,8 +1059,8 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = PawnValueMg - swap) < res) break; - occ ^= lsb(bb); - attackers |= attacks_bb(to, occ) & pieces(BISHOP, QUEEN); + occupied ^= lsb(bb); + attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(KNIGHT))) @@ -1068,7 +1068,7 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = KnightValueMg - swap) < res) break; - occ ^= lsb(bb); + occupied ^= lsb(bb); } else if ((bb = stmAttackers & pieces(BISHOP))) @@ -1076,8 +1076,8 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = BishopValueMg - swap) < res) break; - occ ^= lsb(bb); - attackers |= attacks_bb(to, occ) & pieces(BISHOP, QUEEN); + occupied ^= lsb(bb); + attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(ROOK))) @@ -1085,8 +1085,8 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = RookValueMg - swap) < res) break; - occ ^= lsb(bb); - attackers |= attacks_bb(to, occ) & pieces(ROOK, QUEEN); + occupied ^= lsb(bb); + attackers |= attacks_bb(to, occupied) & pieces(ROOK, QUEEN); } else if ((bb = stmAttackers & pieces(QUEEN))) @@ -1094,9 +1094,9 @@ bool Position::see_ge(Move m, Value threshold) const { if ((swap = QueenValueMg - swap) < res) break; - occ ^= lsb(bb); - attackers |= (attacks_bb(to, occ) & pieces(BISHOP, QUEEN)) - | (attacks_bb(to, occ) & pieces(ROOK , QUEEN)); + occupied ^= lsb(bb); + attackers |= (attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)) + | (attacks_bb(to, occupied) & pieces(ROOK , QUEEN)); } else // KING @@ -1105,7 +1105,7 @@ bool Position::see_ge(Move m, Value threshold) const { return (attackers & ~pieces(stm)) ? res ^ 1 : res; } - return res; + return bool(res); } /// Position::is_draw() tests whether the position is drawn by 50-move rule diff --git a/src/position.h b/src/position.h index 783bb4a3..6791455f 100644 --- a/src/position.h +++ b/src/position.h @@ -46,7 +46,6 @@ struct StateInfo { Square epSquare; // Not copied when making a move (will be recomputed anyhow) - int repetition; Key key; Bitboard checkersBB; Piece capturedPiece; @@ -54,6 +53,7 @@ struct StateInfo { Bitboard blockersForKing[COLOR_NB]; Bitboard pinners[COLOR_NB]; Bitboard checkSquares[PIECE_TYPE_NB]; + int repetition; }; /// A list to keep track of the position states along the setup moves (from the @@ -277,10 +277,14 @@ 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]; } inline Square Position::castling_rook_square(CastlingRights cr) const { + assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); + return castlingRookSquare[cr]; } diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 99f1834b..721a0ef5 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -683,7 +683,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu bool blackStronger = (pos.material_key() != entry->key); int flipColor = (symmetricBlackToMove || blackStronger) * 8; - int flipSquares = (symmetricBlackToMove || blackStronger) * 070; + int flipSquares = (symmetricBlackToMove || blackStronger) * 56; int stm = (symmetricBlackToMove || blackStronger) ^ pos.side_to_move(); // For pawns, TB files store 4 separate tables according if leading pawn is on @@ -762,7 +762,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] ^= 070; // Vertical flip: SQ_A8 -> SQ_A1 + squares[i] ^= SQ_A8; // Vertical flip: SQ_A8 -> SQ_A1 // Look for the first piece of the leading group not on the A1-D4 diagonal // and ensure it is mapped below the diagonal. From 7f623206f413b96170d432b401fe3c647325d01a Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 3 Jan 2020 11:33:18 -0700 Subject: [PATCH 50/59] Rewrite initialization of PseudoMoves This is a non-functional code style change. I believe master is a bit convoluted here and propose this version for clarity. No functional change --- src/bitboard.cpp | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 45d51504..70114f20 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -76,25 +76,29 @@ void Bitboards::init() { for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) - SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); + SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); - int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } }; + 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)); + } - for (Color c : { WHITE, BLACK }) - for (PieceType pt : { PAWN, KNIGHT, KING }) - for (Square s = SQ_A1; s <= SQ_H8; ++s) - for (int i = 0; steps[pt][i]; ++i) - { - Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]); + // 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); + }; - if (is_ok(to) && distance(s, to) < 3) - { - if (pt == PAWN) - PawnAttacks[c][s] |= to; - else - PseudoAttacks[pt][s] |= to; - } - } + 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 }; From 114ddb789bed2d74d6a786f5da6c9ce63d44de27 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 10 Jan 2020 03:02:09 +0100 Subject: [PATCH 51/59] Update Elo estimates for terms in search This updates estimates from 1.5 year ago, and adds missing terms. All estimates from tests run on fishtest at 10+0.1 (STC), 20000 games, error bars +- 3 Elo, see the original message in the pull request for the full list of tests. Noteworthy changes are step 7 (futility pruning) going from ~30 to ~50 Elo and step 13 (pruning at shallow depth) going from ~170 to ~200 Elo. Full list of tests: https://github.com/official-stockfish/Stockfish/pull/2401 @Rocky640 made the suggestion to look at time control dependence of these terms. I picked two large terms (early futility pruning and singular extension), so with small relative error. It turns out it is actually quite interesting (see figure 1). Contrary to my expectation, the Elo gain for early futility pruning is pretty time control sensitive, while singular extension gain is not. Figure 1: TC dependence of two search terms ![elo_search_tc]( http://cassio.free.fr/divers/elo_search_tc.png ) Going back to the old measurement of futility pruning (30 Elo vs today 50 Elo), the code is actually identical but the margins have changed. It seems like a nice example of how connected terms in search really are, i.e. the value of early futility pruning increased significantly due to changes elsewhere in search. No functional change. --- src/search.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index dfc0e5bf..6146bdf6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -808,7 +808,7 @@ namespace { tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - // Step 7. Razoring (~2 Elo) + // Step 7. Razoring (~1 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch && depth < 2 && eval <= alpha - RazorMargin) @@ -817,7 +817,7 @@ namespace { 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 (~30 Elo) + // Step 8. Futility pruning: child node (~50 Elo) if ( !PvNode && depth < 6 && eval - futility_margin(depth, improving) >= beta @@ -917,7 +917,7 @@ namespace { } } - // Step 11. Internal iterative deepening (~2 Elo) + // Step 11. Internal iterative deepening (~1 Elo) if (depth >= 7 && !ttMove) { search(pos, ss, alpha, beta, depth - 7, cutNode); @@ -982,7 +982,7 @@ moves_loop: // When in check, search starts from here // Calculate new depth for this move newDepth = depth - 1; - // Step 13. Pruning at shallow depth (~170 Elo) + // Step 13. Pruning at shallow depth (~200 Elo) if ( !rootNode && pos.non_pawn_material(us) && bestValue > VALUE_MATED_IN_MAX_PLY) @@ -1002,7 +1002,7 @@ moves_loop: // When in check, search starts from here && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) continue; - // Futility pruning: parent node (~2 Elo) + // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 && !inCheck && ss->staticEval + 255 + 182 * lmrDepth <= alpha @@ -1012,17 +1012,17 @@ moves_loop: // When in check, search starts from here + (*contHist[3])[movedPiece][to_sq(move)] < 30000) continue; - // Prune moves with negative SEE (~10 Elo) + // Prune moves with negative SEE (~20 Elo) if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, Value(-194) * depth)) // (~20 Elo) + else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) continue; } - // Step 14. Extensions (~70 Elo) + // Step 14. Extensions (~75 Elo) - // Singular extension search (~60 Elo). If all moves but one fail low on a + // Singular extension search (~70 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), // then that move is singular and should be extended. To verify this we do // a reduced search on all the other moves but the ttMove and if the @@ -1101,7 +1101,7 @@ moves_loop: // When in check, search starts from here // Step 15. Make the move pos.do_move(move, st, givesCheck); - // Step 16. Reduced depth search (LMR). If the move fails high it will be + // 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 + 2 * rootNode @@ -1122,31 +1122,31 @@ moves_loop: // When in check, search starts from here if (th.marked()) r++; - // Decrease reduction if position is or has been on the PV + // Decrease reduction if position is or has been on the PV (~10 Elo) if (ttPv) r -= 2; - // Decrease reduction if opponent's move count is high (~10 Elo) + // 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 + // Decrease reduction if ttMove has been singularly extended (~3 Elo) if (singularLMR) r -= 2; if (!captureOrPromotion) { - // Increase reduction if ttMove is a capture (~0 Elo) + // Increase reduction if ttMove is a capture (~5 Elo) if (ttCapture) r++; - // Increase reduction for cut nodes (~5 Elo) + // Increase reduction for cut nodes (~10 Elo) if (cutNode) r += 2; // Decrease reduction for moves that escape a capture. Filter out // castling moves, because they are coded as "king captures rook" and - // hence break make_move(). (~5 Elo) + // hence break make_move(). (~2 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) r -= 2; From 9f800a25775ddb5335a20eac92d8d288ca74f4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 24 Sep 2019 19:00:27 +0200 Subject: [PATCH 52/59] Show compiler info at startup This patch shows a description of the compiler used to compile Stockfish, when starting from the console. Usage: ``` ./stockfish compiler ``` Example of output: ``` Stockfish 120120 64 POPCNT by T. Romstad, M. Costalba, J. Kiiski, G. Linscott Compiled by clang++ 9.0.0 on Apple __VERSION__ macro expands to: 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.38) ``` No functional change --- src/misc.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/misc.h | 1 + src/uci.cpp | 9 ++++--- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 2a5bc603..053ee67e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -151,6 +151,77 @@ const string engine_info(bool to_uci) { } +/// compiler_info() returns a string trying to describe the compiler we use + +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) + +/// Predefined macros hell: +/// +/// __GNUC__ Compiler is gcc, Clang or Intel on Linux +/// __INTEL_COMPILER Compiler is Intel +/// _MSC_VER Compiler is MSVC or Intel on Windows +/// _WIN32 Building on Windows (any) +/// _WIN64 Building on Windows 64 bit + + std::string compiler = "\nCompiled by "; + + #ifdef __clang__ + compiler += "clang++ "; + compiler += VER_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 += ")"; + #elif _MSC_VER + compiler += "MSVC "; + compiler += "(version "; + compiler += STRINGIFY(_MSC_FULL_VER) "." STRINGIFY(_MSC_BUILD); + compiler += ")"; + #elif __GNUC__ + compiler += "g++ (GNUC) "; + compiler += VER_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); + #else + compiler += "Unknown compiler "; + compiler += "(unknown version)"; + #endif + + #if defined(__APPLE__) + compiler += " on Apple"; + #elif defined(__CYGWIN__) + compiler += " on Cygwin"; + #elif defined(__MINGW64__) + compiler += " on MinGW64"; + #elif defined(__MINGW32__) + compiler += " on MinGW32"; + #elif defined(__ANDROID__) + compiler += " on Android"; + #elif defined(__linux__) + compiler += " on Linux"; + #elif defined(_WIN64) + compiler += " on Microsoft Windows 64-bit"; + #elif defined(_WIN32) + compiler += " on Microsoft Windows 32-bit"; + #else + compiler += " on unknown system"; + #endif + + compiler += "\n __VERSION__ macro expands to: "; + #ifdef __VERSION__ + compiler += __VERSION__; + #else + compiler += "(undefined macro)"; + #endif + compiler += "\n"; + + return compiler; +} + + /// Debug functions used mainly to collect run-time statistics static std::atomic hits[2], means[2]; diff --git a/src/misc.h b/src/misc.h index b1385c2f..b11c5aa8 100644 --- a/src/misc.h +++ b/src/misc.h @@ -30,6 +30,7 @@ #include "types.h" 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); diff --git a/src/uci.cpp b/src/uci.cpp index 9c84ade3..8b35e6fd 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -235,10 +235,11 @@ void UCI::loop(int argc, char* argv[]) { // Additional custom non-UCI commands, mainly for debugging. // Do not use these commands during a search! - else if (token == "flip") pos.flip(); - else if (token == "bench") bench(pos, is, states); - else if (token == "d") sync_cout << pos << sync_endl; - else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; + else if (token == "flip") pos.flip(); + else if (token == "bench") bench(pos, is, states); + else if (token == "d") sync_cout << pos << sync_endl; + else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; + else if (token == "compiler") sync_cout << compiler_info() << sync_endl; else sync_cout << "Unknown command: " << cmd << sync_endl; From 69204f0720bba198952fb7a848ed4377430ef433 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sat, 11 Jan 2020 22:10:22 +0000 Subject: [PATCH 53/59] Smarter time management near stop limit This patch makes Stockfish search same depth again if > 60% of optimum time is already used, instead of trying the next iteration. The idea is that the next iteration will generally take about the same amount of time as has already been used in total. When we are likely to begin the last iteration, as judged by total time taken so far > 0.6 * optimum time, searching the last depth again instead of increasing the depth still helps the other threads in lazy SMP and prepares better move ordering for the next moves. STC : LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 13436 W: 2695 L: 2558 D: 8183 Ptnml(0-2): 222, 1538, 3087, 1611, 253 https://tests.stockfishchess.org/tests/view/5e1618a761fe5f83a67dd964 LTC : LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 32160 W: 4261 L: 4047 D: 23852 Ptnml(0-2): 211, 2988, 9448, 3135, 247 https://tests.stockfishchess.org/tests/view/5e162ca061fe5f83a67dd96d The code was revised as suggested by @vondele for multithreading: STC (8 threads): LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 16640 W: 2049 L: 1885 D: 12706 Ptnml(0-2): 119, 1369, 5158, 1557, 108 https://tests.stockfishchess.org/tests/view/5e19826a2cc590e03c3c2f52 LTC (8 threads): LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 16536 W: 2758 L: 2629 D: 11149 Ptnml(0-2): 182, 1758, 4296, 1802, 224 https://tests.stockfishchess.org/tests/view/5e18b91a27dab692fcf9a140 Thanks to those discussing Stockfish lazy SMP on fishcooking which made me try this, and to @vondele for suggestions and doing related tests. See full discussion in the pull request thread: https://github.com/official-stockfish/Stockfish/pull/2482 Bench: 4586187 --- AUTHORS | 11 +++++++++-- src/search.cpp | 12 +++++++++++- src/thread.cpp | 1 + src/thread.h | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4638b41a..33a7a3d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -91,6 +91,7 @@ Luca Brivio (lucabrivio) Lucas Braesch (lucasart) Lyudmil Antonov (lantonov) Maciej Żenczykowski (zenczykowski) +Malcolm Campbell (xoto10) Mark Tenzer (31m059) marotear Matthew Lai (matthewlai) @@ -151,6 +152,12 @@ Tracey Emery (basepr1me) Uri Blass (uriblass) Vince Negri (cuddlestmonkey) -# Additionally, we acknowledge the authors of fishtest, -# an essential framework for the development of Stockfish: + +# Additionally, we acknowledge the authors and maintainer of fishtest, +# 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 6146bdf6..ec9c6b1d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -393,6 +393,8 @@ void Thread::search() { contempt = (us == WHITE ? make_score(ct, ct / 2) : -make_score(ct, ct / 2)); + int searchAgainCounter = 0; + // Iterative deepening loop until requested to stop or the target depth is reached while ( ++rootDepth < MAX_PLY && !Threads.stop @@ -410,6 +412,9 @@ void Thread::search() { size_t pvFirst = 0; pvLast = 0; + if (!Threads.increaseDepth) + searchAgainCounter++; + // MultiPV loop. We perform a full root search for each PV line for (pvIdx = 0; pvIdx < multiPV && !Threads.stop; ++pvIdx) { @@ -445,7 +450,7 @@ void Thread::search() { int failedHighCnt = 0; while (true) { - Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt); + Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter); bestValue = ::search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting @@ -558,6 +563,11 @@ void Thread::search() { else Threads.stop = true; } + else if ( Threads.increaseDepth + && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6) + Threads.increaseDepth = false; + else + Threads.increaseDepth = true; } mainThread->iterValue[iterIdx] = bestValue; diff --git a/src/thread.cpp b/src/thread.cpp index f55bcb22..615d482c 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -179,6 +179,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, main()->wait_for_search_finished(); main()->stopOnPonderhit = stop = false; + increaseDepth = true; main()->ponder = ponderMode; Search::Limits = limits; Search::RootMoves rootMoves; diff --git a/src/thread.h b/src/thread.h index 4de30edb..aea86fd5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -109,7 +109,7 @@ struct ThreadPool : public std::vector { uint64_t nodes_searched() const { return accumulate(&Thread::nodes); } uint64_t tb_hits() const { return accumulate(&Thread::tbHits); } - std::atomic_bool stop; + std::atomic_bool stop, increaseDepth; private: StateListPtr setupStates; From 01dfdb95dcc92fec97e49c857c96841f16553af2 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Mon, 13 Jan 2020 09:05:49 +0000 Subject: [PATCH 54/59] Fix previous patch in case of ponder No functional change --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index ec9c6b1d..7804119f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -564,6 +564,7 @@ void Thread::search() { Threads.stop = true; } else if ( Threads.increaseDepth + && !mainThread->ponder && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6) Threads.increaseDepth = false; else From 4901218d4cc31658942486ccd1dbadf2d2df783a Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 13 Jan 2020 02:59:06 +0300 Subject: [PATCH 55/59] Tweak futility pruning constants Based on recent improvement of futility pruning by @locutus2 : we lower the futility margin to apply it for more nodes but as a compensation we also lower the history threshold to apply it to less nodes. Further work in tweaking constants can always be done - numbers are guessed "by hand" and are not results of some tuning, maybe there is some more Elo to squeeze from this part of code. Passed STC LLR: 2.98 (-2.94,2.94) {-1.00,3.00} Total: 15300 W: 3081 L: 2936 D: 9283 Ptnml(0-2): 260, 1816, 3382, 1900, 290 http://tests.stockfishchess.org/tests/view/5e18da3b27dab692fcf9a158 Passed LTC LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 108670 W: 14509 L: 14070 D: 80091 Ptnml(0-2): 813, 10259, 31736, 10665, 831 http://tests.stockfishchess.org/tests/view/5e18fc9627dab692fcf9a180 Bench: 4643972 --- AUTHORS | 2 +- src/search.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 33a7a3d5..a9f141f9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -153,7 +153,7 @@ Uri Blass (uriblass) Vince Negri (cuddlestmonkey) -# Additionally, we acknowledge the authors and maintainer of fishtest, +# Additionally, we acknowledge the authors and maintainers of fishtest, # 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 7804119f..035dd40a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1016,11 +1016,11 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 && !inCheck - && ss->staticEval + 255 + 182 * lmrDepth <= alpha + && ss->staticEval + 235 + 172 * lmrDepth <= alpha && thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < 30000) + + (*contHist[3])[movedPiece][to_sq(move)] < 25000) continue; // Prune moves with negative SEE (~20 Elo) From 7150183d07a40653aff6ba64a73f27fe049f525d Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Mon, 13 Jan 2020 11:19:03 +0100 Subject: [PATCH 56/59] Tweak reductions for captures/promotions From the third move reduce captures and promotions more if remaining depth is low. STC: LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 25218 W: 5008 L: 4837 D: 15373 Ptnml(0-2): 439, 2950, 5717, 3001, 499 http://tests.stockfishchess.org/tests/view/5e1b33abd12216a2857e6359 LTC: LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 35491 W: 4760 L: 4524 D: 26207 Ptnml(0-2): 264, 3288, 10413, 3460, 294 http://tests.stockfishchess.org/tests/view/5e1b88d5d12216a2857e6385 Closes https://github.com/official-stockfish/Stockfish/pull/2488 Bench: 4979757 --- src/search.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 035dd40a..c1ed1f95 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1186,6 +1186,10 @@ moves_loop: // When in check, search starts from here r -= ss->statScore / 16384; } + // Increase reduction for captures/promotions if late move and at low depth + else if (depth < 8 && moveCount > 2) + r++; + Depth d = clamp(newDepth - r, 1, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); From baf184e8d9e22c86407538ab4b4004f58e0e996d Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 13 Jan 2020 15:46:40 +0100 Subject: [PATCH 57/59] Tweak late move reductions at root More LMR at root, unless a fail low might happen. passed STC: LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 25428 W: 4960 L: 4789 D: 15679 Ptnml(0-2): 424, 2948, 5832, 3045, 460 http://tests.stockfishchess.org/tests/view/5e1c9afed12216a2857e6401 passed LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 187423 W: 24253 L: 23599 D: 139571 Ptnml(0-2): 1284, 17437, 55536, 18085, 1292 http://tests.stockfishchess.org/tests/view/5e1ceb9975be933c8fe635a3 Closes https://github.com/official-stockfish/Stockfish/pull/2493 Bench: 5156767 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index c1ed1f95..0eea4127 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 + 2 * rootNode + && moveCount > 1 + rootNode + (rootNode && bestValue < alpha) && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion || moveCountPruning From 446a3c2522af66401181f2716e12eb35ca75d8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 15 Jan 2020 22:21:15 +0100 Subject: [PATCH 58/59] Update Readme.md for the compiler command No functional change --- Readme.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Readme.md b/Readme.md index 5b807ee6..a759eff6 100644 --- a/Readme.md +++ b/Readme.md @@ -153,6 +153,14 @@ 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 +be found by typing the following commands in a console: + +``` + ./stockfish + compiler +``` ## Understanding the code base and participating in the project From c3483fa9a7d7c0ffa9fcc32b467ca844cfb63790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 15 Jan 2020 22:39:27 +0100 Subject: [PATCH 59/59] Stockfish 11 Official release version of Stockfish 11. Bench: 5156767 ----------------------- It is our pleasure to release Stockfish 11 to our fans and supporters. Downloads are freely available at http://stockfishchess.org/download/ This version 11 of Stockfish is 50 Elo stronger than the last version, and 150 Elo stronger than the version which famously lost a match to AlphaZero two years ago. This makes Stockfish the strongest chess engine running on your smartphone or normal desktop PC, and we estimate that on a modern four cores CPU, Stockfish 11 could give 1:1000 time odds to the human chess champion having classical time control, and be on par with him. More specific data, including nice cumulative curves for the progression of Stockfish strength over the last seven years, can be found on [our progression page][1], at [Stefan Pohl site][2] or at [NextChessMove][3]. In October 2019 Stockfish has regained its crown in the TCEC competition, beating in the superfinal of season 16 an evolution of the neural-network engine Leela that had won the previous season. This clash of style between an alpha-beta and an neural-network engine produced spectacular chess as always, with Stockfish [emerging victorious this time][0]. Compared to Stockfish 10, we have made hundreds of improvements to the [codebase][4], from the evaluation function (improvements in king attacks, middlegame/endgame transitions, and many more) to the search algorithm (some innovative coordination methods for the searching threads, better pruning of unsound tactical lines, etc), and fixed a couple of bugs en passant. Our testing framework [Fishtest][5] has also seen its share of improvements to continue propelling Stockfish forward. Along with a lot of small enhancements, Fishtest has switched to new SPRT bounds to increase the chance of catching Elo gainers, along with a new testing book and the use of pentanomial statistics to be more resource-efficient. Overall the Stockfish project is an example of open-source at its best, as its buzzing community of programmers sharing ideas and daily reviewing their colleagues' patches proves to be an ideal form to develop innovative ideas for chess programming, while the mathematical accuracy of the testing framework allows us an unparalleled level of quality control for each patch we put in the engine. If you wish, you too can help our ongoing efforts to keep improving it, just [get involved][6] :-) Stockfish is also special in that every chess fan, even if not a programmer, [can easily help][7] the team to improve the engine by connecting their PC to Fishtest and let it play some games in the background to test new patches. Individual contributions vary from 1 to 32 cores, but this year Bojun Guo made it a little bit special by plugging a whole data center during the whole year: it was a vertiginous experience to see Fishtest spikes with 17466 cores connected playing [25600 games/minute][8]. Thanks Guo! The Stockfish team [0]: [1]: [2]: [3]: [4]: [5]: [6]: [7]: [8]: --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 053ee67e..95862ebb 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 = ""; +const string Version = "11"; /// 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