From 434b2c72a44ba255c14957f519e3993ea3d5d6bc Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sun, 9 Jun 2019 08:19:07 -0400 Subject: [PATCH 001/281] Simplify k-value for passers. Bench: 3854907 (#2182) Stockfish evaluates passed pawns in part based on a variable k, which shapes the passed pawn bonus based on the number of squares between the current square and promotion square that are attacked by enemy pieces, and the number defended by friendly ones. Prior to this commit, we gave a large bonus when all squares between the pawn and the promotion square were defended, and if they were not, a somewhat smaller bonus if at least the pawn's next square was. However, this distinction does not appear to provide any Elo at STC or LTC. Where do we go from here? Many promising Elo-gaining patches were attempted in the past few months to refine passed pawn calculation, by altering the definitions of unsafe and defended squares. Stockfish uses these definitions to choose the value of k, so those tests interact with this PR. Therefore, it may be worthwhile to retest previously promising but not-quite-passing tests in the vicinity of this patch. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 42344 W: 9455 L: 9374 D: 23515 http://tests.stockfishchess.org/tests/view/5cf83ede0ebc5925cf0904fb LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 69548 W: 11855 L: 11813 D: 45880 http://tests.stockfishchess.org/tests/view/5cf8698f0ebc5925cf0908c8 Bench: 3854907 --- src/evaluate.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d211db64..8c1b0b08 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -661,13 +661,9 @@ namespace { // assign a smaller bonus if the block square isn't attacked. int k = !unsafeSquares ? 20 : !(unsafeSquares & blockSq) ? 9 : 0; - // If the path to the queen is fully defended, assign a big bonus. - // Otherwise assign a smaller bonus if the block square is defended. - if (defendedSquares == squaresToQueen) - k += 6; - - else if (defendedSquares & blockSq) - k += 4; + // Assign a larger bonus if the block square is defended. + if (defendedSquares & blockSq) + k += 5; bonus += make_score(k * w, k * w); } From 09caea5cab0b6c23fea8347a740bcc00083da6ab Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 3 Jun 2019 07:16:33 -0600 Subject: [PATCH 002/281] Simplify Outposts #2176 This is a functional simplification. This is NOT the exact version that was tested. Beyond the testing, an assignment was removed and a piece changes for consistency. Instead of rewarding ANY square past an opponent pawn as an "outpost," only use squares that are protected by our pawn. I believe this is more consistent with what the chess world calls an "outpost." STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23540 W: 5387 L: 5269 D: 12884 http://tests.stockfishchess.org/tests/view/5cf51e6d0ebc5925cf08b823 LTC LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 53085 W: 9271 L: 9204 D: 34610 http://tests.stockfishchess.org/tests/view/5cf5279e0ebc5925cf08b992 bench 3424592 --- src/evaluate.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8c1b0b08..30c22a8e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -141,7 +141,7 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 9, 3); + constexpr Score Outpost = S( 36, 12); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnPawn = S( 10, 32); @@ -305,14 +305,12 @@ namespace { if (Pt == BISHOP || Pt == KNIGHT) { // Bonus if piece is on an outpost square or can reach one - bb = OutpostRanks & ~pe->pawn_attacks_span(Them); + bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost * (Pt == KNIGHT ? 4 : 2) - * ((attackedBy[Us][PAWN] & s) ? 2 : 1); + score += Outpost * (Pt == KNIGHT ? 2 : 1); - else if (bb &= b & ~pos.pieces(Us)) - score += Outpost * (Pt == KNIGHT ? 2 : 1) - * ((attackedBy[Us][PAWN] & bb) ? 2 : 1); + else if (bb & b & ~pos.pieces(Us)) + score += Outpost / (Pt == KNIGHT ? 1 : 2); // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) From 2d06d659c0321ddfcf0781327e5175df0b0ff616 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 9 Jun 2019 15:26:53 +0300 Subject: [PATCH 003/281] Advanced pawn pushes tweak (#2175) passed STC http://tests.stockfishchess.org/tests/view/5cf586ee0ebc5925cf08c0ed LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 29496 W: 6718 L: 6406 D: 16372 passed LTC http://tests.stockfishchess.org/tests/view/5cf59b630ebc5925cf08c343 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 40778 W: 7057 L: 6765 D: 26956 original idea from early 2018 by @jerrydonaldwatson Code slightly rewritten to be shorter and more logical, no functinal changes compared to passed patch. --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index a3ce4c2d..11586787 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -958,7 +958,7 @@ moves_loop: // When in check, search starts from here if ( !captureOrPromotion && !givesCheck - && !pos.advanced_pawn_push(move)) + && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) { // Move count based pruning (~30 Elo) if (moveCountPruning) From 6ed81f09ffa513f0938c1a16fa4edd55e552c178 Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Sun, 9 Jun 2019 08:27:50 -0400 Subject: [PATCH 004/281] SEE Pruning Tweak (#2183) Don't SEE prune any check extensions STC (yellow): LLR: -2.96 (-2.94,2.94) [0.50,4.50] Total: 129934 W: 29390 L: 28905 D: 71639 http://tests.stockfishchess.org/tests/view/5cf6b1a70ebc5925cf08dedb LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 102115 W: 17692 L: 17224 D: 67199 http://tests.stockfishchess.org/tests/view/5cf830710ebc5925cf090331 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 11586787..f26ab959 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -984,7 +984,8 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) + else if ((!givesCheck || !(pos.blockers_for_king(~us) & from_sq(move))) + && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) continue; } From 5935daf8a5b6925a6af2084f87e3831b3bb17dac Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 9 Jun 2019 06:28:42 -0600 Subject: [PATCH 005/281] Simplify WeakUnopposedPawn #2181 This is a functional simplification. Moves WeakUnopposedPawn to pawns.cpp and remove piece dependency. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 8699 W: 2000 L: 1853 D: 4846 http://tests.stockfishchess.org/tests/view/5cf7721b0ebc5925cf08ee79 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 46605 W: 7969 L: 7890 D: 30746 http://tests.stockfishchess.org/tests/view/5cf7d5f70ebc5925cf08fa96 --- src/evaluate.cpp | 5 ----- src/pawns.cpp | 7 ++++--- src/pawns.h | 2 -- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 30c22a8e..0da6ba4d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -152,7 +152,6 @@ namespace { constexpr Score ThreatBySafePawn = S(173, 94); constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); - constexpr Score WeakUnopposedPawn = S( 12, 23); #undef S @@ -555,10 +554,6 @@ namespace { score += RestrictedPiece * popcount(b); - // Bonus for enemy unopposed weak pawns - if (pos.pieces(Us, ROOK, QUEEN)) - score += WeakUnopposedPawn * pe->weak_unopposed(Them); - // Find squares where our pawns can push on the next move b = shift(pos.pieces(Us, PAWN)) & ~pos.pieces(); b |= shift(b & TRank3BB) & ~pos.pieces(); diff --git a/src/pawns.cpp b/src/pawns.cpp index 291d40b6..47c89ed4 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -35,6 +35,7 @@ namespace { constexpr Score Backward = S( 9, 24); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); + constexpr Score WeakUnopposed = S( 13, 27); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -77,7 +78,7 @@ namespace { Bitboard ourPawns = pos.pieces( Us, PAWN); Bitboard theirPawns = pos.pieces(Them, PAWN); - e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0; + e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); @@ -132,10 +133,10 @@ namespace { score += make_score(v, v * (r - 2) / 4); } else if (!neighbours) - score -= Isolated, e->weakUnopposed[Us] += !opposed; + score -= Isolated + WeakUnopposed * int(!opposed); else if (backward) - score -= Backward, e->weakUnopposed[Us] += !opposed; + score -= Backward + WeakUnopposed * int(!opposed); if (doubled && !support) score -= Doubled; diff --git a/src/pawns.h b/src/pawns.h index 771e9cd3..ef4b83f8 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -37,7 +37,6 @@ struct Entry { Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } - int weak_unopposed(Color c) const { return weakUnopposed[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); } template @@ -59,7 +58,6 @@ struct Entry { Bitboard pawnAttacksSpan[COLOR_NB]; Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; - int weakUnopposed[COLOR_NB]; int castlingRights[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] }; From 14e23d520f251f28234a686a9d30d9711495dfef Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 9 Jun 2019 06:31:16 -0600 Subject: [PATCH 006/281] Remove a few file_of's (simplify adjacent_files_bb) #2171 This is a non-functional simplification that removes two file_of(s). STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 22030 W: 5106 L: 4984 D: 11940 http://tests.stockfishchess.org/tests/view/5cf028de0ebc5925cf0839e7 --- src/bitboard.h | 8 ++++---- src/pawns.cpp | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 4e0267f1..ef5c4fa3 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -184,8 +184,8 @@ constexpr Bitboard pawn_double_attacks_bb(Bitboard b) { /// adjacent_files_bb() returns a bitboard representing all the squares on the /// adjacent files of the given one. -inline Bitboard adjacent_files_bb(File f) { - return shift(file_bb(f)) | shift(file_bb(f)); +inline Bitboard adjacent_files_bb(Square s) { + return shift(file_bb(s)) | shift(file_bb(s)); } @@ -221,7 +221,7 @@ inline Bitboard forward_file_bb(Color c, Square s) { /// starting from the given square. inline Bitboard pawn_attack_span(Color c, Square s) { - return forward_ranks_bb(c, s) & adjacent_files_bb(file_of(s)); + return forward_ranks_bb(c, s) & adjacent_files_bb(s); } @@ -229,7 +229,7 @@ inline Bitboard pawn_attack_span(Color c, Square s) { /// the given color and on the given square is a passed pawn. inline Bitboard passed_pawn_span(Color c, Square s) { - return forward_ranks_bb(c, s) & (adjacent_files_bb(file_of(s)) | file_bb(s)); + return forward_ranks_bb(c, s) & (adjacent_files_bb(s) | file_bb(s)); } diff --git a/src/pawns.cpp b/src/pawns.cpp index 47c89ed4..2b4f039e 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -87,7 +87,6 @@ namespace { { assert(pos.piece_on(s) == make_piece(Us, PAWN)); - File f = file_of(s); Rank r = relative_rank(Us, s); e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); @@ -98,7 +97,7 @@ namespace { lever = theirPawns & PawnAttacks[Us][s]; leverPush = theirPawns & PawnAttacks[Us][s + Up]; doubled = ourPawns & (s - Up); - neighbours = ourPawns & adjacent_files_bb(f); + neighbours = ourPawns & adjacent_files_bb(s); phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); From 53d197b841731840891c783bb7e044f012db4aa7 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 9 Jun 2019 06:33:34 -0600 Subject: [PATCH 007/281] Simplify passed pawns. (#2159) This is a functional simplification. If all of the stoppers are levers, a simple pawn push passes. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 41768 W: 9360 L: 9278 D: 23130 http://tests.stockfishchess.org/tests/view/5ce82ed60ebc5925cf073a79 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 40463 W: 6964 L: 6875 D: 26624 http://tests.stockfishchess.org/tests/view/5ce87d0b0ebc5925cf07472b --- src/pawns.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 2b4f039e..d7848fbd 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -110,9 +110,8 @@ namespace { // full attack info to evaluate them. Include also not passed pawns // which could become passed after one or two pawn pushes when are // not attacked more times than defended. - if ( !(stoppers ^ lever ^ leverPush) - && (support || !more_than_one(lever)) - && popcount(phalanx) >= popcount(leverPush)) + if ( !(stoppers ^ lever) || + (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush))) e->passedPawns[Us] |= s; else if (stoppers == square_bb(s + Up) && r >= RANK_5) From 2ead74d1e2b0c5edbb0da5887e56bbddb5b2a905 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 9 Jun 2019 14:34:51 +0200 Subject: [PATCH 008/281] Remove depth condition for ttPv (#2166) Currently PV nodes with a depth <= 4 were ignored for ttPv. Now remove this constraint and use all PV nodes. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 52209 W: 11755 L: 11694 D: 28760 http://tests.stockfishchess.org/tests/view/5cebc2d30ebc5925cf07b93a LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 20874 W: 3689 L: 3568 D: 13617 http://tests.stockfishchess.org/tests/view/5cec01fc0ebc5925cf07c62d --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f26ab959..df777b3b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -603,7 +603,7 @@ namespace { ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; - ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY); + ttPv = PvNode || (ttHit && tte->is_pv()); // At non-PV nodes we check for an early TT cutoff if ( !PvNode From d39bc2efa197ba2fd55b68eced1c60bcfe2facc1 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 2 May 2019 19:36:25 +0200 Subject: [PATCH 009/281] Assorted trivial cleanups 5/2019 No functional change. bench: 4178282 --- Readme.md | 28 ++++++++++++++-------------- src/endgame.cpp | 35 ++++++++++++++++++----------------- src/endgame.h | 8 ++++---- src/evaluate.cpp | 8 +++----- src/main.cpp | 2 +- src/pawns.h | 1 - src/position.cpp | 12 ++++++------ src/search.cpp | 45 ++++++++++++++++++--------------------------- src/search.h | 2 +- src/tt.cpp | 7 ++++--- src/tt.h | 2 +- src/types.h | 5 +++-- 12 files changed, 73 insertions(+), 82 deletions(-) diff --git a/Readme.md b/Readme.md index bc058dbc..be324763 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ ## Overview [![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?branch=master&svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish/branch/master) [Stockfish](https://stockfishchess.org) is a free, powerful UCI chess engine derived from Glaurung 2.1. It is not a complete chess program and requires a @@ -34,11 +34,11 @@ Currently, Stockfish has the following UCI options: A positive value for contempt favors middle game positions and avoids draws. * #### Analysis Contempt - By default, contempt is set to prefer the side to move. Set this option to "White" + By default, contempt is set to prefer the side to move. Set this option to "White" or "Black" to analyse with contempt for that side, or "Off" to disable contempt. * #### Threads - The number of CPU threads used for searching a position. For best performance, set + The number of CPU threads used for searching a position. For best performance, set this equal to the number of CPU cores available. * #### Hash @@ -58,18 +58,18 @@ Currently, Stockfish has the following UCI options: Lower the Skill Level in order to make Stockfish play weaker. * #### Move Overhead - Assume a time delay of x ms due to network and GUI overheads. This is useful to + Assume a time delay of x ms due to network and GUI overheads. This is useful to avoid losses on time in those cases. * #### Minimum Thinking Time - Search for at least x ms per move. + Search for at least x ms per move. * #### Slow Mover - Lower values will make Stockfish take less time in games, higher values will + Lower values will make Stockfish take less time in games, higher values will make it think longer. * #### nodestime - Tells the engine to use nodes searched instead of wall time to account for + Tells the engine to use nodes searched instead of wall time to account for elapsed time. Useful for engine testing. * #### UCI_Chess960 @@ -79,13 +79,13 @@ Currently, Stockfish has the following UCI options: An option handled by your GUI. * #### SyzygyPath - Path to the folders/directories storing the Syzygy tablebase files. Multiple - directories are to be separated by ";" on Windows and by ":" on Unix-based + Path to the folders/directories storing the Syzygy tablebase files. Multiple + directories are to be separated by ";" on Windows and by ":" on Unix-based operating systems. Do not use spaces around the ";" or ":". - + Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6` - - It is recommended to store .rtbw files on an SSD. There is no loss in storing + + It is recommended to store .rtbw files on an SSD. There is no loss in storing the .rtbz files on a regular HD. It is recommended to verify all md5 checksums of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will lead to engine crashes. @@ -153,7 +153,7 @@ 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) +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). ### Improving the code @@ -169,7 +169,7 @@ generic rather than being focused on Stockfish's precise implementation. 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) +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). 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. diff --git a/src/endgame.cpp b/src/endgame.cpp index 7c4efa3c..4f8c2279 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -88,27 +88,28 @@ namespace Endgames { void init() { - add("KPK"); - add("KNNK"); - add("KBNK"); - add("KRKP"); - add("KRKB"); - add("KRKN"); - add("KQKP"); - add("KQKR"); - add("KNNKP"); + add("KPK"); + add("KNNK"); + add("KBNK"); + add("KRKP"); + add("KRKB"); + add("KRKN"); + add("KQKP"); + add("KQKR"); + add("KNNKP"); - add("KNPK"); - add("KNPKB"); - add("KRPKR"); - add("KRPKB"); - add("KBPKB"); - add("KBPKN"); - add("KBPPKB"); - add("KRPPKRP"); + add("KNPK"); + add("KNPKB"); + add("KRPKR"); + add("KRPKB"); + add("KBPKB"); + add("KBPKN"); + add("KBPPKB"); + add("KRPPKRP"); } } + /// Mate with KX vs K. This function is used to evaluate positions with /// king and plenty of material vs a lone king. It simply gives the /// attacking side a bonus for driving the defending king towards the edge diff --git a/src/endgame.h b/src/endgame.h index 81afb2e5..d0a5a97e 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -91,7 +91,7 @@ struct Endgame : public EndgameBase { }; -/// The Endgames class stores the pointers to endgame evaluation and scaling +/// The Endgames namespace handles the pointers to endgame evaluation and scaling /// base objects in two std::map. We use polymorphism to invoke the actual /// endgame function by calling its virtual operator(). @@ -99,9 +99,11 @@ namespace Endgames { template using Ptr = std::unique_ptr>; template using Map = std::map>; - + extern std::pair, Map> maps; + void init(); + template Map& map() { return std::get::value>(maps); @@ -119,8 +121,6 @@ namespace Endgames { const EndgameBase* probe(Key key) { return map().count(key) ? map()[key].get() : nullptr; } - - void init(); } #endif // #ifndef ENDGAME_H_INCLUDED diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0da6ba4d..3ff1460b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -190,10 +190,8 @@ namespace { // color, including x-rays. But diagonal x-rays through pawns are not computed. Bitboard attackedBy2[COLOR_NB]; - // kingRing[color] are the squares adjacent to the king, plus (only for a - // king on its first rank) the squares two ranks in front. For instance, - // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6 - // and h6. + // kingRing[color] are the squares adjacent to the king plus some other + // very near squares, depending on king position. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color @@ -802,7 +800,7 @@ namespace { // Early exit if score is high Value v = (mg_value(score) + eg_value(score)) / 2; - if (abs(v) > (LazyThreshold + pos.non_pawn_material() / 64)) + if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; // Main evaluation begins here diff --git a/src/main.cpp b/src/main.cpp index 57656f62..f94a322c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,8 +42,8 @@ int main(int argc, char* argv[]) { Bitboards::init(); Position::init(); Bitbases::init(); - Search::init(); Endgames::init(); + Search::init(); Threads.set(Options["Threads"]); Search::clear(); // After threads are up diff --git a/src/pawns.h b/src/pawns.h index ef4b83f8..a34e5e69 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -59,7 +59,6 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; - int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] }; typedef HashTable Table; diff --git a/src/position.cpp b/src/position.cpp index edb40499..14121d47 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -387,7 +387,7 @@ void Position::set_state(StateInfo* si) const { if (type_of(pc) == PAWN) si->pawnKey ^= Zobrist::psq[pc][s]; - else if (type_of(pc) != PAWN && type_of(pc) != KING) + else if (type_of(pc) != KING) si->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc]; } @@ -491,7 +491,7 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners // Snipers are sliders that attack 's' when a piece and other snipers are removed Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; - Bitboard occupancy = pieces() & ~snipers; + Bitboard occupancy = pieces() ^ snipers; while (snipers) { @@ -1192,10 +1192,10 @@ bool Position::has_game_cycle(int ply) const { if (ply > i) return true; - // For nodes before or at the root, check that the move is a repetition one - // rather than a move to the current position. - // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in the same - // location, so we have to select which square to check. + // For nodes before or at the root, check that the move is a + // repetition rather than a move to the current position. + // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in + // the same location, so we have to select which square to check. if (color_of(piece_on(empty(s1) ? s2 : s1)) != side_to_move()) continue; diff --git a/src/search.cpp b/src/search.cpp index df777b3b..0e10f44f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -149,7 +149,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int(22.9 * std::log(i)); + Reductions[i] = int(22.9 * std::log(i)); } @@ -240,17 +240,13 @@ void MainThread::search() { minScore = std::min(minScore, th->rootMoves[0].score); // Vote according to score and depth, and select the best thread - int64_t bestVote = 0; for (Thread* th : Threads) { votes[th->rootMoves[0].pv[0]] += - (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); + (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (votes[th->rootMoves[0].pv[0]] > bestVote) - { - bestVote = votes[th->rootMoves[0].pv[0]]; + if (votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) bestThread = th; - } } } @@ -538,13 +534,13 @@ namespace { bool ttHit, ttPv, inCheck, givesCheck, improving; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; - int moveCount, captureCount, quietCount; + int moveCount, captureCount, quietCount, singularLMR; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); inCheck = pos.checkers(); Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = ss->moveCount = 0; + moveCount = captureCount = quietCount = singularLMR = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; @@ -589,10 +585,10 @@ namespace { // starts with statScore = 0. Later grandchildren start with the last calculated // statScore of the previous grandchild. This influences the reduction rules in // LMR which are based on the statScore of parent position. - if (rootNode) - (ss + 4)->statScore = 0; - else - (ss + 2)->statScore = 0; + if (rootNode) + (ss + 4)->statScore = 0; + else + (ss + 2)->statScore = 0; // Step 4. Transposition table lookup. We don't want the score of a partial // search to overwrite a previous full search TT value, so we use a different @@ -850,7 +846,6 @@ moves_loop: // When in check, search starts from here value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - int singularExtensionLMRmultiplier = 0; // Step 12. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. @@ -907,12 +902,13 @@ moves_loop: // When in check, search starts from here ss->excludedMove = MOVE_NONE; if (value < singularBeta) - { + { extension = ONE_PLY; - singularExtensionLMRmultiplier++; + singularLMR++; + if (value < singularBeta - std::min(3 * depth / ONE_PLY, 39)) - singularExtensionLMRmultiplier++; - } + singularLMR++; + } // Multi-cut pruning // Our ttMove is assumed to fail high, and now we failed high also on a reduced @@ -1023,8 +1019,9 @@ moves_loop: // When in check, search starts from here // Decrease reduction if opponent's move count is high (~10 Elo) if ((ss-1)->moveCount > 15) r -= ONE_PLY; + // Decrease reduction if move has been singularly extended - r -= singularExtensionLMRmultiplier * ONE_PLY; + r -= singularLMR * ONE_PLY; if (!captureOrPromotion) { @@ -1060,7 +1057,7 @@ moves_loop: // When in check, search starts from here r -= ss->statScore / 20000 * ONE_PLY; } - Depth d = std::max(newDepth - std::max(r, DEPTH_ZERO), ONE_PLY); + Depth d = clamp(newDepth - r, ONE_PLY, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); @@ -1476,7 +1473,7 @@ moves_loop: // When in check, search starts from here void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus) { - CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; + CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; Piece moved_piece = pos.moved_piece(move); PieceType captured = type_of(pos.piece_on(to_sq(move))); @@ -1715,10 +1712,4 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW) Cardinality = 0; } - else - { - // Assign the same rank to all moves - for (auto& m : rootMoves) - m.tbRank = 0; - } } diff --git a/src/search.h b/src/search.h index 92e124fc..24c58d30 100644 --- a/src/search.h +++ b/src/search.h @@ -69,7 +69,7 @@ struct RootMove { Value score = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE; int selDepth = 0; - int tbRank; + int tbRank = 0; Value tbScore; std::vector pv; }; diff --git a/src/tt.cpp b/src/tt.cpp index b8fe7567..6121b3ad 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -43,15 +43,16 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) // Overwrite less valuable entries if ( (k >> 48) != key16 - || d / ONE_PLY + 10 > depth8 + ||(d - DEPTH_OFFSET) / ONE_PLY > depth8 - 4 || b == BOUND_EXACT) { + assert((d - DEPTH_OFFSET) / ONE_PLY >= 0); + key16 = (uint16_t)(k >> 48); value16 = (int16_t)v; eval16 = (int16_t)ev; genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b); - assert((d - DEPTH_NONE) / ONE_PLY >= 0); - depth8 = (uint8_t)((d - DEPTH_NONE) / ONE_PLY); + depth8 = (uint8_t)((d - DEPTH_OFFSET) / ONE_PLY); } } diff --git a/src/tt.h b/src/tt.h index 3608b77c..3a5ba5da 100644 --- a/src/tt.h +++ b/src/tt.h @@ -40,7 +40,7 @@ struct TTEntry { Move move() const { return (Move )move16; } Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } - Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_NONE; } + Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_OFFSET; } bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --git a/src/types.h b/src/types.h index b0758f43..bee6538f 100644 --- a/src/types.h +++ b/src/types.h @@ -213,8 +213,9 @@ enum Depth : int { DEPTH_QS_NO_CHECKS = -1 * ONE_PLY, DEPTH_QS_RECAPTURES = -5 * ONE_PLY, - DEPTH_NONE = -6 * ONE_PLY, - DEPTH_MAX = MAX_PLY * ONE_PLY + DEPTH_NONE = -6 * ONE_PLY, + DEPTH_OFFSET = DEPTH_NONE, + DEPTH_MAX = MAX_PLY * ONE_PLY }; static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); From a9cca5c953e6ccec865102b13b47b9f45d98a0fc Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Sun, 9 Jun 2019 18:26:47 -0400 Subject: [PATCH 010/281] No DC prune in QS (#2185) Don't prune discover checks in qSearch STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 23176 W: 5320 L: 5039 D: 12817 http://tests.stockfishchess.org/tests/view/5cfbc9350ebc5925cf094ab3 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 128428 W: 22222 L: 21679 D: 84527 http://tests.stockfishchess.org/tests/view/5cfbf0b70ebc5925cf094ebc Bench: 3883245 --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index 0e10f44f..50bce13c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1363,6 +1363,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))) && !pos.see_ge(move)) continue; From f9518de974fdf1931dbead736364efce9537320b Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 14 Jun 2019 07:36:42 +0200 Subject: [PATCH 011/281] Increase pawns cache (#2187) Increase size of the pawns table by the factor 8. This decreases the number of recalculations of pawn structure information significantly (at least at LTC). I have done measurements for different depths and pawn cache sizes. First are given the number of pawn entry calculations are done (in parentheses is the frequency that a call to probe triggers a pawn entry calculation). The delta% are the percentage of less done pawn entry calculations in comparison to master VSTC: bench 1 1 12 STC: bench 8 1 16 LTC: bench 64 1 20 VLTC: bench 512 1 24 VSTC STC LTC VLTC master 82218(6%) 548935(6%) 2415422(7%) 9548071(7%) pawncache*2 79859(6%) 492943(5%) 2084794(6%) 8275206(6%) pawncache*4 78551(6%) 458758(5%) 1827770(5%) 7112531(5%) pawncache*8 77963(6%) 439421(4%) 1649169(5%) 6128652(4%) delta%(p2-m) -2.9% -10.2% -13.7% -13.3% delta%(p4-m) -4.5% -16.4% -24.3% -25.5% delta%(p8-m) -5.2% -20.0% -31.7% -35.8% STC: (non-regression test because at STC the effect is smaller than at LTC) LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 22767 W: 5160 L: 5040 D: 12567 http://tests.stockfishchess.org/tests/view/5d00f6040ebc5925cf09c3e2 LTC: LLR: 2.94 (-2.94,2.94) [0.00,4.00] Total: 26340 W: 4524 L: 4286 D: 17530 http://tests.stockfishchess.org/tests/view/5d00a3810ebc5925cf09ba16 No functional change. --- src/pawns.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.h b/src/pawns.h index a34e5e69..1f930988 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -61,7 +61,7 @@ struct Entry { int castlingRights[COLOR_NB]; }; -typedef HashTable Table; +typedef HashTable Table; Entry* probe(const Position& pos); From 8cfe27b76521f3c357b8d3542717aceaa5eee23b Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 14 Jun 2019 00:22:02 -0600 Subject: [PATCH 012/281] Remove backmost_sq (#2190) This is a non-functional simplification. backmost_sq and frontmost_sq are redundant. It seems quite clear to always use frontmost_sq and use the correct color. Non functional change. --- src/bitboard.h | 5 +---- src/endgame.cpp | 2 +- src/pawns.cpp | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index ef5c4fa3..7a16597d 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -376,10 +376,7 @@ inline Square pop_lsb(Bitboard* b) { } -/// frontmost_sq() and backmost_sq() return the most/least advanced square in -/// the given bitboard relative to the given color. - +/// frontmost_sq() returns the most advanced square for the given color inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); } -inline Square backmost_sq(Color c, Bitboard b) { return c == WHITE ? lsb(b) : msb(b); } #endif // #ifndef BITBOARD_H_INCLUDED diff --git a/src/endgame.cpp b/src/endgame.cpp index 4f8c2279..e10f8d5d 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -365,7 +365,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && pos.count(weakSide) >= 1) { // Get weakSide pawn that is closest to the home rank - Square weakPawnSq = backmost_sq(weakSide, pos.pieces(weakSide, PAWN)); + Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); Square strongKingSq = pos.square(strongSide); Square weakKingSq = pos.square(weakSide); diff --git a/src/pawns.cpp b/src/pawns.cpp index d7848fbd..bbcadceb 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -190,7 +190,7 @@ void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); - Rank ourRank = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1; + Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; b = theirPawns & file_bb(f); Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; From 46ce245763705c89dba60dcfda549dc1f64eb48b Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Fri, 14 Jun 2019 13:59:17 -0400 Subject: [PATCH 013/281] Simplify SEE Pruning (#2191) Simplify SEE Pruning Note this should also be a speedup... If givesCheck is extended we know (except for DC) that it will have a positive SEE. So this new logic will be triggered before doing another expensive SEE function. STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 24429 W: 5484 L: 5368 D: 13577 http://tests.stockfishchess.org/tests/view/5cffbccd0ebc5925cf09a154 LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 28428 W: 4873 L: 4765 D: 18790 http://tests.stockfishchess.org/tests/view/5d0015f60ebc5925cf09acb1 Bench: 3897263 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 50bce13c..d9543899 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -980,7 +980,7 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth))) continue; } - else if ((!givesCheck || !(pos.blockers_for_king(~us) & from_sq(move))) + else if ((!givesCheck || !extension) && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) continue; } From 466daf6fbafd1f58f064c2fa03d2fa2c1315c4f5 Mon Sep 17 00:00:00 2001 From: syzygy1 <3028851+syzygy1@users.noreply.github.com> Date: Tue, 18 Jun 2019 23:27:34 +0200 Subject: [PATCH 014/281] Partial revert of "Assorted trivial cleanups 5/2019". Since root_probe() and root_probe_wdl() do not reset all tbRank values if they fail, it is necessary to do this in rank_root_move(). This fixes issue #2196. Alternatively, the loop could be moved into both root_probe() and root_probe_wdl(). No functional change --- src/search.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index d9543899..047a0892 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1713,4 +1713,10 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW) Cardinality = 0; } + else + { + // Clean up if root_probe() and root_probe_wdl() have failed + for (auto& m : rootMoves) + m.tbRank = 0; + } } From 59f1d0c7dd3fcca307a18ff493ce07e290754a2b Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 13 Jun 2019 22:32:23 +0200 Subject: [PATCH 015/281] Fix progress issue with shuffling extensions Fixes issues #2126 and #2189 where no progress in rootDepth is made for particular fens: 8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1 8/1r1rp1k1/1b1pPp2/2pP1Pp1/1pP3Pp/pP5P/P5K1/8 w - - 79 46 the cause are the shuffle extensions. Upon closer analysis, it appears that in these cases a shuffle extension is made for every node searched, and progess can not be made. This patch implements a fix, namely to limit the number of extensions relative to the number of nodes searched. The ratio employed is 1/4, which fixes the issues seen so far, but it is a heuristic, and I expect that certain positions might require an even smaller fraction. The patch was tested as a bug fix and passed: STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 56601 W: 12633 L: 12581 D: 31387 http://tests.stockfishchess.org/tests/view/5d02b37a0ebc5925cf09f6da LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 52042 W: 8907 L: 8837 D: 34298 http://tests.stockfishchess.org/tests/view/5d0319420ebc5925cf09fe57 Furthermore, to confirm that the shuffle extension in this form indeed still brings Elo, one more test at VLTC was performed: VLTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 142022 W: 20963 L: 20435 D: 100624 http://tests.stockfishchess.org/tests/view/5d03630d0ebc5925cf0a011a Bench: 3961247 --- src/search.cpp | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 047a0892..9919b0cc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -932,7 +932,7 @@ moves_loop: // When in check, search starts from here else if ( PvNode && pos.rule50_count() > 18 && depth < 3 * ONE_PLY - && ss->ply < 3 * thisThread->rootDepth / ONE_PLY) // To avoid too deep searches + && ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions extension = ONE_PLY; // Passed pawn extension diff --git a/src/thread.cpp b/src/thread.cpp index 2f1237a3..e5043b6e 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -191,7 +191,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, for (Thread* th : *this) { - th->nodes = th->tbHits = th->nmpMinPly = 0; + th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0; th->rootDepth = th->completedDepth = DEPTH_ZERO; 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 114769d2..c11d1787 100644 --- a/src/thread.h +++ b/src/thread.h @@ -59,7 +59,7 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; - size_t pvIdx, pvLast; + size_t pvIdx, pvLast, shuffleExts; int selDepth, nmpMinPly; Color nmpColor; std::atomic nodes, tbHits, bestMoveChanges; From 297c40291a1cc0ca27fecef342501ba1c359f9cd Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Mon, 17 Jun 2019 17:35:03 -0400 Subject: [PATCH 016/281] QuietPick Speed-up Non-functional speedup: no need to generate, score, or sort quiet moves if SkipQuiet is true. Thanks to @mstembera for his suggestion. STC: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 27910 W: 6406 L: 6129 D: 15375 http://tests.stockfishchess.org/tests/view/5d07e0920ebc5925cf0a58a8 Closes https://github.com/official-stockfish/Stockfish/pull/2194 No functional change --- src/movepick.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index a70785e7..52ac5b4c 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -200,11 +200,15 @@ top: /* fallthrough */ case QUIET_INIT: - cur = endBadCaptures; - endMoves = generate(pos, cur); + if (!skipQuiets) + { + cur = endBadCaptures; + endMoves = generate(pos, cur); - score(); - partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); + score(); + partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); + } + ++stage; /* fallthrough */ From 8bf21a723e77399382f05c75e45201882772684a Mon Sep 17 00:00:00 2001 From: Miguel Lahoz Date: Sat, 15 Jun 2019 14:01:02 +0800 Subject: [PATCH 017/281] Change multi-cut pruning condition Use comparison of eval with beta to predict potential cutNodes. This allows multi-cut pruning to also prune possibly mislabeled Pv and NonPv nodes. STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 54305 W: 12302 L: 11867 D: 30136 http://tests.stockfishchess.org/tests/view/5d048ba50ebc5925cf0a15e8 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 189512 W: 32620 L: 31904 D: 124988 http://tests.stockfishchess.org/tests/view/5d04bf740ebc5925cf0a17f0 Normally I would think such changes are risky, specially for PvNodes, but after trying a few other versions, it seems this version is more sound than I initially thought. Aside from this, a small funtional change is made to return singularBeta instead of beta to be more consistent with the fail-soft logic used in other parts of search. ============================= How to continue from there ? We could try to audit other parts of the search where the "cutNode" variable is used, and try to use dynamic info based on heuristic eval rather than on this variable, to check if the idea behind this patch could also be applied successfuly. Bench: 3503788 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 9919b0cc..f682da3a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -913,10 +913,11 @@ moves_loop: // When in check, search starts from here // Multi-cut pruning // Our ttMove is assumed to fail high, and now we failed high also on a reduced // search without the ttMove. So we assume this expected Cut-node is not singular, - // that is multiple moves fail high, and we can prune the whole subtree by returning - // the hard beta bound. - else if (cutNode && singularBeta > beta) - return beta; + // that multiple moves fail high, and we can prune the whole subtree by returning + // a soft bound. + else if ( eval >= beta + && singularBeta >= beta) + return singularBeta; } // Check extension (~2 Elo) From 37ffacf2094594314346bf9c3d7d8a61911b34d5 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 20 Jun 2019 03:05:57 +0300 Subject: [PATCH 018/281] More bonus for free passed pawn Give even more bonus to passed pawn if adjacent squares to its path are not attacked. passed STC http://tests.stockfishchess.org/tests/view/5d08c9b10ebc5925cf0a6630 LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 175197 W: 39859 L: 38816 D: 96522 passed LTC http://tests.stockfishchess.org/tests/view/5d0ab8240ebc5925cf0a8fe4 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 92928 W: 16124 L: 15682 D: 61122 Bench: 3398333 --- src/evaluate.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3ff1460b..cf478909 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -605,6 +605,7 @@ namespace { }; Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; + Bitboard wideUnsafeSquares; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); @@ -639,6 +640,7 @@ namespace { // consider all the squaresToQueen. Otherwise consider only the squares // in the pawn's path attacked or occupied by the enemy. defendedSquares = unsafeSquares = squaresToQueen = forward_file_bb(Us, s); + wideUnsafeSquares = AllSquares; bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); @@ -647,10 +649,14 @@ namespace { if (!(pos.pieces(Them) & bb)) unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); + + if (!unsafeSquares) + wideUnsafeSquares = (attackedBy[Them][ALL_PIECES] | pos.pieces(Them)) + & (shift(squaresToQueen) | shift(squaresToQueen)); // If there aren't any enemy attacks, assign a big bonus. Otherwise // assign a smaller bonus if the block square isn't attacked. - int k = !unsafeSquares ? 20 : !(unsafeSquares & blockSq) ? 9 : 0; + int k = !wideUnsafeSquares ? 35 : !unsafeSquares ? 20 : !(unsafeSquares & blockSq) ? 9 : 0; // Assign a larger bonus if the block square is defended. if (defendedSquares & blockSq) From 7cb8817ef2194737140410b07997fde9f777ef32 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 21 Jun 2019 10:04:31 +0200 Subject: [PATCH 019/281] Rewrite "More bonus for free passed pawn" -removes wideUnsafeSquares bitboard -removes a couple of bitboard operations -removes one if operator -updates comments so they actually represent what this part of code is doing now. passed non-regression STC http://tests.stockfishchess.org/tests/view/5d0c1ae50ebc5925cf0aa8db LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 16892 W: 3865 L: 3733 D: 9294 No functional change --- src/evaluate.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cf478909..da76de10 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -605,7 +605,6 @@ namespace { }; Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; - Bitboard wideUnsafeSquares; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); @@ -636,11 +635,8 @@ namespace { // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) { - // If there is a rook or queen attacking/defending the pawn from behind, - // consider all the squaresToQueen. Otherwise consider only the squares - // in the pawn's path attacked or occupied by the enemy. - defendedSquares = unsafeSquares = squaresToQueen = forward_file_bb(Us, s); - wideUnsafeSquares = AllSquares; + defendedSquares = squaresToQueen = forward_file_bb(Us, s); + unsafeSquares = passed_pawn_span(Us, s); bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); @@ -649,14 +645,14 @@ namespace { if (!(pos.pieces(Them) & bb)) unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); - - if (!unsafeSquares) - wideUnsafeSquares = (attackedBy[Them][ALL_PIECES] | pos.pieces(Them)) - & (shift(squaresToQueen) | shift(squaresToQueen)); - // If there aren't any enemy attacks, assign a big bonus. Otherwise - // assign a smaller bonus if the block square isn't attacked. - int k = !wideUnsafeSquares ? 35 : !unsafeSquares ? 20 : !(unsafeSquares & blockSq) ? 9 : 0; + // If there are no enemy attacks on passed pawn span, assign a big bonus. + // Otherwise assign a smaller bonus if the path to queen is not attacked + // and even smaller bonus if it is attacked but block square is not. + int k = !unsafeSquares ? 35 : + !(unsafeSquares & squaresToQueen) ? 20 : + !(unsafeSquares & blockSq) ? 9 : + 0 ; // Assign a larger bonus if the block square is defended. if (defendedSquares & blockSq) From 4c986b050111e4fb96716a75ae2168c005b03df9 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 21 Jun 2019 16:24:28 +0200 Subject: [PATCH 020/281] Make the debug counters thread safe. needed to use them in a threaded run. No functional change. --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 8d3b202d..b1539ce2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -145,7 +145,7 @@ const string engine_info(bool to_uci) { /// Debug functions used mainly to collect run-time statistics -static int64_t hits[2], means[2]; +static std::atomic hits[2], means[2]; void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; } void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); } From a8de07cc26999e2fef7298a63bfe349aaa4650fa Mon Sep 17 00:00:00 2001 From: joergoster Date: Thu, 27 Jun 2019 08:56:35 +0200 Subject: [PATCH 021/281] Improve multiPV mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip all moves during the Non-PV (zero-window) search which will be searched as PV moves later anyways. We also wake sure the moves will be reported to the GUI despite they're not being searched — some GUIs may get confused otherwise, and it would unnecessarily complicate the code. Tested with MultiPV=4 STC http://tests.stockfishchess.org/tests/view/5ce7137c0ebc5925cf070d69 LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 8233 W: 3708 L: 3424 D: 1101 LTC http://tests.stockfishchess.org/tests/view/5ce798d60ebc5925cf071d17 LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 7369 W: 3197 L: 2911 D: 1261 Closes https://github.com/official-stockfish/Stockfish/pull/2163 No functional change. (in single PV mode) --- src/search.cpp | 8 +++++++- src/thread.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f682da3a..37fc2ec4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -292,7 +292,7 @@ void Thread::search() { bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; - size_t multiPV = Options["MultiPV"]; + multiPV = Options["MultiPV"]; Skill skill(Options["Skill Level"]); // When playing with strength handicap enable MultiPV search that we will @@ -870,6 +870,12 @@ moves_loop: // When in check, search starts from here sync_cout << "info depth " << depth / ONE_PLY << " currmove " << UCI::move(move, pos.is_chess960()) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; + + // In MultiPV mode also skip moves which will be searched later as PV moves + if (rootNode && std::count(thisThread->rootMoves.begin() + thisThread->pvIdx + 1, + thisThread->rootMoves.begin() + thisThread->multiPV, move)) + continue; + if (PvNode) (ss+1)->pv = nullptr; diff --git a/src/thread.h b/src/thread.h index c11d1787..46ddb495 100644 --- a/src/thread.h +++ b/src/thread.h @@ -59,7 +59,7 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; - size_t pvIdx, pvLast, shuffleExts; + size_t pvIdx, multiPV, pvLast, shuffleExts; int selDepth, nmpMinPly; Color nmpColor; std::atomic nodes, tbHits, bestMoveChanges; From 8b4521df83fb08c1b76e99b0ef9d4611b22bfbf3 Mon Sep 17 00:00:00 2001 From: Sergei Ivanov Date: Sat, 25 May 2019 15:30:32 +0300 Subject: [PATCH 022/281] Do not define increment operators on Value, Depth and Direction These operators are never used and do not make sense for these types. No functional change. --- src/types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types.h b/src/types.h index bee6538f..b9c01fe7 100644 --- a/src/types.h +++ b/src/types.h @@ -291,7 +291,6 @@ inline T& operator--(T& d) { return d = T(int(d) - 1); } #define ENABLE_FULL_OPERATORS_ON(T) \ ENABLE_BASE_OPERATORS_ON(T) \ -ENABLE_INCR_OPERATORS_ON(T) \ constexpr T operator*(int i, T d) { return T(i * int(d)); } \ constexpr T operator*(T d, int i) { return T(int(d) * i); } \ constexpr T operator/(T d, int i) { return T(int(d) / i); } \ From dab66631e8e31b86f91475f4245c4be6b36a37de Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 27 Jun 2019 09:21:50 +0200 Subject: [PATCH 023/281] Introduce attacks on space area This patch introduces a small malus for every square in our space mask that is attacked by enemy. The value of the malus is completely arbitrary and is something we can tweak, also maybe we can gain some elo with tweaking space threshold after this addition. Passed STC http://tests.stockfishchess.org/tests/view/5d10ce590ebc5925cf0af30b LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 7082 W: 1648 L: 1449 D: 3985 Passed LTC http://tests.stockfishchess.org/tests/view/5d10d2d80ebc5925cf0af3fd LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 79494 W: 13727 L: 13324 D: 52443 Closes https://github.com/official-stockfish/Stockfish/pull/2207 bench 3516460 --- src/evaluate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index da76de10..f2e822d0 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -133,6 +133,7 @@ namespace { }; // Assorted bonuses and penalties + constexpr Score AttacksOnSpaceArea = S( 4, 0); constexpr Score BishopPawns = S( 3, 7); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@ -711,6 +712,8 @@ namespace { int weight = pos.count(Us) - 1; Score score = make_score(bonus * weight * weight / 16, 0); + score -= AttacksOnSpaceArea * popcount(attackedBy[Them][ALL_PIECES] & behind & safe); + if (T) Trace::add(SPACE, Us, score); From d889bb47185e33012b45cab63359952247bc86e2 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 27 Jun 2019 09:45:53 +0200 Subject: [PATCH 024/281] Bonus for double attacks on unsupported pawns This is a functional change that rewards double attacks on an unsupported pawns. STC (non-functional difference) LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 83276 W: 18981 L: 18398 D: 45897 http://tests.stockfishchess.org/tests/view/5d0970500ebc5925cf0a77d4 LTC (incomplete looping version) LLR: 0.50 (-2.94,2.94) [0.00,3.50] Total: 82999 W: 14244 L: 13978 D: 54777 http://tests.stockfishchess.org/tests/view/5d0a8d480ebc5925cf0a8d58 LTC (completed non-looping version). LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 223381 W: 38323 L: 37512 D: 147546 http://tests.stockfishchess.org/tests/view/5d0e80510ebc5925cf0ad320 Closes https://github.com/official-stockfish/Stockfish/pull/2205 Bench 3633546 ---------------------------------- Comments by Alain SAVARD: interesting result ! I would have expected that search would resolve such positions correctly on the very next move. This is not a very common pattern, and when it happens, it will quickly disappear. So I'm quite surprised that it passed LTC. I would be even more surprised if this would resist a simplification. Anyway, let's try to imagine a few cases. a) If you have White d5 f5 against Black e6, and White to move last move by Black was probably a capture on e6 and White is about to recapture on e6 b) If you have White d5 f5 against e6, and Black to move last move by White was possibly a capture on d5 or f5 or the pawn on e6 was pinned or could not move for some reason. and white wants to blast open the position and just pushed d4-d5 or f4-f5 Some possible follow-ups a) Motif is so rare that the popcount() can be safely replaced with a bool() But this would not pass a SPRT[0,4], So try a simplification with bool() and also without the & ~theirAttacks b) If it works, we probably can simply have this in the loop if (lever) score += S(0, 20); c) remove all this and tweak something in search for pawn captures (priority, SEE, extension,..) --- src/movepick.cpp | 2 +- src/pawns.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 52ac5b4c..b7f66178 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -208,7 +208,7 @@ top: score(); partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); } - + ++stage; /* fallthrough */ diff --git a/src/pawns.cpp b/src/pawns.cpp index bbcadceb..54748504 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -36,6 +36,7 @@ namespace { constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); constexpr Score WeakUnopposed = S( 13, 27); + constexpr Score Attacked2Unsupported = S( 0, 20); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -79,8 +80,13 @@ namespace { Bitboard theirPawns = pos.pieces(Them, PAWN); e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; - e->kingSquares[Us] = SQ_NONE; - e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); + e->kingSquares[Us] = SQ_NONE; + e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); + + // Unsupported enemy pawns attacked twice by us + score += Attacked2Unsupported * popcount( theirPawns + & pawn_double_attacks_bb(ourPawns) + & ~pawn_attacks_bb(theirPawns)); // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) From c9d73d1aa5cf609b626776a112cd699339fefb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Oster?= Date: Sun, 30 Jun 2019 15:16:20 +0200 Subject: [PATCH 025/281] Try to get a more precise bench time (#2211) Initialization of larger hash sizes can take some time. Don't include this time in the bench by resetting the timer after Search::clear(). Also move 'ucinewgame' command down in the list, so that it is processed after the configuration of Threads and Hash size. No functional change. --- src/benchmark.cpp | 2 +- src/uci.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 51bd7949..b23c5d17 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -139,9 +139,9 @@ vector setup_bench(const Position& current, istream& is) { file.close(); } - list.emplace_back("ucinewgame"); list.emplace_back("setoption name Threads value " + threads); list.emplace_back("setoption name Hash value " + ttSize); + list.emplace_back("ucinewgame"); for (const string& fen : fens) if (fen.find("setoption") != string::npos) diff --git a/src/uci.cpp b/src/uci.cpp index 739cf343..a4235f2b 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -164,7 +164,7 @@ namespace { } else if (token == "setoption") setoption(is); else if (token == "position") position(pos, is, states); - else if (token == "ucinewgame") Search::clear(); + else if (token == "ucinewgame") { Search::clear(); elapsed = now(); } // Search::clear() may take some while } elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero' From 79d06d8840110713ca135ca53f2347a57c6494e2 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 30 Jun 2019 07:22:37 -0600 Subject: [PATCH 026/281] Move storm special condition to UnblockedStorm array (#2210) This is a functional simplification. Looks like we can accommodate the special initialization of Value in evaluate_shelter in the UnblockedStorm array. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 32483 W: 7422 L: 7322 D: 17739 http://tests.stockfishchess.org/tests/view/5d14c5f80ebc5925cf0b48da LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 35361 W: 6139 L: 6042 D: 23180 http://tests.stockfishchess.org/tests/view/5d14d69c0ebc5925cf0b4bd0 Bench 3596270 --- src/pawns.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 54748504..c85d4fd9 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -53,11 +53,12 @@ namespace { // Danger of enemy pawns moving toward our king by [distance from edge][rank]. // RANK_1 = 0 is used for files where the enemy has no pawn, or their pawn // is behind our king. + // [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(107), V(123), 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( 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) } }; #undef S @@ -181,16 +182,12 @@ template void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); - constexpr Bitboard BlockSquares = (Rank1BB | Rank2BB | Rank7BB | Rank8BB) - & (FileABB | FileHBB); Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); - Value bonus[] = { (shift(theirPawns) & BlockSquares & ksq) ? Value(374) : Value(5), - VALUE_ZERO }; + Value bonus[] = { Value(5), Value(5) }; File center = clamp(file_of(ksq), FILE_B, FILE_G); for (File f = File(center - 1); f <= File(center + 1); ++f) From 217840a6a5a40b516cab59a450a9f36352997240 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 1 Jul 2019 14:07:23 +0200 Subject: [PATCH 027/281] Introduce coordination between searching threads (#2204) this patch improves threading performance by introducing some coordination between threads. The observation is that threading is an area where a lot of Elo can potentially be gained: https://github.com/glinscott/fishtest/wiki/UsefulData#elo-from-threading At STC, 8 threads gain roughly 320 Elo, vs sequential at the same time, however, loses 66 Elo against a single thread with 8x more time. This 66 Elo should be partially recoverable with improved threading. To improve threading, this patch introduces some LMR at nodes that are already being searched by other threads. This requires some coordination between threads, avoiding however synchronisation. To do so, threads leave a trail of breadcrumbs to mark the nodes they are searching. These breadcrumbs are stored in a small hash table, which is only probed at low plies (currently ply < 8). A couple of variants of this patch passed both STC and LTC threaded tests. I picked the simpler, more robust version. I expect that further tests can find further improvements. STC (5+0.05 @ 8 threads): LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 26209 W: 5359 L: 5079 D: 15771 http://tests.stockfishchess.org/tests/view/5d0a9b030ebc5925cf0a8e6f LTC (20+0.2 @ 8 threads): LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 34832 W: 5650 L: 5382 D: 23800 http://tests.stockfishchess.org/tests/view/5d0c67a20ebc5925cf0aafa7 other passed/tested variants: http://tests.stockfishchess.org/tests/view/5d0a9b030ebc5925cf0a8e6f http://tests.stockfishchess.org/tests/view/5d0c67ca0ebc5925cf0aafa9 http://tests.stockfishchess.org/tests/view/5d0c67810ebc5925cf0aafa3 http://tests.stockfishchess.org/tests/view/5d0958ca0ebc5925cf0a74c6 For the sequential code there is no change in bench, and an earlier version of this patch passed a non-regression test. STC (10+0.1 @ 1 thread) LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 10471 W: 2364 L: 2220 D: 5887 http://tests.stockfishchess.org/tests/view/5d087ee20ebc5925cf0a6381 passed the additional non-regression tests at 2 and 4 threads 20+0.2 TC. The code was rebased on master prior to testing. 2 threads: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 218863 W: 40927 L: 41153 D: 136783 http://tests.stockfishchess.org/tests/view/5d18c6c30ebc5925cf0b9566 4threads: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 16839 W: 3017 L: 2889 D: 10933 http://tests.stockfishchess.org/tests/view/5d18c6ea0ebc5925cf0b9568 No functional change. --- src/search.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 37fc2ec4..e008bec1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -102,6 +102,48 @@ namespace { Move best = MOVE_NONE; }; + // Breadcrumbs are used to mark nodes as being searched by a given thread. + struct Breadcrumb { + std::atomic thread; + std::atomic key; + }; + std::array breadcrumbs; + + // ThreadHolding keeps track of which thread left breadcrumbs at the given node for potential reductions. + // A free node will be marked upon entering the moves loop, and unmarked upon leaving that loop, by the ctor/dtor of this struct. + struct ThreadHolding { + explicit ThreadHolding(Thread* thisThread, Key posKey, int ply) { + location = ply < 8 ? &breadcrumbs[posKey & (breadcrumbs.size() - 1)] : nullptr; + otherThread = false; + owning = false; + if (location) + { + // see if another already marked this location, if not, mark it ourselves. + Thread* tmp = (*location).thread.load(std::memory_order_relaxed); + if (tmp == nullptr) + { + (*location).thread.store(thisThread, std::memory_order_relaxed); + (*location).key.store(posKey, std::memory_order_relaxed); + owning = true; + } + else if ( tmp != thisThread + && (*location).key.load(std::memory_order_relaxed) == posKey) + otherThread = true; + } + } + + ~ThreadHolding() { + if (owning) // free the marked location. + (*location).thread.store(nullptr, std::memory_order_relaxed); + } + + bool marked() { return otherThread; } + + private: + Breadcrumb* location; + bool otherThread, owning; + }; + template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); @@ -847,6 +889,9 @@ moves_loop: // When in check, search starts from here moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); + // Mark this node as being searched. + ThreadHolding th(thisThread, posKey, ss->ply); + // Step 12. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE) @@ -1019,6 +1064,10 @@ moves_loop: // When in check, search starts from here { Depth r = reduction(improving, depth, moveCount); + // Reduction if other threads are searching this position. + if (th.marked()) + r += ONE_PLY; + // Decrease reduction if position is or has been on the PV if (ttPv) r -= 2 * ONE_PLY; From ca51d1ee63f376e0eb6efb6f3d5d901e4b2a5bb0 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 1 Jul 2019 14:07:54 +0200 Subject: [PATCH 028/281] Smoothly change playing strength with skill level. (#2142) The current skill levels (1-20) allow for adjusting playing strengths, but do so in big steps (e.g. level 10 vs level 11 is a ~143 Elo jump at STC). Since the 'Skill Level' input can already be a floating point number, this patch uses the fractional part of the input to provide the user with fine control, allowing for varying the playing strength essentially continuously. The implementation internally still uses integer skill levels (needed since they pick Depths), but non-deterministically rounds up or down the used skill level such that the average integer skill corresponds to the input floating point one. As expected, intermediate (fractional) skill levels yield intermediate playing strenghts. Tested at STC, playing level 10 against levels between 10 and 11 for 10000 games level 10.25 ELO: 24.26 +-6.2 level 10.5 ELO: 67.51 +-6.3 level 10.75 ELO: 98.52 +-6.4 level 11 ELO: 143.65 +-6.7 http://tests.stockfishchess.org/tests/view/5cd9c6b40ebc5925cf056791 http://tests.stockfishchess.org/tests/view/5cd9d22b0ebc5925cf056989 http://tests.stockfishchess.org/tests/view/5cd9cf610ebc5925cf056906 http://tests.stockfishchess.org/tests/view/5cd9d2490ebc5925cf05698e No functional change. --- src/search.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e008bec1..b4a69092 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -335,7 +335,12 @@ void Thread::search() { beta = VALUE_INFINITE; multiPV = Options["MultiPV"]; - Skill skill(Options["Skill Level"]); + // Pick integer skill levels, but non-deterministically round up or down + // such that the average integer skill corresponds to the input floating point one. + PRNG rng(now()); + int intLevel = int(Options["Skill Level"]) + + ((Options["Skill Level"] - int(Options["Skill Level"])) * 1024 > rng.rand() % 1024 ? 1 : 0); + Skill skill(intLevel); // When playing with strength handicap enable MultiPV search that we will // use behind the scenes to retrieve a set of possible moves. From fa1a2a0667ff81f04e94cab078c50c2d51f4cb5e Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Thu, 11 Jul 2019 09:12:54 +1000 Subject: [PATCH 029/281] Enable popcount and prefetch for ppc-64 PowerPC has had popcount instructions for a long time, at least as far back as POWER5 (released 2004). Enable them via a gcc builtin. Using a gcc builtin has the added bonus that if compiled for a processor that lacks a hardware instruction, gcc will include a software popcount implementation that does not use the instruction. It might be slower than the table lookups (or it might be faster) but it will certainly work. So this isn't going to break anything. On my POWER8 VM, this leads to a ~4.27% speedup. Fir prefetch, the gcc builtin generates a 'dcbt' instruction, which is supported at least as far back as the G5 (2002) and POWER4 (2001). This leads to a ~5% speedup on my POWER8 VM. No functional change --- src/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 2d6042e2..285d314e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -136,6 +136,8 @@ endif ifeq ($(ARCH),ppc-64) arch = ppc64 bits = 64 + popcnt = yes + prefetch = yes endif @@ -313,7 +315,9 @@ endif ### 3.6 popcnt ifeq ($(popcnt),yes) - ifeq ($(comp),icc) + ifeq ($(arch),ppc64) + CXXFLAGS += -DUSE_POPCNT + else ifeq ($(comp),icc) CXXFLAGS += -msse3 -DUSE_POPCNT else CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT From 93349d0dbd22f063b39e6815c02835a4748fffbc Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 9 Jul 2019 14:03:00 -0600 Subject: [PATCH 030/281] Use score instead of array to evaluate shelter This is a non-functional simplification. Instead of an array of values, just use a Score. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 16309 W: 3673 L: 3541 D: 9095 http://tests.stockfishchess.org/tests/view/5d24f3b80ebc5925cf0ceb5b No functional change --- src/pawns.cpp | 14 +++++++------- src/search.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index c85d4fd9..acc3d770 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -181,13 +181,13 @@ Entry* probe(const Position& pos) { template void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us); Bitboard theirPawns = b & pos.pieces(Them); - Value bonus[] = { Value(5), Value(5) }; + Score bonus = make_score(5, 5); File center = clamp(file_of(ksq), FILE_B, FILE_G); for (File f = File(center - 1); f <= File(center + 1); ++f) @@ -199,16 +199,16 @@ void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; int d = std::min(f, ~f); - bonus[MG] += ShelterStrength[d][ourRank]; + bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) - bonus[MG] -= 82 * (theirRank == RANK_3), bonus[EG] -= 82 * (theirRank == RANK_3); + bonus -= make_score(82 * (theirRank == RANK_3), 82 * (theirRank == RANK_3)); else - bonus[MG] -= UnblockedStorm[d][theirRank]; + bonus -= make_score(UnblockedStorm[d][theirRank], 0); } - if (bonus[MG] > mg_value(shelter)) - shelter = make_score(bonus[MG], bonus[EG]); + if (mg_value(bonus) > mg_value(shelter)) + shelter = bonus; } diff --git a/src/search.cpp b/src/search.cpp index b4a69092..8993a4b0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1070,7 +1070,7 @@ moves_loop: // When in check, search starts from here Depth r = reduction(improving, depth, moveCount); // Reduction if other threads are searching this position. - if (th.marked()) + if (th.marked()) r += ONE_PLY; // Decrease reduction if position is or has been on the PV From 5a7827d59de5e3dea0d90bdb3e7c57153c0a9f1f Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sun, 7 Jul 2019 02:20:49 +0100 Subject: [PATCH 031/281] Combo of statscore divisor and pawn psqt changes Passed STC 10+0.1 th 1: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 13282 W: 3100 L: 2881 D: 7301 http://tests.stockfishchess.org/tests/view/5d21132e0ebc5925cf0c81f4 Passed LTC 60+0.6 th 1: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 44243 W: 7768 L: 7468 D: 29007 http://tests.stockfishchess.org/tests/view/5d2119050ebc5925cf0c832b Bench 3705891 --- src/psqt.cpp | 12 ++++++------ src/search.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/psqt.cpp b/src/psqt.cpp index cba6bb06..36d99feb 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -93,12 +93,12 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { constexpr Score PBonus[RANK_NB][FILE_NB] = { // Pawn (asymmetric distribution) { }, - { S( 0,-10), S( -5,-3), S( 10, 7), S( 13,-1), S( 21, 7), S( 17, 6), S( 6, 1), S( -3,-20) }, - { S(-11, -6), S(-10,-6), S( 15,-1), S( 22,-1), S( 26, -1), S( 28, 2), S( 4,-2), S(-24, -5) }, - { S( -9, 4), S(-18,-5), S( 8,-4), S( 22,-5), S( 33, -6), S( 25,-13), S( -4,-3), S(-16, -7) }, - { S( 6, 18), S( -3, 2), S(-10, 2), S( 1,-9), S( 12,-13), S( 6, -8), S(-12,11), S( 1, 9) }, - { S( -6, 25), S( -8,17), S( 5,19), S( 11,29), S(-14, 29), S( 0, 8), S(-12, 4), S(-14, 12) }, - { S(-10, -1), S( 6,-6), S( -5,18), S(-11,22), S( -2, 22), S(-14, 17), S( 12, 2), S( -1, 9) } + { S( 3,-10), S( 3, -6), S( 10, 10), S( 19, 0), S( 16, 14), S( 19, 7), S( 7, -5), S( -5,-19) }, + { S( -9,-10), S(-15,-10), S( 11,-10), S( 15, 4), S( 32, 4), S( 22, 3), S( 5, -6), S(-22, -4) }, + { S( -8, 6), S(-23, -2), S( 6, -8), S( 20, -4), S( 40,-13), S( 17,-12), S( 4,-10), S(-12, -9) }, + { S( 13, 9), S( 0, 4), S(-13, 3), S( 1,-12), S( 11,-12), S( -2, -6), S(-13, 13), S( 5, 8) }, + { S( -5, 28), S(-12, 20), S( -7, 21), S( 22, 28), S( -8, 30), S( -5, 7), S(-15, 6), S(-18, 13) }, + { S( -7, 0), S( 7,-11), S( -3, 12), S(-13, 21), S( 5, 25), S(-16, 19), S( 10, 4), S( -8, 7) } }; #undef S diff --git a/src/search.cpp b/src/search.cpp index 8993a4b0..ff7a2c23 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1115,7 +1115,7 @@ moves_loop: // When in check, search starts from here r += ONE_PLY; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 20000 * ONE_PLY; + r -= ss->statScore / 16384 * ONE_PLY; } Depth d = clamp(newDepth - r, ONE_PLY, newDepth); From c83cbe42f3a6c9b145a4557ef874222fe685a9bc Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Wed, 10 Jul 2019 19:59:33 -0400 Subject: [PATCH 032/281] Tweak capture scoring formula STC: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 20556 W: 4685 L: 4438 D: 11433 http://tests.stockfishchess.org/tests/view/5d25d26e0ebc5925cf0d0b4a LTC: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 14856 W: 2649 L: 2446 D: 9761 http://tests.stockfishchess.org/tests/view/5d25d8b20ebc5925cf0d0c6d bench: 3206912 --- src/movepick.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index b7f66178..64380da9 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -107,8 +107,8 @@ void MovePicker::score() { for (auto& m : *this) if (Type == CAPTURES) - m.value = PieceValue[MG][pos.piece_on(to_sq(m))] - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))] / 8; + m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6 + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; else if (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] From 4ae5a7b45a430aea5f4b21f9455b4db74ed1c44a Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 9 Jun 2019 15:07:36 +0200 Subject: [PATCH 033/281] Assorted trivial cleanups June 2019 No functional change. --- src/evaluate.cpp | 10 +++++----- src/pawns.cpp | 18 ++++++++++-------- src/position.cpp | 6 +++--- src/position.h | 5 +++++ src/search.cpp | 12 ++++++------ 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f2e822d0..c4e02e4e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -142,7 +142,7 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 36, 12); + constexpr Score Outpost = S( 18, 6); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnPawn = S( 10, 32); @@ -222,7 +222,7 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); - constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB); + constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); const Square ksq = pos.square(Us); @@ -305,10 +305,10 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost * (Pt == KNIGHT ? 2 : 1); + score += Outpost * (Pt == KNIGHT ? 4 : 2); else if (bb & b & ~pos.pieces(Us)) - score += Outpost / (Pt == KNIGHT ? 1 : 2); + score += Outpost * (Pt == KNIGHT ? 2 : 1); // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) @@ -561,7 +561,7 @@ namespace { b &= ~attackedBy[Them][PAWN] & safe; // Bonus for safe pawn threats on the next move - b = pawn_attacks_bb(b) & pos.pieces(Them); + b = pawn_attacks_bb(b) & nonPawnEnemies; score += ThreatByPawnPush * popcount(b); // Our safe or protected pawns diff --git a/src/pawns.cpp b/src/pawns.cpp index acc3d770..45c40471 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,9 +32,9 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 9, 24); - constexpr Score Doubled = S(11, 56); - constexpr Score Isolated = S( 5, 15); + constexpr Score Backward = S( 9, 24); + constexpr Score Doubled = S(11, 56); + constexpr Score Isolated = S( 5, 15); constexpr Score WeakUnopposed = S( 13, 27); constexpr Score Attacked2Unsupported = S( 0, 20); @@ -108,17 +108,18 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - // A pawn is backward when it is behind all pawns of the same color - // on the adjacent files and cannot be safely advanced. - backward = !(ourPawns & pawn_attack_span(Them, s + Up)) + // A pawn is backward when it is behind all pawns of the same color on + // the adjacent files and cannot safely advance. Phalanx and isolated + // pawns will be excluded when the pawn is scored. + backward = !(neighbours & forward_ranks_bb(Them, s)) && (stoppers & (leverPush | (s + Up))); // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate them. Include also not passed pawns // which could become passed after one or two pawn pushes when are // not attacked more times than defended. - if ( !(stoppers ^ lever) || - (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush))) + if ( !(stoppers ^ lever) || + (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush))) e->passedPawns[Us] |= s; else if (stoppers == square_bb(s + Up) && r >= RANK_5) @@ -137,6 +138,7 @@ namespace { score += make_score(v, v * (r - 2) / 4); } + else if (!neighbours) score -= Isolated + WeakUnopposed * int(!opposed); diff --git a/src/position.cpp b/src/position.cpp index 14121d47..9f06e174 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -55,13 +55,13 @@ constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING // 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 +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); + return min_attacker(byTypeBB, to, stmAttackers, occupied, attackers); occupied ^= lsb(b); // Remove the attacker from occupied @@ -77,7 +77,7 @@ PieceType min_attacker(const Bitboard* byTypeBB, Square to, Bitboard stmAttacker // 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 (PieceType)Pt; + return Pt; } template<> diff --git a/src/position.h b/src/position.h index 343751ed..2106414b 100644 --- a/src/position.h +++ b/src/position.h @@ -108,6 +108,7 @@ public: Bitboard checkers() const; Bitboard blockers_for_king(Color c) const; Bitboard check_squares(PieceType pt) const; + bool is_discovery_check_on_king(Color c, Move m) const; // Attacks to/from a given square Bitboard attackers_to(Square s) const; @@ -316,6 +317,10 @@ inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; } +inline bool Position::is_discovery_check_on_king(Color c, Move m) const { + return st->blockersForKing[c] & from_sq(m); +} + inline bool Position::pawn_passed(Color c, Square s) const { return !(pieces(~c, PAWN) & passed_pawn_span(c, s)); } diff --git a/src/search.cpp b/src/search.cpp index ff7a2c23..e6446768 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -739,7 +739,7 @@ namespace { } else if (ttHit) { - // Never assume anything on values stored in TT + // Never assume anything about values stored in TT ss->staticEval = eval = tte->eval(); if (eval == VALUE_NONE) ss->staticEval = eval = evaluate(pos); @@ -978,7 +978,7 @@ moves_loop: // When in check, search starts from here // Check extension (~2 Elo) else if ( givesCheck - && (pos.blockers_for_king(~us) & from_sq(move) || pos.see_ge(move))) + && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))) extension = ONE_PLY; // Castling extension @@ -1013,7 +1013,7 @@ 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 (~30 Elo) + // Move count based pruning if (moveCountPruning) continue; @@ -1037,8 +1037,8 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth))) continue; } - else if ((!givesCheck || !extension) - && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) + else if ( (!givesCheck || !extension) + && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) continue; } @@ -1341,7 +1341,7 @@ moves_loop: // When in check, search starts from here { if (ttHit) { - // Never assume anything on values stored in TT + // Never assume anything about values stored in TT if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) ss->staticEval = bestValue = evaluate(pos); From 82d66f6b72c656a3efc4fd54b6eb489a8f74a945 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Thu, 11 Jul 2019 09:14:57 -0400 Subject: [PATCH 034/281] Exclude passed pawns from Attacked2Unsupported We recently added a bonus for double pawn attacks on unsupported enemy pawns, on June 27. However, it is possible that the unsupported pawn may become a passer by simply pushing forward out of the double attack. By rewarding double attacks, we may inadvertently reward the creation of enemy passers, by encouraging both of our would-be stoppers to attack the enemy pawn even if there is no opposing friendly pawn on the same file. Here, we revise this term to exclude passed pawns. In order to simplify the code with this change included, we non-functionally rewrite Attacked2Unsupported to be a penalty for enemy attacks on friendly pawns, rather than a bonus for our attacks on enemy pawns. This allows us to exclude passed pawns with a simple & ~e->passedPawns[Us], while passedPawns[Them] is not yet defined in this part of the code. This dramatically reduces the proportion of positions in which Attacked2Unsupported is applied, to about a third of the original. To compensate, maintaining the same average effect across our bench positions, we nearly triple Attacked2Unsupported from S(0, 20) to S(0, 56). Although this pawn formation is rare, it is worth more than half a pawn in the endgame! STC: (stopped automatically by fishtest after 250,000 games) LLR: -0.87 (-2.94,2.94) [0.50,4.50] Total: 250000 W: 56585 L: 55383 D: 138032 http://tests.stockfishchess.org/tests/view/5d25795e0ebc5925cf0cfb51 LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 81038 W: 13965 L: 13558 D: 53515 http://tests.stockfishchess.org/tests/view/5d25f3920ebc5925cf0d10dd Closes https://github.com/official-stockfish/Stockfish/pull/2233 Bench: 3765158 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c4e02e4e..a52cdf09 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -655,7 +655,7 @@ namespace { !(unsafeSquares & blockSq) ? 9 : 0 ; - // Assign a larger bonus if the block square is defended. + // Assign a larger bonus if the block square is defended if (defendedSquares & blockSq) k += 5; diff --git a/src/pawns.cpp b/src/pawns.cpp index 45c40471..0d3a57bf 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -35,8 +35,8 @@ namespace { constexpr Score Backward = S( 9, 24); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); - constexpr Score WeakUnopposed = S( 13, 27); - constexpr Score Attacked2Unsupported = S( 0, 20); + constexpr Score WeakUnopposed = S(13, 27); + constexpr Score Attacked2Unsupported = S(0, 56); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -84,11 +84,6 @@ namespace { e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); - // Unsupported enemy pawns attacked twice by us - score += Attacked2Unsupported * popcount( theirPawns - & pawn_double_attacks_bb(ourPawns) - & ~pawn_attacks_bb(theirPawns)); - // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) { @@ -116,8 +111,8 @@ namespace { // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate them. Include also not passed pawns - // which could become passed after one or two pawn pushes when are - // not attacked more times than defended. + // which could become passed after one or two pawn pushes when they + // are not attacked more times than defended. if ( !(stoppers ^ lever) || (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush))) e->passedPawns[Us] |= s; @@ -149,6 +144,12 @@ namespace { score -= Doubled; } + // Unsupported friendly pawns attacked twice by the enemy + score -= Attacked2Unsupported * popcount( ourPawns + & pawn_double_attacks_bb(theirPawns) + & ~pawn_attacks_bb(ourPawns) + & ~e->passedPawns[Us]); + return score; } From 389e60741f308bb23904baec0d52552935162e0f Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 12 Jul 2019 07:22:46 +0200 Subject: [PATCH 035/281] Late Move reduction and continuation history Update continuation history after LMR-triggered full depth research. Directly after a LMR-triggered full depth research, we update the continuation history for quiet moves (but with only half stat bonus). STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 39657 W: 8966 L: 8604 D: 22087 http://tests.stockfishchess.org/tests/view/5d279fa40ebc5925cf0d4566 LTC: LLR: 2.96 (-2.94,2.94) [0.50,3.50] Total: 32582 W: 5740 L: 5427 D: 21415 http://tests.stockfishchess.org/tests/view/5d27dbf90ebc5925cf0d4b7e Bench: 3239357 --- src/search.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e6446768..ea0c64f1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -578,7 +578,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving; + bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount, singularLMR; @@ -1122,15 +1122,26 @@ moves_loop: // When in check, search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && d != newDepth); + doFullDepthSearch = (value > alpha && d != newDepth), doLMR = true; } else - doFullDepthSearch = !PvNode || moveCount > 1; + doFullDepthSearch = !PvNode || moveCount > 1, doLMR = 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) + { + int bonus = stat_bonus(newDepth) / 2; + if (value <= alpha) + bonus = -bonus; + + update_continuation_histories(ss, movedPiece, to_sq(move), bonus); + } + } + // For PV nodes only, do a full PV search on the first move or after a fail // high (in the latter case search only if value < beta), otherwise let the // parent node fail low with value <= alpha and try another move. From ff69d570d774c465b63ed65f8f14afdaac4eb107 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 12 Jul 2019 10:17:24 +0200 Subject: [PATCH 036/281] Full bonus for LMR stats update Simplify previous commit by using the full bonus for LMR-triggered stats update. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 23684 W: 5255 L: 5137 D: 13292 http://tests.stockfishchess.org/tests/view/5d2826660ebc5925cf0d5180 LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 16245 W: 2832 L: 2704 D: 10709 http://tests.stockfishchess.org/tests/view/5d282e9c0ebc5925cf0d529b Closes https://github.com/official-stockfish/Stockfish/pull/2236 Bench: 3361902 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ea0c64f1..bd5ae75e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1134,9 +1134,8 @@ moves_loop: // When in check, search starts from here if (doLMR && !captureOrPromotion) { - int bonus = stat_bonus(newDepth) / 2; - if (value <= alpha) - bonus = -bonus; + int bonus = value > alpha ? stat_bonus(newDepth) + : -stat_bonus(newDepth); update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } From a0360cc2d4397edaad590cdf131fef95915b55c0 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sun, 14 Jul 2019 08:40:45 -0400 Subject: [PATCH 037/281] Linear formula for w. Bench: 3328507 (#2239) In Stockfish, both the middlegame and endgame bonus for a passed pawn are calculated as a product of two factors. The first is k, chosen based on the presence of defended and unsafe squares. The second is w, a quadratic function of the pawn's rank. Both are only applied if the pawn's relative rank is at least RANK_4. It does not appear that the complexity of a quadratic function is necessary for w. Here, we replace it with a simpler linear one, which performs equally at both STC and LTC. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 46814 W: 10386 L: 10314 D: 26114 http://tests.stockfishchess.org/tests/view/5d29686e0ebc5925cf0d76a1 LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 82372 W: 13845 L: 13823 D: 54704 http://tests.stockfishchess.org/tests/view/5d2980650ebc5925cf0d7bfd Bench: 3328507 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a52cdf09..b20c93b7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -622,7 +622,7 @@ namespace { if (r > RANK_3) { - int w = (r-2) * (r-2) + 2; + int w = 5 * r - 13; Square blockSq = s + Up; // Adjust bonus based on the king's proximity From 0a8a3b8d9c1936c75a71d899d4bbfd6839621318 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 14 Jul 2019 15:41:28 +0300 Subject: [PATCH 038/281] tviigg. (#2238) Current master code made sence when we had 2 types of bonuses for protected path to queen. But it was simplified so we have only one bonus now and code was never cleaned. This non-functional simplification removes useless defendedsquares bitboard and removes one bitboard assignment (defendedSquares &= attackedBy[Us][ALL_PIECES] + defendedSquares & blockSq becomes just attackedBy[Us][ALL_PIECES] & blockSq also we never assign defendedSquares = squaresToQueen because we don't need it). So should be small non-functional speedup. Passed simplification SPRT. http://tests.stockfishchess.org/tests/view/5d2966ef0ebc5925cf0d7659 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23319 W: 5152 L: 5034 D: 13133 bench 3361902 --- src/evaluate.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index b20c93b7..8b017a5c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -605,7 +605,7 @@ namespace { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, defendedSquares, unsafeSquares; + Bitboard b, bb, squaresToQueen, unsafeSquares; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); @@ -636,14 +636,11 @@ namespace { // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) { - defendedSquares = squaresToQueen = forward_file_bb(Us, s); + squaresToQueen = forward_file_bb(Us, s); unsafeSquares = passed_pawn_span(Us, s); bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); - if (!(pos.pieces(Us) & bb)) - defendedSquares &= attackedBy[Us][ALL_PIECES]; - if (!(pos.pieces(Them) & bb)) unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); @@ -656,7 +653,7 @@ namespace { 0 ; // Assign a larger bonus if the block square is defended - if (defendedSquares & blockSq) + if ((pos.pieces(Us) & bb) || (attackedBy[Us][ALL_PIECES] & blockSq)) k += 5; bonus += make_score(k * w, k * w); From 13ba67801f0331e3ffde23794b989765af5a9aa2 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sun, 14 Jul 2019 08:42:30 -0400 Subject: [PATCH 039/281] Just blockSq, not forward file. Bench: 3377831 (#2240) This is another functional simplification to Stockfish passed pawn evaluation. Stockfish evaluates some pawns which are not yet passed as "candidate" passed pawns, which are given half the bonus of fully passed ones. Prior to this commit, Stockfish considered a passed pawn to be a "candidate" if (a) it would not be a passed pawn if moved one square forward (the blocking square), or (b) there were other pawns (of either color) in front of it on the file. This latter condition used a fairly complicated method, forward_file_bb; here, rather than inspect the entire forward file, we simply re-use the blocking square. As a result, some pawns previously considered "candidates", but which are able to push forward, no longer have their bonus halved. Simplification tests passed quickly at both STC and LTC. The results from both tests imply that this simplification is, most likely, additionally a small Elo gain, with a LTC likelihood of superiority of 87 percent. STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 12908 W: 2909 L: 2770 D: 7229 http://tests.stockfishchess.org/tests/view/5d2a1c880ebc5925cf0d9006 LTC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 20723 W: 3591 L: 3470 D: 13662 http://tests.stockfishchess.org/tests/view/5d2a21fd0ebc5925cf0d9118 Bench: 3377831 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8b017a5c..9a67a8e4 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -663,7 +663,7 @@ namespace { // Scale down bonus for candidate passers which need more than one // pawn push to become passed, or have a pawn in front of them. if ( !pos.pawn_passed(Us, s + Up) - || (pos.pieces(PAWN) & forward_file_bb(Us, s))) + || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; score += bonus + PassedFile[file_of(s)]; From 650aeaf2420bdac00de03963132d82a415193a1c Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 14 Jul 2019 06:46:10 -0600 Subject: [PATCH 040/281] Remove std::pow from reduction. (#2234) This is a functional simplification that removes the std::pow from reduction. The resulting reduction values are within 1% of master. This is a simplification because i believe an fp addition and multiplication is much faster than a call to std::pow() which is historically slow and performance varies widely on different architectures. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23471 W: 5245 L: 5127 D: 13099 http://tests.stockfishchess.org/tests/view/5d27ac1b0ebc5925cf0d476b LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 51533 W: 8736 L: 8665 D: 34132 http://tests.stockfishchess.org/tests/view/5d27b74e0ebc5925cf0d493c Bench 3765158 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index bd5ae75e..df19108f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -503,7 +503,7 @@ void Thread::search() { // If the bestMove is stable over several iterations, reduce time accordingly timeReduction = lastBestMoveDepth + 10 * ONE_PLY < completedDepth ? 1.95 : 1.0; - double reduction = std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction; + double reduction = (1.25 + mainThread->previousTimeReduction) / (2.25 * timeReduction); // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) From 0dbc72d82e7f5f314499b22a04dcef45edcdba9a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 14 Jul 2019 14:47:50 +0200 Subject: [PATCH 041/281] UCI_Elo implementation (#2225) This exploits the recent fractional Skill Level, and is a result from some discussion in #2221 and the older #758. Basically, if UCI_LimitStrength is set, it will internally convert UCI_Elo to a matching fractional Skill Level. The Elo estimate is based on games at TC 60+0.6, Hash 64Mb, 8moves_v3.pgn, rated with Ordo, anchored to goldfish1.13 (CCRL 40/4 ~2000). Note that this is mostly about internal consistency, the anchoring to CCRL is a bit weak, e.g. within this tournament, goldfish and sungorus only have a 200Elo difference, their rating difference on CCRL is 300Elo. I propose that we continue to expose 'Skill Level' as an UCI option, for backwards compatibility. The result of a tournament under those conditions are given by the following table, where the player name reflects the UCI_Elo. # PLAYER : RATING ERROR POINTS PLAYED (%) CFS(%) 1 Elo2837 : 2792.2 50.8 536.5 711 75 100 2 Elo2745 : 2739.0 49.0 487.5 711 69 100 3 Elo2654 : 2666.4 49.2 418.0 711 59 100 4 Elo2562 : 2604.5 38.5 894.5 1383 65 100 5 Elo2471 : 2515.2 38.1 651.5 924 71 100 6 Elo2380 : 2365.9 35.4 478.5 924 52 100 7 Elo2289 : 2290.0 28.0 864.0 1596 54 100 8 sungorus1.4 : 2204.9 27.8 680.5 1596 43 60 9 Elo2197 : 2201.1 30.1 523.5 924 57 100 10 Elo2106 : 2103.8 24.5 730.5 1428 51 100 11 Elo2014 : 2030.5 30.3 377.5 756 50 98 12 goldfish1.13 : 2000.0 ---- 511.0 1428 36 100 13 Elo1923 : 1928.5 30.9 641.5 1260 51 100 14 Elo1831 : 1829.0 42.1 370.5 756 49 100 15 Elo1740 : 1738.3 42.9 277.5 756 37 100 16 Elo1649 : 1625.0 42.1 525.5 1260 42 100 17 Elo1558 : 1521.5 49.9 298.0 756 39 100 18 Elo1467 : 1471.3 51.3 246.5 756 33 100 19 Elo1375 : 1407.1 51.9 183.0 756 24 --- It can be observed that all set Elos correspond within the error bars with the observed Ordo rating. No functional change --- Readme.md | 11 ++++++++++- src/search.cpp | 13 ++++++++++--- src/ucioption.cpp | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index be324763..10ffdeae 100644 --- a/Readme.md +++ b/Readme.md @@ -55,7 +55,16 @@ Currently, Stockfish has the following UCI options: Leave at 1 for best performance. * #### Skill Level - Lower the Skill Level in order to make Stockfish play weaker. + Lower the Skill Level in order to make Stockfish play weaker (see also UCI_LimitStrength). + Internally, MultiPV is enabled, and with a certain probability depending on the Skill Level a + weaker move will be played. + + * #### UCI_LimitStrength + Enable weaker play aiming for an Elo rating as set by UCI_Elo. This option overrides Skill Level. + + * #### UCI_Elo + If enabled by UCI_LimitStrength, aim for an engine strength of the given Elo. + This Elo rating has been calibrated at a time control of 60s+0.6s and anchored to CCRL 40/4. * #### Move Overhead Assume a time delay of x ms due to network and GUI overheads. This is useful to diff --git a/src/search.cpp b/src/search.cpp index df19108f..2c2321ee 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -271,7 +271,7 @@ void MainThread::search() { // Check if there are threads with a better score than main thread if ( Options["MultiPV"] == 1 && !Limits.depth - && !Skill(Options["Skill Level"]).enabled() + && !(Skill(Options["Skill Level"]).enabled() || Options["UCI_LimitStrength"]) && rootMoves[0].pv[0] != MOVE_NONE) { std::map votes; @@ -335,11 +335,18 @@ void Thread::search() { beta = VALUE_INFINITE; multiPV = Options["MultiPV"]; + // Pick integer skill levels, but non-deterministically round up or down // such that the average integer skill corresponds to the input floating point one. + // UCI_Elo is converted to a suitable fractional skill level, using anchoring + // to CCRL Elo (goldfish 1.13 = 2000) and a fit through Ordo derived Elo + // for match (TC 60+0.6) results spanning a wide range of k values. PRNG rng(now()); - int intLevel = int(Options["Skill Level"]) + - ((Options["Skill Level"] - int(Options["Skill Level"])) * 1024 > rng.rand() % 1024 ? 1 : 0); + double floatLevel = Options["UCI_LimitStrength"] ? + clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : + double(Options["Skill Level"]); + int intLevel = int(floatLevel) + + ((floatLevel - int(floatLevel)) * 1024 > rng.rand() % 1024 ? 1 : 0); Skill skill(intLevel); // When playing with strength handicap enable MultiPV search that we will diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 813a0890..23c0c480 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -74,6 +74,8 @@ void init(OptionsMap& o) { o["nodestime"] << Option(0, 0, 10000); o["UCI_Chess960"] << Option(false); o["UCI_AnalyseMode"] << Option(false); + o["UCI_LimitStrength"] << Option(false); + o["UCI_Elo"] << Option(1350, 1350, 2850); o["SyzygyPath"] << Option("", on_tb_path); o["SyzygyProbeDepth"] << Option(1, 1, 100); o["Syzygy50MoveRule"] << Option(true); From 3ec362e4b299128b91d961250b444d930b4c60fa Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sun, 14 Jul 2019 13:13:06 -0400 Subject: [PATCH 043/281] Space Invaders Try a more ambitius simplification of the space bonus STC http://tests.stockfishchess.org/tests/view/5d2b62c90ebc5925cf0da2a4 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 51299 W: 11320 L: 11257 D: 28722 LTC http://tests.stockfishchess.org/tests/view/5d2bac270ebc5925cf0db215 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 49761 W: 8409 L: 8335 D: 33017 Closes https://github.com/official-stockfish/Stockfish/pull/2243 bench: 3395999 --- src/evaluate.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9a67a8e4..10dddc7d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -133,7 +133,6 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score AttacksOnSpaceArea = S( 4, 0); constexpr Score BishopPawns = S( 3, 7); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@ -705,12 +704,10 @@ namespace { behind |= shift(behind); behind |= shift(behind); - int bonus = popcount(safe) + popcount(behind & safe); + int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); int weight = pos.count(Us) - 1; Score score = make_score(bonus * weight * weight / 16, 0); - score -= AttacksOnSpaceArea * popcount(attackedBy[Them][ALL_PIECES] & behind & safe); - if (T) Trace::add(SPACE, Us, score); From 19509e5f1313e3693a7ee56531326eed3c62a1af Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 16 Jul 2019 14:56:52 +0300 Subject: [PATCH 044/281] Tweak LMR and killers Give extra stat bonus/malus in case of LMR for killers. passed STC http://tests.stockfishchess.org/tests/view/5d2c8e760ebc5925cf0dcf23 LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 67188 W: 15030 L: 14534 D: 37624 passed LTC http://tests.stockfishchess.org/tests/view/5d2d0ce40ebc5925cf0de115 LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 144355 W: 24739 L: 24153 D: 95463 Closes https://github.com/official-stockfish/Stockfish/pull/2246 bench 3723147 --- src/search.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 2c2321ee..1fc0bf1e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1144,6 +1144,9 @@ moves_loop: // When in check, search starts from here int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); + if (move == ss->killers[0]) + bonus += bonus / 4; + update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } } From fd96cba67603c9c2462d41887f79d4b6ac8920b1 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Tue, 16 Jul 2019 10:14:09 +0200 Subject: [PATCH 045/281] No influence on unsafeSquares of passers by pieces Remove their pieces from influencing 'unsafeSquares' in passer evaluation. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 36421 W: 8170 L: 8078 D: 20173 http://tests.stockfishchess.org/tests/view/5d22fc8e0ebc5925cf0cb26e LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 18927 W: 3253 L: 3129 D: 12545 http://tests.stockfishchess.org/tests/view/5d26e2b20ebc5925cf0d3218 Closes https://github.com/official-stockfish/Stockfish/pull/2248 Bench: 3285659 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 10dddc7d..23af60f3 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -641,7 +641,7 @@ namespace { bb = forward_file_bb(Them, s) & pos.pieces(ROOK, QUEEN); if (!(pos.pieces(Them) & bb)) - unsafeSquares &= attackedBy[Them][ALL_PIECES] | pos.pieces(Them); + unsafeSquares &= attackedBy[Them][ALL_PIECES]; // If there are no enemy attacks on passed pawn span, assign a big bonus. // Otherwise assign a smaller bonus if the path to queen is not attacked From 9dc57b660eb22190166c006eb99319c2b321e4f7 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 20 Jul 2019 11:38:45 -0400 Subject: [PATCH 046/281] Passed file cleanup Protonspring had a successful functional simplification that removes the PassedFile array using a simple linear equation. Merge the additive term S(5, 10) of protonspring passed file simplification (pull request https://github.com/official-stockfish/Stockfish/pull/2250) into the PassedRank array. This harmless change has a different bench because the candidate passer evaluation will always get less compared to #2250, as we apply bonus = bonus /2. Tested as a non-regression against #2250 Passed STC http://tests.stockfishchess.org/tests/view/5d33427e0ebc5925cf0e6fa2 LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 81459 W: 18174 L: 18171 D: 45114 Passed LTC http://tests.stockfishchess.org/tests/view/5d335c8d0ebc5925cf0e731e LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 18525 W: 3176 L: 3052 D: 12297 Closes https://github.com/official-stockfish/Stockfish/pull/2250 Closes https://github.com/official-stockfish/Stockfish/pull/2251 Bench: 3859856 --- src/evaluate.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 23af60f3..7359eb92 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -123,13 +123,7 @@ namespace { // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(5, 18), S(12, 23), S(10, 31), S(57, 62), S(163, 167), S(271, 250) - }; - - // PassedFile[File] contains a bonus according to the file of a passed pawn - constexpr Score PassedFile[FILE_NB] = { - S( -1, 7), S( 0, 9), S(-9, -8), S(-30,-14), - S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7) + S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; // Assorted bonuses and penalties @@ -142,6 +136,7 @@ namespace { constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); constexpr Score Outpost = S( 18, 6); + constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnPawn = S( 10, 32); @@ -616,6 +611,7 @@ 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]; @@ -665,7 +661,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus + PassedFile[file_of(s)]; + score += bonus - PassedFile * std::min(f, ~f); } if (T) From dc243a3c880d0a736fb93848cf56e3221e07f8a3 Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Sun, 21 Jul 2019 11:25:58 -0400 Subject: [PATCH 047/281] LMR Tweak Reset statScore to zero if negative and most stats shows >= 0 STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 23097 W: 5242 L: 4963 D: 12892 http://tests.stockfishchess.org/tests/view/5d31dd650ebc5925cf0e598f LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 227597 W: 39013 L: 38191 D: 150393 http://tests.stockfishchess.org/tests/view/5d31fcdf0ebc5925cf0e5c13 Closes https://github.com/official-stockfish/Stockfish/pull/2252 Bench: 3242229 --- src/search.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 1fc0bf1e..f50fdf88 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1114,6 +1114,13 @@ moves_loop: // When in check, search starts from here + (*contHist[3])[movedPiece][to_sq(move)] - 4000; + // Reset statScore to zero if negative and most stats shows >= 0 + if ( ss->statScore < 0 + && (*contHist[0])[movedPiece][to_sq(move)] >= 0 + && (*contHist[1])[movedPiece][to_sq(move)] >= 0 + && thisThread->mainHistory[us][from_to(move)] >= 0) + ss->statScore = 0; + // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) if (ss->statScore >= 0 && (ss-1)->statScore < 0) r -= ONE_PLY; From 33c3a0465358116560174ae7421144be714e43f9 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Thu, 25 Jul 2019 09:02:26 +0200 Subject: [PATCH 048/281] Pawn clean up Non functional simplification when we find the passed pawns in pawn.cpp and some code clean up. It also better follows the pattern "flag the pawn" and "score the pawn". ------------------------- The idea behind the third condition for candidate passed pawn is a little bit difficult to visualize. Just for the record, the idea is the following: Consider White e5 d4 against black e6. d4 can (in some endgames) push to d5 and lever e6. Thanks to this sacrifice, or after d5xe6, we consider e5 as "passed". However: - if White e5/d4 against black e6/c6: d4 cannot safely push to d5 since d5 is double attacked; - if White e5/d4 against black e6/d5: d4 cannot safely push to d5 since it is occupied. This is exactly what the following expression does: ``` && (shift(support) & ~(theirPawns | dblAttackThem))) ``` -------------------------- http://tests.stockfishchess.org/tests/view/5d3325bb0ebc5925cf0e6e91 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 124666 W: 27586 L: 27669 D: 69411 Closes https://github.com/official-stockfish/Stockfish/pull/2255 No functional change --- src/pawns.cpp | 43 ++++++++++++++++++++++--------------------- src/search.cpp | 2 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 0d3a57bf..9755c2ec 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -35,8 +35,8 @@ namespace { constexpr Score Backward = S( 9, 24); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); + constexpr Score WeakLever = S( 0, 56); constexpr Score WeakUnopposed = S(13, 27); - constexpr Score Attacked2Unsupported = S(0, 56); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -73,13 +73,15 @@ namespace { Bitboard b, neighbours, stoppers, doubled, support, phalanx; Bitboard lever, leverPush; Square s; - bool opposed, backward; + bool opposed, backward, passed; Score score = SCORE_ZERO; const Square* pl = pos.squares(Us); Bitboard ourPawns = pos.pieces( Us, PAWN); Bitboard theirPawns = pos.pieces(Them, PAWN); + Bitboard doubleAttackThem = pawn_double_attacks_bb(theirPawns); + e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); @@ -109,21 +111,20 @@ namespace { backward = !(neighbours & forward_ranks_bb(Them, s)) && (stoppers & (leverPush | (s + Up))); - // Passed pawns will be properly scored in evaluation because we need - // full attack info to evaluate them. Include also not passed pawns - // which could become passed after one or two pawn pushes when they - // are not attacked more times than defended. - if ( !(stoppers ^ lever) || - (!(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush))) - e->passedPawns[Us] |= s; + // A pawn is passed if one of the three following conditions is true: + // (a) there is no stoppers except some levers + // (b) the only stoppers are the leverPush, but we outnumber them + // (c) there is only one front stopper which can be levered. + passed = !(stoppers ^ lever) + || ( !(stoppers ^ leverPush) + && popcount(phalanx) >= popcount(leverPush)) + || ( stoppers == square_bb(s + Up) && r >= RANK_5 + && (shift(support) & ~(theirPawns | doubleAttackThem))); - else if (stoppers == square_bb(s + Up) && r >= RANK_5) - { - b = shift(support) & ~theirPawns; - while (b) - if (!more_than_one(theirPawns & PawnAttacks[Us][pop_lsb(&b)])) - e->passedPawns[Us] |= s; - } + // Passed pawns will be properly scored later in evaluation when we have + // full attack info. + if (passed) + e->passedPawns[Us] |= s; // Score this pawn if (support | phalanx) @@ -144,11 +145,11 @@ namespace { score -= Doubled; } - // Unsupported friendly pawns attacked twice by the enemy - score -= Attacked2Unsupported * popcount( ourPawns - & pawn_double_attacks_bb(theirPawns) - & ~pawn_attacks_bb(ourPawns) - & ~e->passedPawns[Us]); + // Penalize the unsupported and non passed pawns attacked twice by the enemy + b = ourPawns + & doubleAttackThem + & ~(e->pawnAttacks[Us] | e->passedPawns[Us]); + score -= WeakLever * popcount(b); return score; } diff --git a/src/search.cpp b/src/search.cpp index f50fdf88..222be393 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1152,7 +1152,7 @@ moves_loop: // When in check, search starts from here : -stat_bonus(newDepth); if (move == ss->killers[0]) - bonus += bonus / 4; + bonus += bonus / 4; update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } From acdda38b93361f10e331a6d951d6870577efdace Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 24 Jul 2019 17:30:59 +0300 Subject: [PATCH 049/281] Tweak of SEE pruning condition passed STC http://tests.stockfishchess.org/tests/view/5d386bda0ebc5925cf0ef49a LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 56874 W: 12820 L: 12373 D: 31681 passed LTC http://tests.stockfishchess.org/tests/view/5d38873a0ebc5925cf0ef86e LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 43512 W: 7547 L: 7247 D: 28718 Additional thanks to @locutus2 , @miguel-l and @xoto10 for fruitful discussion. There may be some more elo there since this tweak was the first one and numbers are more or less arbitrary. Closes https://github.com/official-stockfish/Stockfish/pull/2256 Bench 3935523 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 222be393..09df1ac2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1041,7 +1041,7 @@ moves_loop: // When in check, search starts from here continue; // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth))) + if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } else if ( (!givesCheck || !extension) From aec918a2b6ee931826ef19db1726950976da7ffe Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 16 Jul 2019 06:08:58 -0600 Subject: [PATCH 050/281] Remove operators for color This is a non-functional and untested simplification. The increment operator for color isn't really necessary and seems a bit unnatural to me. Passed STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 47027 W: 10589 L: 10518 D: 25920 http://tests.stockfishchess.org/tests/view/5d3472d10ebc5925cf0e8d3e Closes https://github.com/official-stockfish/Stockfish/pull/2247 No functional change --- src/bitboard.cpp | 2 +- src/material.cpp | 4 ++-- src/position.cpp | 4 ++-- src/syzygy/tbprobe.cpp | 2 +- src/types.h | 1 - 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 281579c4..2afd3766 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -80,7 +80,7 @@ void Bitboards::init() { int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } }; - for (Color c = WHITE; c <= BLACK; ++c) + 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) diff --git a/src/material.cpp b/src/material.cpp index 3a05f3fa..11d4c687 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -140,7 +140,7 @@ Entry* probe(const Position& pos) { if ((e->evaluationFunction = Endgames::probe(key)) != nullptr) return e; - for (Color c = WHITE; c <= BLACK; ++c) + for (Color c : { WHITE, BLACK }) if (is_KXK(pos, c)) { e->evaluationFunction = &EvaluateKXK[c]; @@ -160,7 +160,7 @@ Entry* probe(const Position& pos) { // We didn't find any specialized scaling function, so fall back on generic // ones that refer to more than one material distribution. Note that in this // case we don't return after setting the function. - for (Color c = WHITE; c <= BLACK; ++c) + for (Color c : { WHITE, BLACK }) { if (is_KBPsK(pos, c)) e->scalingFunction[c] = &ScaleKBPsK[c]; diff --git a/src/position.cpp b/src/position.cpp index 9f06e174..fbde810b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1299,8 +1299,8 @@ bool Position::pos_is_ok() const { assert(0 && "pos_is_ok: Index"); } - for (Color c = WHITE; c <= BLACK; ++c) - for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1)) + for (Color c : { WHITE, BLACK }) + for (CastlingSide s : {KING_SIDE, QUEEN_SIDE}) { if (!can_castle(c | s)) continue; diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 7864486c..90c86388 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -367,7 +367,7 @@ TBTable::TBTable(const std::string& code) : TBTable() { hasPawns = pos.pieces(PAWN); hasUniquePieces = false; - for (Color c = WHITE; c <= BLACK; ++c) + for (Color c : {WHITE, BLACK}) for (PieceType pt = PAWN; pt < KING; ++pt) if (popcount(pos.pieces(c, pt)) == 1) hasUniquePieces = true; diff --git a/src/types.h b/src/types.h index b9c01fe7..b0c333b8 100644 --- a/src/types.h +++ b/src/types.h @@ -304,7 +304,6 @@ ENABLE_FULL_OPERATORS_ON(Direction) ENABLE_INCR_OPERATORS_ON(PieceType) ENABLE_INCR_OPERATORS_ON(Piece) -ENABLE_INCR_OPERATORS_ON(Color) ENABLE_INCR_OPERATORS_ON(Square) ENABLE_INCR_OPERATORS_ON(File) ENABLE_INCR_OPERATORS_ON(Rank) From 9d3a2ecaa22cb55bddef0e932f2b2951cf6cacf5 Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 7 Jul 2019 18:36:57 -0700 Subject: [PATCH 051/281] Bug fix: always choose shortest mate in multithread mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In current master, with the voting scheme the best thread selection may pick a non mate or not the shortest mate thread. This patch fixes this bug. Formatting suggestion by Jörg Oster. Related past pull requests: https://github.com/official-stockfish/Stockfish/pull/1074 https://github.com/official-stockfish/Stockfish/pull/1215 Passed a [-4..0] verification test with 3 threads: LLR: 2.95 (-2.94,2.94) [-4.00,0.00] Total: 57158 W: 11374 L: 11424 D: 34360 http://tests.stockfishchess.org/tests/view/5d22deb30ebc5925cf0caefd Closes https://github.com/official-stockfish/Stockfish/pull/2226 No functional change (in single threaded mode) ---------------------------------------------------- Comment by Jörg Oster Just one sample output to demonstrate the effect of this patch. 5 Threads, 1 GB Hash +---+---+---+---+---+---+---+---+ | r | | b | | | r | k | | +---+---+---+---+---+---+---+---+ | | | | n | | p | b | | +---+---+---+---+---+---+---+---+ | | | p | | p | | p | | +---+---+---+---+---+---+---+---+ | p | | | | | | P | | +---+---+---+---+---+---+---+---+ | P | p | | | B | | N | Q | +---+---+---+---+---+---+---+---+ | | q | | | | | P | | +---+---+---+---+---+---+---+---+ | | | R | | | P | | | +---+---+---+---+---+---+---+---+ | | | | R | | | K | | +---+---+---+---+---+---+---+---+ Fen: r1b2rk1/3n1pb1/2p1p1p1/p5P1/Pp2B1NQ/1q4P1/2R2P2/3R2K1 w - - 8 34 Key: 38B4CA1067D4F477 Checkers: ucinewgame isready readyok go mate 17 searchmoves d1d7 info depth 65 seldepth 36 multipv 1 score mate 18 nodes 785875935 nps 8650448 hashfull 1000 tbhits 0 time 90848 pv d1d7 c8d7 g4f6 g7f6 g5f6 b3a3 g1g2 a3a1 h4g5 a1f6 g5f6 e6e5 c2c1 d7h3 g2h3 a8a6 h3g2 c6c5 f6a6 g8g7 c1c5 f7f6 a6e6 f8f7 c5c8 f6f5 e4d5 g7h6 e6f7 f5f4 f7e7 f4f3 d5f3 b4b3 c8h8 info depth 63 seldepth 36 multipv 1 score mate 17 nodes 785875935 nps 8650448 hashfull 1000 tbhits 0 time 90848 pv d1d7 c8d7 g4f6 g7f6 g5f6 b3a3 g1g2 a3a1 h4g5 a1f6 g5f6 e6e5 c2c1 d7h3 g2h3 a8a6 c1d1 b4b3 h3g2 c6c5 f6a6 g8g7 d1d7 g7g8 a6f6 b3b2 e4g6 b2b1q g6f7 f8f7 f6f7 g8h8 f7g7 bestmove d1d7 ponder c8d7 --- src/search.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 09df1ac2..eda7f2f7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -277,7 +277,7 @@ void MainThread::search() { std::map votes; Value minScore = this->rootMoves[0].score; - // Find out minimum score and reset votes for moves which can be voted + // Find out minimum score for (Thread* th: Threads) minScore = std::min(minScore, th->rootMoves[0].score); @@ -287,7 +287,14 @@ void MainThread::search() { votes[th->rootMoves[0].pv[0]] += (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) + if (bestThread->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY) + { + // Make sure we pick the shortest mate + if (th->rootMoves[0].score > bestThread->rootMoves[0].score) + bestThread = th; + } + else if ( th->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY + || votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) bestThread = th; } } From d980d7c0d4b2efe7abe26bdd094859f6d888ee60 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 25 Jul 2019 16:27:46 -0600 Subject: [PATCH 052/281] Simplify weak lever STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 14844 W: 3347 L: 3212 D: 8285 http://tests.stockfishchess.org/tests/view/5d3a2d7b0ebc5925cf0f1632 LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 55261 W: 9374 L: 9309 D: 36578 http://tests.stockfishchess.org/tests/view/5d3a3d9e0ebc5925cf0f1786 Closes https://github.com/official-stockfish/Stockfish/pull/2257 bench: 3484124 --- src/pawns.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 9755c2ec..86c4b8ef 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -70,7 +70,7 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - Bitboard b, neighbours, stoppers, doubled, support, phalanx; + Bitboard neighbours, stoppers, doubled, support, phalanx; Bitboard lever, leverPush; Square s; bool opposed, backward, passed; @@ -145,11 +145,10 @@ namespace { score -= Doubled; } - // Penalize the unsupported and non passed pawns attacked twice by the enemy - b = ourPawns - & doubleAttackThem - & ~(e->pawnAttacks[Us] | e->passedPawns[Us]); - score -= WeakLever * popcount(b); + // Penalize our unsupported pawns attacked twice by enemy pawns + score -= WeakLever * popcount( ourPawns + & doubleAttackThem + & ~e->pawnAttacks[Us]); return score; } From 8152a74ab4f703717fdb493cf9059f89be9a4fba Mon Sep 17 00:00:00 2001 From: xoto10 Date: Tue, 30 Jul 2019 11:46:43 +0100 Subject: [PATCH 053/281] Tune search constants This is the result of a 200k tuning run at LTC: http://tests.stockfishchess.org/tests/view/5d3576b70ebc5925cf0e9e1e which passed quickly at LTC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 12954 W: 2280 L: 2074 D: 8600 http://tests.stockfishchess.org/tests/view/5d3ff3f70ebc5925cf0f87a2 STC failed, but second LTC at [0,4] passed easily: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 8004 W: 1432 L: 1252 D: 5320 http://tests.stockfishchess.org/tests/view/5d407cff0ebc5925cf0f9119 Further work? No doubt some of these changes produce most of the gain and some are neutral or even bad, so further testing on individual/groups of parameters changed here might show more gains. It does look like these tests might need to be at LTC though, so maybe not too practical to do. See the thread in the pull request for an interesting discussion: https://github.com/official-stockfish/Stockfish/pull/2260 Bench: 4024328 --- src/search.cpp | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index eda7f2f7..6d1a66e5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -62,9 +62,9 @@ namespace { enum NodeType { NonPV, PV }; // Razor and futility margins - constexpr int RazorMargin = 600; + constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { - return Value((175 - 50 * improving) * d / ONE_PLY); + return Value((168 - 51 * improving) * d / ONE_PLY); } // Reductions lookup table, initialized at startup @@ -72,7 +72,7 @@ namespace { Depth reduction(bool i, Depth d, int mn) { int r = Reductions[d / ONE_PLY] * Reductions[mn]; - return ((r + 512) / 1024 + (!i && r > 1024)) * ONE_PLY; + return ((r + 520) / 1024 + (!i && r > 999)) * ONE_PLY; } constexpr int futility_move_count(bool improving, int depth) { @@ -82,7 +82,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth depth) { int d = depth / ONE_PLY; - return d > 17 ? 0 : 29 * d * d + 138 * d - 134; + return d > 17 ? -8 : 22 * d * d + 151 * d - 140; } // Add a small random component to draw evaluations to avoid 3fold-blindness @@ -191,7 +191,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int(22.9 * std::log(i)); + Reductions[i] = int(23.4 * std::log(i)); } @@ -409,15 +409,15 @@ void Thread::search() { selDepth = 0; // Reset aspiration window starting size - if (rootDepth >= 5 * ONE_PLY) + if (rootDepth >= 4 * ONE_PLY) { Value previousScore = rootMoves[pvIdx].previousScore; - delta = Value(20); + delta = Value(23); 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 + 88 * previousScore / (abs(previousScore) + 200); + int dct = ct + 86 * previousScore / (abs(previousScore) + 176); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -512,12 +512,12 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (314 + 9 * (mainThread->previousScore - bestValue)) / 581.0; + double fallingEval = (354 + 10 * (mainThread->previousScore - bestValue)) / 692.0; fallingEval = clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 10 * ONE_PLY < completedDepth ? 1.95 : 1.0; - double reduction = (1.25 + mainThread->previousTimeReduction) / (2.25 * timeReduction); + timeReduction = lastBestMoveDepth + 9 * ONE_PLY < completedDepth ? 1.97 : 0.98; + double reduction = (1.36 + mainThread->previousTimeReduction) / (2.29 * timeReduction); // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) @@ -796,9 +796,9 @@ namespace { // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23200 + && (ss-1)->statScore < 22661 && eval >= beta - && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225 + && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -806,7 +806,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY; + Depth R = ((835 + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY; ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; @@ -823,7 +823,7 @@ namespace { if (nullValue >= VALUE_MATE_IN_MAX_PLY) nullValue = beta; - if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 12 * ONE_PLY)) + if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13 * ONE_PLY)) return nullValue; assert(!thisThread->nmpMinPly); // Recursive verification is not allowed @@ -849,7 +849,7 @@ namespace { && depth >= 5 * ONE_PLY && abs(beta) < VALUE_MATE_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 216 - 48 * improving, VALUE_INFINITE); + Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); int probCutCount = 0; @@ -881,7 +881,7 @@ namespace { } // Step 11. Internal iterative deepening (~2 Elo) - if (depth >= 8 * ONE_PLY && !ttMove) + if (depth >= 7 * ONE_PLY && !ttMove) { search(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode); @@ -955,7 +955,7 @@ moves_loop: // When in check, search starts from here // 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 // result is lower than ttValue minus a margin then we will extend the ttMove. - if ( depth >= 8 * ONE_PLY + if ( depth >= 6 * ONE_PLY && move == ttMove && !rootNode && !excludedMove // Avoid recursive singular search @@ -976,7 +976,7 @@ moves_loop: // When in check, search starts from here extension = ONE_PLY; singularLMR++; - if (value < singularBeta - std::min(3 * depth / ONE_PLY, 39)) + if (value < singularBeta - std::min(4 * depth / ONE_PLY, 36)) singularLMR++; } @@ -1036,15 +1036,15 @@ moves_loop: // When in check, search starts from here lmrDepth /= ONE_PLY; // Countermoves based pruning (~20 Elo) - if ( lmrDepth < 3 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) + 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 < 7 + if ( lmrDepth < 6 && !inCheck - && ss->staticEval + 256 + 200 * lmrDepth <= alpha) + && ss->staticEval + 250 + 211 * lmrDepth <= alpha) continue; // Prune moves with negative SEE (~10 Elo) @@ -1052,7 +1052,7 @@ moves_loop: // When in check, search starts from here continue; } else if ( (!givesCheck || !extension) - && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) // (~20 Elo) + && !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo) continue; } @@ -1119,7 +1119,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)] - - 4000; + - 4729; // Reset statScore to zero if negative and most stats shows >= 0 if ( ss->statScore < 0 @@ -1129,10 +1129,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 >= 0 && (ss-1)->statScore < 0) + if (ss->statScore >= -99 && (ss-1)->statScore < -116) r -= ONE_PLY; - else if ((ss-1)->statScore >= 0 && ss->statScore < 0) + else if ((ss-1)->statScore >= -117 && ss->statScore < -144) r += ONE_PLY; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) @@ -1402,7 +1402,7 @@ moves_loop: // When in check, search starts from here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 128; + futilityBase = bestValue + 153; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From fcee0ce6a39a28ffdfa4b1ed438b353a895edb6b Mon Sep 17 00:00:00 2001 From: joergoster Date: Thu, 4 Jul 2019 11:02:32 +0200 Subject: [PATCH 054/281] Revert "Improve multiPV mode" This reverts commit a8de07cc26999e2fef7298a63bfe349aaa4650fa. --- src/search.cpp | 8 +------- src/thread.h | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6d1a66e5..98419b20 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -341,7 +341,7 @@ void Thread::search() { bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; - multiPV = Options["MultiPV"]; + size_t multiPV = Options["MultiPV"]; // Pick integer skill levels, but non-deterministically round up or down // such that the average integer skill corresponds to the input floating point one. @@ -934,12 +934,6 @@ moves_loop: // When in check, search starts from here sync_cout << "info depth " << depth / ONE_PLY << " currmove " << UCI::move(move, pos.is_chess960()) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; - - // In MultiPV mode also skip moves which will be searched later as PV moves - if (rootNode && std::count(thisThread->rootMoves.begin() + thisThread->pvIdx + 1, - thisThread->rootMoves.begin() + thisThread->multiPV, move)) - continue; - if (PvNode) (ss+1)->pv = nullptr; diff --git a/src/thread.h b/src/thread.h index 46ddb495..c11d1787 100644 --- a/src/thread.h +++ b/src/thread.h @@ -59,7 +59,7 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; - size_t pvIdx, multiPV, pvLast, shuffleExts; + size_t pvIdx, pvLast, shuffleExts; int selDepth, nmpMinPly; Color nmpColor; std::atomic nodes, tbHits, bestMoveChanges; From 66a3c2968b8552efce8c7e670d7ceabb28f9c1eb Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Wed, 14 Aug 2019 10:02:21 +0200 Subject: [PATCH 055/281] Tweak unsafe checks Remove mobility area for unsafe checks. Also separate the evaluation terms for unsafe checks and blockers for king with adjusted weights. STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 124526 W: 28292 L: 27504 D: 68730 http://tests.stockfishchess.org/tests/view/5d5138290ebc5925cf1070c3 LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 84968 W: 14499 L: 14083 D: 56386 http://tests.stockfishchess.org/tests/view/5d527cfa0ebc5925cf107f93 Bench: 4139590 --- src/evaluate.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7359eb92..edebb269 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -441,10 +441,6 @@ namespace { else unsafeChecks |= knightChecks; - // Unsafe or occupied checking squares will also be considered, as long as - // the square is in the attacker's mobility area. - unsafeChecks &= mobilityArea[Them]; - // Find the squares that opponent attacks in our king flank, and the squares // which are attacked twice in that flank. b1 = attackedBy[Them][ALL_PIECES] & KingFlank[file_of(ksq)] & Camp; @@ -457,7 +453,8 @@ namespace { + 185 * popcount(kingRing[Us] & weak) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) + + 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]) From 7efc39d6833a0d999a7bf2f9b5629ceb246accd2 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Wed, 14 Aug 2019 22:15:41 +0200 Subject: [PATCH 056/281] Assorted trivial cleanups (July 2019) No functional change --- AUTHORS | 2 ++ src/bitboard.h | 4 +++- src/evaluate.cpp | 17 ++++++++--------- src/pawns.cpp | 12 ++++++------ src/position.cpp | 2 +- src/search.cpp | 19 ++++++++++--------- src/syzygy/tbprobe.cpp | 2 +- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/AUTHORS b/AUTHORS index 431bc838..207c5a85 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,6 +11,7 @@ Ajith Chandy Jose (ajithcj) Alain Savard (Rocky640) alayan-stk-2 Alexander Kure +Alexander Pagel (Lolligerhans) Ali AlZhrani (Cooffe) Andrew Grant (AndyGrant) Andrey Neporada (nepal) @@ -82,6 +83,7 @@ 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) diff --git a/src/bitboard.h b/src/bitboard.h index 7a16597d..477b1655 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -377,6 +377,8 @@ inline Square pop_lsb(Bitboard* b) { /// frontmost_sq() returns the most advanced square for the given color -inline Square frontmost_sq(Color c, Bitboard b) { return c == WHITE ? msb(b) : lsb(b); } +inline Square frontmost_sq(Color c, Bitboard b) { + return c == WHITE ? msb(b) : lsb(b); +} #endif // #ifndef BITBOARD_H_INCLUDED diff --git a/src/evaluate.cpp b/src/evaluate.cpp index edebb269..05fa45bc 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -505,9 +505,6 @@ namespace { // Enemies not strongly protected and under our attack weak = pos.pieces(Them) & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - // Safe or protected squares - safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; - // Bonus according to the kind of attacking pieces if (defended | weak) { @@ -544,6 +541,14 @@ namespace { score += RestrictedPiece * popcount(b); + // Protected or unattacked squares + safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; + + // Bonus for attacking enemy pieces with our relatively safe pawns + b = pos.pieces(Us, PAWN) & safe; + b = pawn_attacks_bb(b) & nonPawnEnemies; + score += ThreatBySafePawn * popcount(b); + // Find squares where our pawns can push on the next move b = shift(pos.pieces(Us, PAWN)) & ~pos.pieces(); b |= shift(b & TRank3BB) & ~pos.pieces(); @@ -555,12 +560,6 @@ namespace { b = pawn_attacks_bb(b) & nonPawnEnemies; score += ThreatByPawnPush * popcount(b); - // Our safe or protected pawns - b = pos.pieces(Us, PAWN) & safe; - - b = pawn_attacks_bb(b) & nonPawnEnemies; - score += ThreatBySafePawn * popcount(b); - // Bonus for threats on the next moves against enemy queen if (pos.count(Them) == 1) { diff --git a/src/pawns.cpp b/src/pawns.cpp index 86c4b8ef..5df175b2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -52,8 +52,8 @@ namespace { // Danger of enemy pawns moving toward our king by [distance from edge][rank]. // RANK_1 = 0 is used for files where the enemy has no pawn, or their pawn - // is behind our king. - // [0][1-2] accommodate opponent pawn on edge (likely blocked by our king) + // 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) }, @@ -196,10 +196,10 @@ void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); - Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; + int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; b = theirPawns & file_bb(f); - Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1; + int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; int d = std::min(f, ~f); bonus += make_score(ShelterStrength[d][ourRank], 0); @@ -234,7 +234,7 @@ Score Entry::do_king_safety(const Position& pos) { else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); - Score shelter = make_score(-VALUE_INFINITE, VALUE_ZERO); + Score shelter = make_score(-VALUE_INFINITE, 0); evaluate_shelter(pos, ksq, shelter); // If we can castle use the bonus after the castling if it is bigger @@ -244,7 +244,7 @@ Score Entry::do_king_safety(const Position& pos) { if (pos.can_castle(Us | QUEEN_SIDE)) evaluate_shelter(pos, relative_square(Us, SQ_C1), shelter); - return shelter - make_score(VALUE_ZERO, 16 * minPawnDist); + return shelter - make_score(0, 16 * minPawnDist); } // Explicit template instantiation diff --git a/src/position.cpp b/src/position.cpp index fbde810b..4358f968 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -882,7 +882,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { if (end >= 4) { StateInfo* stp = st->previous->previous; - for (int i=4; i <= end; i += 2) + for (int i = 4; i <= end; i += 2) { stp = stp->previous->previous; if (stp->key == st->key) diff --git a/src/search.cpp b/src/search.cpp index 98419b20..b154c6d9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -102,15 +102,16 @@ namespace { Move best = MOVE_NONE; }; - // Breadcrumbs are used to mark nodes as being searched by a given thread. + // Breadcrumbs are used to mark nodes as being searched by a given thread struct Breadcrumb { std::atomic thread; std::atomic key; }; std::array breadcrumbs; - // ThreadHolding keeps track of which thread left breadcrumbs at the given node for potential reductions. - // A free node will be marked upon entering the moves loop, and unmarked upon leaving that loop, by the ctor/dtor of this struct. + // ThreadHolding structure keeps track of which thread left breadcrumbs at the given + // node for potential reductions. A free node will be marked upon entering the moves + // loop by the constructor, and unmarked upon leaving that loop by the destructor. struct ThreadHolding { explicit ThreadHolding(Thread* thisThread, Key posKey, int ply) { location = ply < 8 ? &breadcrumbs[posKey & (breadcrumbs.size() - 1)] : nullptr; @@ -118,7 +119,7 @@ namespace { owning = false; if (location) { - // see if another already marked this location, if not, mark it ourselves. + // See if another already marked this location, if not, mark it ourselves Thread* tmp = (*location).thread.load(std::memory_order_relaxed); if (tmp == nullptr) { @@ -133,7 +134,7 @@ namespace { } ~ThreadHolding() { - if (owning) // free the marked location. + if (owning) // Free the marked location (*location).thread.store(nullptr, std::memory_order_relaxed); } @@ -647,9 +648,9 @@ namespace { // statScore of the previous grandchild. This influences the reduction rules in // LMR which are based on the statScore of parent position. if (rootNode) - (ss + 4)->statScore = 0; + (ss+4)->statScore = 0; else - (ss + 2)->statScore = 0; + (ss+2)->statScore = 0; // Step 4. Transposition table lookup. We don't want the score of a partial // search to overwrite a previous full search TT value, so we use a different @@ -680,7 +681,7 @@ namespace { // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !pos.captured_piece()) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); } // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) @@ -908,7 +909,7 @@ moves_loop: // When in check, search starts from here moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - // Mark this node as being searched. + // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); // Step 12. Loop through all pseudo-legal moves until no moves remain diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 90c86388..10864744 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -367,7 +367,7 @@ TBTable::TBTable(const std::string& code) : TBTable() { hasPawns = pos.pieces(PAWN); hasUniquePieces = false; - for (Color c : {WHITE, BLACK}) + for (Color c : { WHITE, BLACK }) for (PieceType pt = PAWN; pt < KING; ++pt) if (popcount(pos.pieces(c, pt)) == 1) hasUniquePieces = true; From d4dca9187e83dde29be8d76ca50ff53d14199ce9 Mon Sep 17 00:00:00 2001 From: Jean Gauthier Date: Wed, 14 Aug 2019 08:44:21 -0400 Subject: [PATCH 057/281] Slight speep up fetching the endgame table Replace calls to count(key) + operator[key] with a single call to find(key). Replace the std::map with std::unordered_map which provide O(1) access, although the map has a really small number of objects. Test with [0..4] failed yellow: TC 10+0.1 SPRT elo0: 0.00 alpha: 0.05 elo1: 4.00 beta: 0.05 LLR -2.96 [-2.94,2.94] (rejected) Elo 1.01 [-0.87,3.08] (95%) LOS 85.3% Games 71860 [w:22.3%, l:22.2%, d:55.5%] http://tests.stockfishchess.org/tests/view/5d5432210ebc5925cf109d61 Closes https://github.com/official-stockfish/Stockfish/pull/2269 No functional change --- src/endgame.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/endgame.h b/src/endgame.h index d0a5a97e..e29f8777 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -21,7 +21,7 @@ #ifndef ENDGAME_H_INCLUDED #define ENDGAME_H_INCLUDED -#include +#include #include #include #include @@ -98,7 +98,7 @@ struct Endgame : public EndgameBase { namespace Endgames { template using Ptr = std::unique_ptr>; - template using Map = std::map>; + template using Map = std::unordered_map>; extern std::pair, Map> maps; @@ -119,7 +119,8 @@ namespace Endgames { template const EndgameBase* probe(Key key) { - return map().count(key) ? map()[key].get() : nullptr; + auto it = map().find(key); + return it != map().end() ? it->second.get() : nullptr; } } From 18279b24fc76bb6eaf6ac01f3032b1b90da5dabb Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 20 Aug 2019 19:52:18 -0600 Subject: [PATCH 058/281] Tuned Futility Equation @Vizvezdenec array suggested that alternate values may be better than current master (see pull request #2270 ). I tuned some linear equations to more closely represent his values and it passed. These futility values seem quite sensitive, so perhaps additional Elo improvements can be found here. STC LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 12257 W: 2820 L: 2595 D: 6842 http://tests.stockfishchess.org/tests/view/5d5b2f360ebc5925cf1111ac LTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 20273 W: 3497 L: 3264 D: 13512 http://tests.stockfishchess.org/tests/view/5d5c0d250ebc5925cf111ac3 Closes https://github.com/official-stockfish/Stockfish/pull/2272 ------------------------------------------ How to continue from there ? a) we can try a simpler version for the futility margin, this would be a simplification : margin = 188 * (depth - improving) b) on the other direction, we can try a complexification by trying again to gain Elo with an complete array of futility values. ------------------------------------------ Bench: 4330402 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b154c6d9..69488ad5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -64,7 +64,7 @@ namespace { // Razor and futility margins constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { - return Value((168 - 51 * improving) * d / ONE_PLY); + return Value(198 * (d / ONE_PLY) - 178 * improving); } // Reductions lookup table, initialized at startup From 10d2ebc6ae7aad8ee3a48aac41ad00321b1b7e78 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 21 Aug 2019 08:30:48 +0300 Subject: [PATCH 059/281] Late move reduction, captures and CUT nodes Expand of Stefan Geschwentner's original idea: we always do LMR for captures at cutnodes. Passed STC http://tests.stockfishchess.org/tests/view/5d5b2f8e0ebc5925cf1111b8 LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 36026 W: 8122 L: 7779 D: 20125 Passed LTC http://tests.stockfishchess.org/tests/view/5d5b40c80ebc5925cf111353 LLR: 3.22 (-2.94,2.94) [0.00,3.50] Total: 133502 W: 22508 L: 21943 D: 89051 Closes https://github.com/official-stockfish/Stockfish/pull/2273 Bench: 3494372 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 69488ad5..7f421b9c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1074,7 +1074,8 @@ moves_loop: // When in check, search starts from here && moveCount > 1 + 3 * rootNode && ( !captureOrPromotion || moveCountPruning - || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha)) + || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha + || cutNode)) { Depth r = reduction(improving, depth, moveCount); From a016626825972d546d2e4ef6abd2e55f7bf2f3dc Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 22 Aug 2019 08:27:26 -0600 Subject: [PATCH 060/281] Simplify futility equation This is a functional simplification. The 178 constant for the futility equation in master can be removed. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 42626 W: 9508 L: 9428 D: 23690 http://tests.stockfishchess.org/tests/view/5d5d4e320ebc5925cf11254e LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 26182 W: 4432 L: 4320 D: 17430 http://tests.stockfishchess.org/tests/view/5d5df70d0ebc5925cf112fee Closes https://github.com/official-stockfish/Stockfish/pull/2278 Bench: 3985701 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7f421b9c..7a16ef8c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -64,7 +64,7 @@ namespace { // Razor and futility margins constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { - return Value(198 * (d / ONE_PLY) - 178 * improving); + return Value(198 * (d / ONE_PLY - improving)); } // Reductions lookup table, initialized at startup From 3984b8f8f0e1f53c737020c936f2a8372029545d Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 12 Aug 2019 08:42:28 -0600 Subject: [PATCH 061/281] Consolidate CastlingSide and CastlingRights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a non-functional simplification that removes CastlingSide and implements the functionality in CastlingRights (thanks to Jörg Oster for a comment on the first version of this patch). STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 53854 W: 12077 L: 12019 D: 29758 http://tests.stockfishchess.org/tests/view/5d517b940ebc5925cf107474 Closes https://github.com/official-stockfish/Stockfish/pull/2265 No functional change --- src/movegen.cpp | 6 +++--- src/pawns.cpp | 4 ++-- src/position.cpp | 17 ++++++++--------- src/position.h | 12 ++++++------ src/types.h | 16 +++++++--------- 5 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 4c609352..fc99ec26 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -219,8 +219,8 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { - constexpr CastlingRight OO = Us | KING_SIDE; - constexpr CastlingRight OOO = Us | QUEEN_SIDE; + constexpr CastlingRights OO = Us & KING_SIDE; + constexpr CastlingRights OOO = Us & QUEEN_SIDE; constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); @@ -236,7 +236,7 @@ namespace { while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); - if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) + if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) { if (!pos.castling_impeded(OO) && pos.can_castle(OO)) *moveList++ = make(ksq, pos.castling_rook_square(OO)); diff --git a/src/pawns.cpp b/src/pawns.cpp index 5df175b2..1cacc1e3 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -238,10 +238,10 @@ Score Entry::do_king_safety(const Position& pos) { evaluate_shelter(pos, ksq, shelter); // If we can castle use the bonus after the castling if it is bigger - if (pos.can_castle(Us | KING_SIDE)) + if (pos.can_castle(Us & KING_SIDE)) evaluate_shelter(pos, relative_square(Us, SQ_G1), shelter); - if (pos.can_castle(Us | QUEEN_SIDE)) + if (pos.can_castle(Us & QUEEN_SIDE)) evaluate_shelter(pos, relative_square(Us, SQ_C1), shelter); return shelter - make_score(0, 16 * minPawnDist); diff --git a/src/position.cpp b/src/position.cpp index 4358f968..db66f416 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -330,16 +330,15 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si, Th void Position::set_castling_right(Color c, Square rfrom) { Square kfrom = square(c); - CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE; - CastlingRight cr = (c | cs); + CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE: QUEEN_SIDE); st->castlingRights |= cr; castlingRightsMask[kfrom] |= cr; castlingRightsMask[rfrom] |= cr; castlingRookSquare[cr] = rfrom; - Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 : SQ_C1); - Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 : SQ_D1); + Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1); + Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) & ~(square_bb(kfrom) | rfrom); @@ -1300,14 +1299,14 @@ bool Position::pos_is_ok() const { } for (Color c : { WHITE, BLACK }) - for (CastlingSide s : {KING_SIDE, QUEEN_SIDE}) + for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE}) { - if (!can_castle(c | s)) + if (!can_castle(cr)) continue; - if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK) - || castlingRightsMask[castlingRookSquare[c | s]] != (c | s) - || (castlingRightsMask[square(c)] & (c | s)) != (c | s)) + if ( piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK) + || castlingRightsMask[castlingRookSquare[cr]] != (cr) + || (castlingRightsMask[square(c)] & (cr)) != (cr)) assert(0 && "pos_is_ok: Castling"); } diff --git a/src/position.h b/src/position.h index 2106414b..a0a9a306 100644 --- a/src/position.h +++ b/src/position.h @@ -100,9 +100,9 @@ public: // Castling int castling_rights(Color c) const; - bool can_castle(CastlingRight cr) const; - bool castling_impeded(CastlingRight cr) const; - Square castling_rook_square(CastlingRight cr) const; + bool can_castle(CastlingRights cr) const; + bool castling_impeded(CastlingRights cr) const; + Square castling_rook_square(CastlingRights cr) const; // Checking Bitboard checkers() const; @@ -268,7 +268,7 @@ inline bool Position::is_on_semiopen_file(Color c, Square s) const { return !(pieces(c, PAWN) & file_bb(s)); } -inline bool Position::can_castle(CastlingRight cr) const { +inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } @@ -276,11 +276,11 @@ inline int Position::castling_rights(Color c) const { return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING); } -inline bool Position::castling_impeded(CastlingRight cr) const { +inline bool Position::castling_impeded(CastlingRights cr) const { return byTypeBB[ALL_PIECES] & castlingPath[cr]; } -inline Square Position::castling_rook_square(CastlingRight cr) const { +inline Square Position::castling_rook_square(CastlingRights cr) const { return castlingRookSquare[cr]; } diff --git a/src/types.h b/src/types.h index b0c333b8..3559d72b 100644 --- a/src/types.h +++ b/src/types.h @@ -131,19 +131,17 @@ enum Color { WHITE, BLACK, COLOR_NB = 2 }; -enum CastlingSide { - KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2 -}; - -enum CastlingRight { +enum CastlingRights { NO_CASTLING, WHITE_OO, WHITE_OOO = WHITE_OO << 1, BLACK_OO = WHITE_OO << 2, BLACK_OOO = WHITE_OO << 3, - WHITE_CASTLING = WHITE_OO | WHITE_OOO, - BLACK_CASTLING = BLACK_OO | BLACK_OOO, + KING_SIDE = WHITE_OO | BLACK_OO, + QUEEN_SIDE = WHITE_OOO | BLACK_OOO, + WHITE_CASTLING = WHITE_OO | WHITE_OOO, + BLACK_CASTLING = BLACK_OO | BLACK_OOO, ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING, CASTLING_RIGHT_NB = 16 @@ -363,8 +361,8 @@ constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } -constexpr CastlingRight operator|(Color c, CastlingSide s) { - return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c)); +constexpr CastlingRights operator&(Color c, CastlingRights cr) { + return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } constexpr Value mate_in(int ply) { From d799529b4843edd7630901a16c48a13d1fb50565 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sat, 24 Aug 2019 08:16:20 +0200 Subject: [PATCH 062/281] Improve signature of evaluate_shelter() Remove one parameter in function evaluate_shelter(), making all comparisons for castled/uncastled shelter locally in do_king_safety(). Also introduce BlockedStorm penalty. Passed non-regression test at STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 65864 W: 14630 L: 14596 D: 36638 http://tests.stockfishchess.org/tests/view/5d5fc80c0ebc5939d09f0acc No functional change --- src/pawns.cpp | 37 +++++++++++++++++++++---------------- src/pawns.h | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 1cacc1e3..33e859e5 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -33,6 +33,7 @@ namespace { // Pawn penalties constexpr Score Backward = S( 9, 24); + constexpr Score BlockedStorm = S(82, 82); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); constexpr Score WeakLever = S( 0, 56); @@ -182,7 +183,7 @@ Entry* probe(const Position& pos) { /// penalty for a king, looking at the king file and the two closest files. template -void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { +Score Entry::evaluate_shelter(const Position& pos, Square ksq) { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); @@ -205,13 +206,12 @@ void Entry::evaluate_shelter(const Position& pos, Square ksq, Score& shelter) { bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) - bonus -= make_score(82 * (theirRank == RANK_3), 82 * (theirRank == RANK_3)); + bonus -= BlockedStorm * int(theirRank == RANK_3); else bonus -= make_score(UnblockedStorm[d][theirRank], 0); } - if (mg_value(bonus) > mg_value(shelter)) - shelter = bonus; + return bonus; } @@ -225,26 +225,31 @@ Score Entry::do_king_safety(const Position& pos) { kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); + Score shelters[3] = { evaluate_shelter(pos, ksq), + make_score(-VALUE_INFINITE, 0), + make_score(-VALUE_INFINITE, 0) }; + + // If we can castle use the bonus after castling if it is bigger + if (pos.can_castle(Us & KING_SIDE)) + shelters[1] = evaluate_shelter(pos, relative_square(Us, SQ_G1)); + + if (pos.can_castle(Us & QUEEN_SIDE)) + shelters[2] = evaluate_shelter(pos, relative_square(Us, SQ_C1)); + + for (int i : {1, 2}) + if (mg_value(shelters[i]) > mg_value(shelters[0])) + shelters[0] = shelters[i]; + + // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); int minPawnDist = pawns ? 8 : 0; if (pawns & PseudoAttacks[KING][ksq]) minPawnDist = 1; - else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); - Score shelter = make_score(-VALUE_INFINITE, 0); - evaluate_shelter(pos, ksq, shelter); - - // If we can castle use the bonus after the castling if it is bigger - if (pos.can_castle(Us & KING_SIDE)) - evaluate_shelter(pos, relative_square(Us, SQ_G1), shelter); - - if (pos.can_castle(Us & QUEEN_SIDE)) - evaluate_shelter(pos, relative_square(Us, SQ_C1), shelter); - - return shelter - make_score(0, 16 * minPawnDist); + return shelters[0] - make_score(0, 16 * minPawnDist); } // Explicit template instantiation diff --git a/src/pawns.h b/src/pawns.h index 1f930988..4c041716 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -49,7 +49,7 @@ struct Entry { Score do_king_safety(const Position& pos); template - void evaluate_shelter(const Position& pos, Square ksq, Score& shelter); + Score evaluate_shelter(const Position& pos, Square ksq); Key key; Score scores[COLOR_NB]; From 0e295fee25a41962d234c0833e1f7ca29e4c2189 Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Wed, 14 Aug 2019 20:46:09 -0400 Subject: [PATCH 063/281] NMP Tweaks Tweak again the null move pruning preconditions. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 19675 W: 4430 L: 4169 D: 11076 http://tests.stockfishchess.org/tests/view/5d52bc0e0ebc5925cf108300 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 73895 W: 12496 L: 12114 D: 49285 http://tests.stockfishchess.org/tests/view/5d52dcbc0ebc5925cf108552 Closes https://github.com/official-stockfish/Stockfish/pull/2268 Bench: 3690065 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7a16ef8c..f0fa6f05 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -799,7 +799,8 @@ namespace { && (ss-1)->currentMove != MOVE_NULL && (ss-1)->statScore < 22661 && eval >= beta - && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 + && eval >= ss->staticEval + && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) From 8fec8834715a440ac18e24e130888c2c60bab352 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 25 Aug 2019 21:45:58 +0200 Subject: [PATCH 064/281] Tweak Late Move Reduction at root Maintain best move counter at the root and allow there only moves which has a counter of zero for Late Move Reduction. For compensation only the first three moves are excluded from Late Move Reduction per default instead the first four moves. What we can further do: - here we use a simple counting scheme but perhaps some aging to fade out early iterations could be helpful - use the best move counter also at inner nodes for LMR and/or pruning STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 17414 W: 3984 L: 3733 D: 9697 http://tests.stockfishchess.org/tests/view/5d6234bb0ebc5939d09f2aa2 LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 38058 W: 6448 L: 6166 D: 25444 http://tests.stockfishchess.org/tests/view/5d62681a0ebc5939d09f2f27 Closes https://github.com/official-stockfish/Stockfish/pull/2282 Bench: 3568210 --- src/search.cpp | 6 +++++- src/search.h | 1 + src/thread.cpp | 9 +++++++++ src/thread.h | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f0fa6f05..28cbffd6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -472,7 +472,10 @@ void Thread::search() { ++failedHighCnt; } else + { + ++rootMoves[pvIdx].bestMoveCount; break; + } delta += delta / 4 + 5; @@ -1072,7 +1075,8 @@ moves_loop: // When in check, search starts from here // Step 16. Reduced depth search (LMR). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 * ONE_PLY - && moveCount > 1 + 3 * rootNode + && moveCount > 1 + 2 * rootNode + && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha diff --git a/src/search.h b/src/search.h index 24c58d30..c77ca3ad 100644 --- a/src/search.h +++ b/src/search.h @@ -70,6 +70,7 @@ struct RootMove { Value previousScore = -VALUE_INFINITE; int selDepth = 0; int tbRank = 0; + int bestMoveCount = 0; Value tbScore; std::vector pv; }; diff --git a/src/thread.cpp b/src/thread.cpp index e5043b6e..5165fd90 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -52,6 +52,15 @@ Thread::~Thread() { stdThread.join(); } +/// Thread::bestMoveCount(Move move) return best move counter for the given root move + +int Thread::best_move_count(Move move) { + + auto rm = std::find(rootMoves.begin() + pvIdx, + rootMoves.begin() + pvLast, move); + + return rm != rootMoves.begin() + pvLast ? rm->bestMoveCount : 0; +} /// Thread::clear() reset histories, usually before a new game diff --git a/src/thread.h b/src/thread.h index c11d1787..ed427b10 100644 --- a/src/thread.h +++ b/src/thread.h @@ -56,6 +56,7 @@ public: void idle_loop(); void start_searching(); void wait_for_search_finished(); + int best_move_count(Move move); Pawns::Table pawnsTable; Material::Table materialTable; From 61f44ce57864f866de5d26a3402a9ad135e17c6d Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Wed, 11 Sep 2019 13:46:08 +0200 Subject: [PATCH 065/281] Update reverse move stats For a good quiet non-pawn move consider the reverse move as bad and update the main history with a negative stat bonus. STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 19292 W: 4401 L: 4141 D: 10750 http://tests.stockfishchess.org/tests/view/5d7751d50ebc594e7864973c LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 111952 W: 18762 L: 18275 D: 74915 http://tests.stockfishchess.org/tests/view/5d7771cf0ebc594e786498fa Closes https://github.com/official-stockfish/Stockfish/pull/2294 Bench: 3914238 --- src/search.cpp | 5 ++++- src/types.h | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 28cbffd6..f8535a5f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1113,7 +1113,7 @@ moves_loop: // When in check, search starts from here // castling moves, because they are coded as "king captures rook" and // hence break make_move(). (~5 Elo) else if ( type_of(move) == NORMAL - && !pos.see_ge(make_move(to_sq(move), from_sq(move)))) + && !pos.see_ge(reverse_move(move))) r -= 2 * ONE_PLY; ss->statScore = thisThread->mainHistory[us][from_to(move)] @@ -1603,6 +1603,9 @@ moves_loop: // When in check, search starts from here thisThread->mainHistory[us][from_to(move)] << bonus; update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus); + if (type_of(pos.moved_piece(move)) != PAWN) + thisThread->mainHistory[us][from_to(reverse_move(move))] << -bonus; + if (is_ok((ss-1)->currentMove)) { Square prevSq = to_sq((ss-1)->currentMove); diff --git a/src/types.h b/src/types.h index 3559d72b..934f884e 100644 --- a/src/types.h +++ b/src/types.h @@ -442,6 +442,10 @@ constexpr Move make_move(Square from, Square to) { return Move((from << 6) + to); } +constexpr Move reverse_move(Move m) { + return make_move(to_sq(m), from_sq(m)); +} + template constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) { return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to); From 270b241ec12ad3a32634a846b87ec9dc08fa2730 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 11 Sep 2019 12:36:58 -0600 Subject: [PATCH 066/281] Simplify Weak Lever This is a simplification that integrated WeakLever into doubled pawns. Since we already check for !support for Doubled pawns, it is trivial to check for weak lever by just checking more_than_one(lever). We also introduce the Score * bool operation overload to remove some casts in the code. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 26757 W: 5842 L: 5731 D: 15184 http://tests.stockfishchess.org/tests/view/5d77ee220ebc5902d384e5a4 Closes https://github.com/official-stockfish/Stockfish/pull/2295 No functional change --- src/pawns.cpp | 18 +++++++----------- src/types.h | 5 +++++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 33e859e5..1ae65bf1 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -71,10 +71,10 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - Bitboard neighbours, stoppers, doubled, support, phalanx; + Bitboard neighbours, stoppers, support, phalanx; Bitboard lever, leverPush; Square s; - bool opposed, backward, passed; + bool opposed, backward, passed, doubled; Score score = SCORE_ZERO; const Square* pl = pos.squares(Us); @@ -137,20 +137,16 @@ namespace { } else if (!neighbours) - score -= Isolated + WeakUnopposed * int(!opposed); + score -= Isolated + WeakUnopposed * !opposed; else if (backward) - score -= Backward + WeakUnopposed * int(!opposed); + score -= Backward + WeakUnopposed * !opposed; - if (doubled && !support) - score -= Doubled; + if (!support) + score -= Doubled * doubled + + WeakLever * more_than_one(lever); } - // Penalize our unsupported pawns attacked twice by enemy pawns - score -= WeakLever * popcount( ourPawns - & doubleAttackThem - & ~e->pawnAttacks[Us]); - return score; } diff --git a/src/types.h b/src/types.h index 934f884e..c77d8040 100644 --- a/src/types.h +++ b/src/types.h @@ -345,6 +345,11 @@ inline Score operator*(Score s, int i) { return result; } +/// Multiplication of a Score by an boolean +inline Score operator*(Score s, bool b) { + return Score(int(s) * int(b)); +} + constexpr Color operator~(Color c) { return Color(c ^ BLACK); // Toggle color } From 36e4a86c08a4b79965d819b7893709245cad840a Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 12 Sep 2019 04:29:23 +0100 Subject: [PATCH 067/281] Bonus for rook on same file as their queen This patch creates a simple bonus for a rook that is on the same file as the opponent's queen. STC 10+0.1 th 1 : LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 45609 W: 10120 L: 9733 D: 25756 http://tests.stockfishchess.org/tests/view/5d79895a0ebc5902d385484a LTC 60+0.6 th 1 : LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 51651 W: 8606 L: 8288 D: 34757 http://tests.stockfishchess.org/tests/view/5d79a0850ebc5902d3854d27 Many thanks to @noobpwnftw for providing the extra cpu resources for fishtest, which led to me doing these tests. Closes https://github.com/official-stockfish/Stockfish/pull/2297 Bench: 4024461 --- src/evaluate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 05fa45bc..cb1ad1f4 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -140,6 +140,7 @@ namespace { constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); constexpr Score RookOnPawn = S( 10, 32); + constexpr Score RookOnQueenFile = S( 11, 4); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); @@ -346,6 +347,10 @@ namespace { if (relative_rank(Us, s) >= RANK_5) score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); + // Bonus for rook on same file as their queen + if (file_bb(s) & pos.pieces(Them, QUEEN)) + score += RookOnQueenFile; + // Bonus for rook on an open or semi-open file if (pos.is_on_semiopen_file(Us, s)) score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))]; From 8aecf2698184babce57ccfd2ba5948342e29c325 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 12 Sep 2019 06:43:04 +0300 Subject: [PATCH 068/281] Scale down complexity for almost unwinnable endgames This patch greatly scales down complexity of endgames when the following conditions are all true together: - pawns are all on one flank - stronger side king is not outflanking weaker side - no passed pawns are present This should improve stockfish evaluation of obvious draws 4 vs 3, 3 vs 2 and 2 vs 1 pawns in rook/queen/knight/bishop single flank endgames where strong side can not make progress. passed STC LLR: 2.94 (-2.94,2.94) [0.50,4.50] Total: 15843 W: 3601 L: 3359 D: 8883 passed LTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 121275 W: 20107 L: 19597 D: 81571 Closes https://github.com/official-stockfish/Stockfish/pull/2298 Bench: 3954190 ========================== How to continue from there? a) This could be a powerful idea for refining some parts of the evaluation function, a bit like when we try quadratics or other equations to emphasize certain situations (xoto10). b) Some other combinaison values for this bonus can be done further, or overall retuning of weight and offset while keeping the formula simple. --- src/evaluate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cb1ad1f4..73e2144c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -725,12 +725,17 @@ namespace { bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); + bool almostUnwinnable = !pe->passed_count() + && outflanking < 0 + && !pawnsOnBothFlanks; + // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking + 18 * pawnsOnBothFlanks + 49 * !pos.non_pawn_material() + - 36 * almostUnwinnable -103 ; // Now apply the bonus: note that we find the attacking side by extracting From db00e1625eb46517f61085ffd3bcd28779e71220 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 12 Sep 2019 21:25:58 +0200 Subject: [PATCH 069/281] Add sse4 if bmi2 is enabled The only change done to the Makefile to get a somewhat faster binary as discussed in #2291 is to add -msse4 to the compile options of the bmi2 build. Since all processors supporting bmi2 also support sse4 this can be done easily. It is a useful step to avoid sending around custom and poorly tested builds. The speedup isn't enough to pass [0,4] but it is roughly 1.15Elo and a LOS of 90%: LLR: -2.95 (-2.94,2.94) [0.00,4.00] Total: 93009 W: 20519 L: 20316 D: 52174 Also rewrite the documentation for the user when using `make --help`, so that the order of architectures for x86-64 has the more performant build one on top. Closes https://github.com/official-stockfish/Stockfish/pull/2300 No functional change --- src/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Makefile b/src/Makefile index 285d314e..6deb0e27 100644 --- a/src/Makefile +++ b/src/Makefile @@ -328,7 +328,7 @@ endif ifeq ($(pext),yes) CXXFLAGS += -DUSE_PEXT ifeq ($(comp),$(filter $(comp),gcc clang mingw)) - CXXFLAGS += -mbmi2 + CXXFLAGS += -msse4 -mbmi2 endif endif @@ -379,9 +379,9 @@ help: @echo "" @echo "Supported archs:" @echo "" - @echo "x86-64 > x86 64-bit" - @echo "x86-64-modern > x86 64-bit with popcnt support" - @echo "x86-64-bmi2 > x86 64-bit with pext support" + @echo "x86-64-bmi2 > x86 64-bit with pext support (also enables SSE4)" + @echo "x86-64-modern > x86 64-bit with popcnt support (also enables SSE3)" + @echo "x86-64 > x86 64-bit generic" @echo "x86-32 > x86 32-bit with SSE support" @echo "x86-32-old > x86 32-bit fall back for old hardware" @echo "ppc-64 > PPC 64-bit" From 8a04b3a13cdbd2153287050e65aaa3530ad0104c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sat, 14 Sep 2019 07:33:48 +0200 Subject: [PATCH 070/281] Update Makefile documentation Follow-up to previous commit. Update the documentation for the user when using `make`, to show the preferred bmi2 compile in the advanced examples section. Note: I made a mistake in the previous commit comment, the documentation is shown when using `make` or `make help`, not `make --help`. No functional change --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 6deb0e27..70246f56 100644 --- a/src/Makefile +++ b/src/Makefile @@ -382,7 +382,7 @@ help: @echo "x86-64-bmi2 > x86 64-bit with pext support (also enables SSE4)" @echo "x86-64-modern > x86 64-bit with popcnt support (also enables SSE3)" @echo "x86-64 > x86 64-bit generic" - @echo "x86-32 > x86 32-bit with SSE support" + @echo "x86-32 > x86 32-bit (also enables SSE)" @echo "x86-32-old > x86 32-bit fall back for old hardware" @echo "ppc-64 > PPC 64-bit" @echo "ppc-32 > PPC 32-bit" @@ -405,7 +405,7 @@ help: @echo "Advanced examples, for experienced users: " @echo "" @echo "make build ARCH=x86-64 COMP=clang" - @echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8" + @echo "make profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-4.8" @echo "" From a83d1a0e800f494d3b4d0aa2ed6db5bdcda50fc3 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Fri, 13 Sep 2019 15:46:05 -0400 Subject: [PATCH 071/281] Use queens of either color in RookOnQueenFile The recently-added RookOnQueenFile evaluation term (36e4a86) provided a bonus for placing our rook on the same file as an enemy queen. Here, we relax a condition in this bonus, broadening its effect to any queen. It is also strategically desirable to place the rook on the same file as a friendly queen, so the restriction on the queen's color is removed. STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 66856 W: 14847 L: 14815 D: 37194 http://tests.stockfishchess.org/tests/view/5d7b3c6a0ebc5902d385bcf5 LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 86786 W: 14264 L: 14248 D: 58274 http://tests.stockfishchess.org/tests/view/5d7b4e9b0ebc5902d385c178 Closes https://github.com/official-stockfish/Stockfish/pull/2302 Bench: 3703909 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 73e2144c..ad76fc8d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -347,8 +347,8 @@ namespace { if (relative_rank(Us, s) >= RANK_5) score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); - // Bonus for rook on same file as their queen - if (file_bb(s) & pos.pieces(Them, QUEEN)) + // Bonus for rook on the same file as a queen + if (file_bb(s) & pos.pieces(QUEEN)) score += RookOnQueenFile; // Bonus for rook on an open or semi-open file From e5cfa14f40a38d99d11a9c048c34858e3145fbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sat, 14 Sep 2019 08:33:00 +0200 Subject: [PATCH 072/281] Assorted trivial cleanups No functional change --- AUTHORS | 1 + src/position.cpp | 4 ++-- src/search.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 207c5a85..e55f94fb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -60,6 +60,7 @@ Jacques B. (Timshel) Jan Ondruš (hxim) Jared Kish (Kurtbusch) Jarrod Torriero (DU-jdto) +Jean Gauthier (QuaisBla) Jean-Francois Romang (jromang) Jerry Donald Watson (jerrydonaldwatson) Jonathan Calovski (Mysseno) diff --git a/src/position.cpp b/src/position.cpp index db66f416..6336a5ed 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1305,8 +1305,8 @@ bool Position::pos_is_ok() const { continue; if ( piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK) - || castlingRightsMask[castlingRookSquare[cr]] != (cr) - || (castlingRightsMask[square(c)] & (cr)) != (cr)) + || castlingRightsMask[castlingRookSquare[cr]] != cr + || (castlingRightsMask[square(c)] & cr) != cr) assert(0 && "pos_is_ok: Castling"); } diff --git a/src/search.cpp b/src/search.cpp index f8535a5f..79942bcd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1050,7 +1050,7 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if ( (!givesCheck || !extension) + else if ( !(givesCheck && extension) && !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo) continue; } @@ -1096,7 +1096,7 @@ moves_loop: // When in check, search starts from here if ((ss-1)->moveCount > 15) r -= ONE_PLY; - // Decrease reduction if move has been singularly extended + // Decrease reduction if ttMove has been singularly extended r -= singularLMR * ONE_PLY; if (!captureOrPromotion) From 843a6c43053ceb9cc79d29bf7c0d3a5d236e057e Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 15 Sep 2019 00:32:39 +0200 Subject: [PATCH 073/281] Introduce midgame initiative This patch finally introduces something that was tried for years: midgame score dependance on complexity of position. More precisely, if the position is very simplified and the complexity measure calculated in the initiative() function is inferior to -50 by an amount d, then we add this value d to the midgame score. One example of play of this patch will be (again!) 4 vs 3 etc same flank endgames where sides have a lot of non-pawn material: 4 vs 3 draw mostly remains the same draw even if we add a lot of equal material to both sides. STC run was stopped after 200k games (and not converging): LLR: -1.75 (-2.94,2.94) [0.50,4.50] Total: 200319 W: 44197 L: 43310 D: 112812 http://tests.stockfishchess.org/tests/view/5d7cfdb10ebc5902d386572c passed LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 41051 W: 6858 L: 6570 D: 27623 http://tests.stockfishchess.org/tests/view/5d7d14680ebc5902d3866196 This is the first and not really precise version, a lot of other stuff can be tried on top of it (separate complexity for middlegame, some more terms, even simple retuning of values). Bench: 4248476 --- src/evaluate.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ad76fc8d..d92239c1 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -169,7 +169,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Value eg) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@ -717,7 +717,10 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Value eg) const { + Score Evaluation::initiative(Score score) const { + + Value mg = mg_value(score); + Value eg = eg_value(score); int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -738,15 +741,16 @@ namespace { - 36 * almostUnwinnable -103 ; - // Now apply the bonus: note that we find the attacking side by extracting - // the sign of the endgame value, and that we carefully cap the bonus so - // that the endgame score will never change sign after the bonus. + // Now apply the bonus: note that we find the attacking side by extracting the + // sign of the midgame or endgame values, and that we carefully cap the bonus + // so that the midgame and endgame scores do not change sign after the bonus. + int u = ((mg > 0) - (mg < 0)) * std::max(std::min(complexity + 50, 0), -abs(mg)); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) - Trace::add(INITIATIVE, make_score(0, v)); + Trace::add(INITIATIVE, make_score(u, v)); - return make_score(0, v); + return make_score(u, v); } @@ -822,7 +826,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(eg_value(score)); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); From 7b064752943b67eaa7ef93f1109acfad50b4ecc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sun, 15 Sep 2019 23:18:54 +0200 Subject: [PATCH 074/281] Scale down endgame factor when shuffling This patch decreases the endgame scale factor using the 50 moves counter. Looking at some games with this patch, it seems to have two effects on the playing style: 1) when no progress can be made in late endgames (for instance in fortresses or opposite bishops endgames) the evaluation will be largely tamed down towards a draw value. 2) more interestingly, there is also a small effect in the midgame play because Stockfish will panic a little bit if there are more than four consecutive shuffling moves with an advantage: the engine will try to move a pawn or to exchange a piece to keep the advantage, so the follow-ups of the position will be discovered earlier by the alpha-beta search. passed STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 23017 W: 5080 L: 4805 D: 13132 http://tests.stockfishchess.org/tests/view/5d7e4aef0ebc59069c36fc74 passed LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 30746 W: 5171 L: 4911 D: 20664 http://tests.stockfishchess.org/tests/view/5d7e513d0ebc59069c36ff26 Pull request: https://github.com/official-stockfish/Stockfish/pull/2304 Bench: 4272173 --- src/evaluate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d92239c1..a7a091ab 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -769,8 +769,9 @@ namespace { && pos.non_pawn_material() == 2 * BishopValueMg) sf = 16 + 4 * pe->passed_count(); else - sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); + sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4 ); } return ScaleFactor(sf); From a858defd332bddd828c9280a9e326a0b750b3dda Mon Sep 17 00:00:00 2001 From: noobpwnftw Date: Sun, 15 Sep 2019 00:18:10 +0800 Subject: [PATCH 075/281] Raise stack size to 8MB for pthreads It seems there is no other way to specify stack size on std::thread than linker flags and the effective flags are named differently in many toolchains. On toolchains where pthread is always available, this patch changes the stack size change in our C++ code via pthread to ensure a minimum stack size of 8MB, instead of relying on linker defaults which may be platform-specific. Also raises default stack size on OSX to current Linux default (8MB) just to be safe. Closes https://github.com/official-stockfish/Stockfish/pull/2303 No functional change --- src/thread_win32_osx.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index 88900540..5583a06e 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -73,11 +73,14 @@ typedef std::condition_variable ConditionVariable; /// adjust it to TH_STACK_SIZE. The implementation calls pthread_create() with /// proper stack size parameter. -#if defined(__APPLE__) +/// On toolchains where pthread is always available, ensure minimum stack size +/// instead of relying on linker defaults which may be platform-specific. + +#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) #include -static const size_t TH_STACK_SIZE = 2 * 1024 * 1024; +static const size_t TH_STACK_SIZE = 8 * 1024 * 1024; template > void* start_routine(void* ptr) From 64af5434ed2b775b054993de85aa015e5a120da3 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 22 Sep 2019 16:56:36 +0200 Subject: [PATCH 076/281] Acknowledge fishtest authors Explicitly acknowledge fishtest authors. Their efforts are almost invisible, but essential for the project. Many thanks to https://github.com/glinscott/fishtest/blob/master/AUTHORS ! No functional change. --- AUTHORS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AUTHORS b/AUTHORS index e55f94fb..455cf6ca 100644 --- a/AUTHORS +++ b/AUTHORS @@ -133,3 +133,7 @@ Tom Vijlbrief (tomtor) Torsten Franz (torfranz) Uri Blass (uriblass) Vince Negri + +# Additionally, we acknowledge the authors of fishtest, +# an essential framework for the development of Stockfish: +# https://github.com/glinscott/fishtest/blob/master/AUTHORS From 7e4c3256aab178f303578b4c4a31c59d43421640 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 22 Sep 2019 19:48:52 -0600 Subject: [PATCH 077/281] Simplify connected pawn scoring When scoring the connected pawns, replace the intricate ternary expressions choosing the coefficient by a simpler addition of boolean conditions: ` value = Connected * (2 + phalanx - opposed) ` This is the map showing the old coefficients and the new ones: ``` phalanx and unopposed: 3x -> 3x phalanx and opposed: 1.5x -> 2x not phalanx and unopposed: 2x -> 2x not phalanx and opposed: 1x -> 1x ``` STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 11354 W: 2579 L: 2437 D: 6338 http://tests.stockfishchess.org/tests/view/5d8151f00ebc5971531d244f LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 41221 W: 7001 L: 6913 D: 27307 http://tests.stockfishchess.org/tests/view/5d818f930ebc5971531d26d6 Bench: 3959889 blah --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a7a091ab..9521cd10 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -353,7 +353,7 @@ namespace { // Bonus for rook on an open or semi-open file if (pos.is_on_semiopen_file(Us, s)) - score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))]; + score += RookOnFile[pos.is_on_semiopen_file(Them, s)]; // Penalty when trapped by the king, even more if the king cannot castle else if (mob <= 3) diff --git a/src/pawns.cpp b/src/pawns.cpp index 1ae65bf1..f6041199 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -130,7 +130,7 @@ namespace { // Score this pawn if (support | phalanx) { - int v = Connected[r] * (phalanx ? 3 : 2) / (opposed ? 2 : 1) + int v = Connected[r] * (2 + bool(phalanx) - opposed) + 17 * popcount(support); score += make_score(v, v * (r - 2) / 4); From 770c8d92f3886d11ae88afef13f6552f9132a714 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 20 Sep 2019 16:33:57 +0200 Subject: [PATCH 078/281] More random draw evaluations Use the randomized draw function value_draw() also for draw evalutions. This extends the earlier commit https://github.com/official-stockfish/Stockfish/commit/97d2cc9a9c1c4b6ff1b470676fa18c7fc6509886 which did this only for 3folds. As in that case, this test was yellow at STC and LTC, but green at VLTC, indicative of the fact that the higher the drawrate, the more likely this idea is beneficial. STC: LLR: -2.96 (-2.94,2.94) [0.50,4.50] Total: 83573 W: 18584 L: 18335 D: 46654 http://tests.stockfishchess.org/tests/view/5d84e44d0ebc5971531d4f94 LTC: LLR: -2.96 (-2.94,2.94) [0.00,3.50] Total: 92252 W: 15240 L: 15160 D: 61852 http://tests.stockfishchess.org/tests/view/5d865dd90ebc5971531d68e1 VLTC: 120+1.2 @ 2th LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 51902 W: 7323 L: 7028 D: 37551 http://tests.stockfishchess.org/tests/view/5d8763620ebc595f57c22b15 Closes https://github.com/official-stockfish/Stockfish/pull/2321 Bench: 3441237 --- src/search.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 79942bcd..2d5fb630 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -762,6 +762,9 @@ namespace { if (eval == VALUE_NONE) ss->staticEval = eval = evaluate(pos); + if (eval == VALUE_DRAW) + eval = value_draw(depth, thisThread); + // Can ttValue be used as a better position evaluation? if ( ttValue != VALUE_NONE && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))) From 7756344d5d2b93970e7cd423f8cbf6fb1da11b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Mon, 23 Sep 2019 08:52:27 +0200 Subject: [PATCH 079/281] Clarify the mapping of files to queenside Author: @nickpelling We replace in the code the obscure expressions mapping files ABCDEFGH to ABCDDCBA by an explicite call to an auxiliary function : old: f = min(f, ~f) new: f = map_to_queenside(f) We used the Golbolt web site (https://godbolt.org) to find the optimal code for the auxiliary function. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 30292 W: 6756 L: 6651 D: 16885 http://tests.stockfishchess.org/tests/view/5d8676720ebc5971531d6aa1 No functional change --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- src/psqt.cpp | 2 +- src/types.h | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9521cd10..f37820af 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -662,7 +662,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * std::min(f, ~f); + score += bonus - PassedFile * map_to_queenside(f); } if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index f6041199..d822ef4e 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -198,7 +198,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - int d = std::min(f, ~f); + int d = map_to_queenside(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index 36d99feb..13e69499 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -119,7 +119,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = std::min(file_of(s), ~file_of(s)); + File f = map_to_queenside(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][~s] = -psq[pc][s]; diff --git a/src/types.h b/src/types.h index c77d8040..6af03687 100644 --- a/src/types.h +++ b/src/types.h @@ -366,6 +366,10 @@ constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } +inline File map_to_queenside(File f) { + return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA +} + constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } From 302e0f70c653bfcca4338d7be71dfdd1166da910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Mon, 23 Sep 2019 09:10:28 +0200 Subject: [PATCH 080/281] Revert "Clarify the mapping of files to queenside" This reverts commit 7756344d5d2b93970e7cd423f8cbf6fb1da11b74. --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- src/psqt.cpp | 2 +- src/types.h | 4 ---- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f37820af..9521cd10 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -662,7 +662,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * map_to_queenside(f); + score += bonus - PassedFile * std::min(f, ~f); } if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index d822ef4e..f6041199 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -198,7 +198,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - int d = map_to_queenside(f); + int d = std::min(f, ~f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index 13e69499..36d99feb 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -119,7 +119,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = map_to_queenside(file_of(s)); + File f = std::min(file_of(s), ~file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][~s] = -psq[pc][s]; diff --git a/src/types.h b/src/types.h index 6af03687..c77d8040 100644 --- a/src/types.h +++ b/src/types.h @@ -366,10 +366,6 @@ constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } -inline File map_to_queenside(File f) { - return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA -} - constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } From defa1ccaa9c145b0ccff38a1ae660c052d753e81 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Mon, 23 Sep 2019 08:24:13 +0100 Subject: [PATCH 081/281] Encourage rook lift to third rank This change to the Rook psqt encourages rook lifts to the third rank on the two center files. STC 10+0.1 th 1 : LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 40654 W: 9028 L: 8704 D: 22922 http://tests.stockfishchess.org/tests/view/5d885da60ebc5906dd3e9fcd LTC 60+0.6 th 1 : LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 56963 W: 9530 L: 9196 D: 38237 http://tests.stockfishchess.org/tests/view/5d88618c0ebc5906dd3ea45f Thanks to @snicolet for mentioning that Komodo does this a lot and Stockfish doesn't, which gave me the idea for this patch, and to @noobpwnftw for providing cores to fishtest which allowed very quick testing. Future work: perhaps this can be refined somehow to encourage this on other files, my attempts have failed. Closes https://github.com/official-stockfish/Stockfish/pull/2322 Bench: 3950249 --- src/psqt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psqt.cpp b/src/psqt.cpp index 36d99feb..2b06931c 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -61,7 +61,7 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { // Rook { S(-24, -2), S(-13,-6), S(-7, -3), S( 2,-2) }, { S(-18,-10), S(-10,-7), S(-5, 1), S( 9, 0) }, - { S(-21, 10), S( -7,-4), S( 3, 2), S(-1,-2) }, + { S(-21, 10), S( -7,-4), S( 3, 2), S( 7,-2) }, { S(-13, -5), S( -5, 2), S(-4, -8), S(-6, 8) }, { S(-24, -8), S(-12, 5), S(-1, 4), S( 6,-9) }, { S(-24, 3), S( -4,-2), S( 4,-10), S(10, 7) }, From d232a4ae684eccd829fd703a1872c1e0e17aaee9 Mon Sep 17 00:00:00 2001 From: nickpelling Date: Sat, 21 Sep 2019 08:59:32 +0100 Subject: [PATCH 082/281] Clarify the mapping of files to queenside This patch replaces the obscure expressions mapping files ABCDEFGH to ABCDDCBA by explicite calls to an auxiliary function: old: f = min(f, ~f) new: f = map_to_queenside(f) We used the Golbolt web site (https://godbolt.org) to check that the current code for the auxiliary function is optimal. STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 30292 W: 6756 L: 6651 D: 16885 http://tests.stockfishchess.org/tests/view/5d8676720ebc5971531d6aa1 Achieved with a bit of help from Sopel97, snicolet and vondele, thanks everyone! Closes https://github.com/official-stockfish/Stockfish/pull/2325 No functional change --- AUTHORS | 1 + src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- src/psqt.cpp | 2 +- src/types.h | 9 +++++---- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 455cf6ca..aff6a6c9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -99,6 +99,7 @@ Miroslav Fontán (Hexik) Moez Jellouli (MJZ1977) Mohammed Li (tthsqe12) Nathan Rugg (nmrugg) +Nick Pelling (nickpelling) Nicklas Persson (NicklasPersson) Niklas Fiekas (niklasf) Ondrej Mosnáček (WOnder93) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9521cd10..f37820af 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -662,7 +662,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * std::min(f, ~f); + score += bonus - PassedFile * map_to_queenside(f); } if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index f6041199..ca4156da 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -198,7 +198,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - int d = std::min(f, ~f); + File d = map_to_queenside(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index 2b06931c..83d11cf1 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -119,7 +119,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = std::min(file_of(s), ~file_of(s)); + File f = map_to_queenside(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][~s] = -psq[pc][s]; diff --git a/src/types.h b/src/types.h index c77d8040..6d2c09a6 100644 --- a/src/types.h +++ b/src/types.h @@ -43,6 +43,7 @@ #include #include #include +#include #if defined(_MSC_VER) // Disable some silly and noisy warning from MSVC compiler @@ -358,14 +359,14 @@ constexpr Square operator~(Square s) { return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 } -constexpr File operator~(File f) { - return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H -} - constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } +inline File map_to_queenside(File f) { + return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA +} + constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } From 667d24f22743959ceddda6af53718619ea5c551d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 24 Sep 2019 12:41:45 +0200 Subject: [PATCH 083/281] Increase weight for supported pawns This patch changes the weight for counting supports of pawns from 17 to 21. Hopefully Stockfish will accept to play a bit more of closed or semi-closed positions. STC: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 13822 W: 3158 L: 2939 D: 7725 http://tests.stockfishchess.org/tests/view/5d89c3a10ebc595091802379 LTC: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 63066 W: 10590 L: 10236 D: 42240 http://tests.stockfishchess.org/tests/view/5d89ca7f0ebc595091802680 Future work: try to tweak the evaluation to better understand the French structures. Closes https://github.com/official-stockfish/Stockfish/pull/2326 Bench: 3618154 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index ca4156da..50eb3aa3 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -131,7 +131,7 @@ namespace { if (support | phalanx) { int v = Connected[r] * (2 + bool(phalanx) - opposed) - + 17 * popcount(support); + + 21 * popcount(support); score += make_score(v, v * (r - 2) / 4); } From 0436f01d05f05e2669cbb5b4bee752145b5b9991 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 084/281] Temporary patch to show the compiler for TCEC submission This patch shows a description of the compiler used to compile Stockfish, when starting from the console. Usage: ``` ./stockfish compiler ``` Example of output: ``` Stockfish 240919 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 b1539ce2..a5717e7a 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -144,6 +144,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 ddd05e4e..0efdd562 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 a4235f2b..6e560572 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -230,10 +230,11 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "isready") sync_cout << "readyok" << sync_endl; // Additional custom non-UCI commands, mainly for debugging - 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 8726beba59ca10d03cfee5073e4ac51da7cae42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 26 Sep 2019 23:19:31 +0200 Subject: [PATCH 085/281] Restore development version (revert previous commit) Revert the previous patch now that the binary for the super-final of TCEC season 16 has been sent. Maybe the feature of showing the name of compiler will be added to the master branch in the future. But we may use a cleaner way to code it, see some ideas using the Makefile approach at the end of pull request #2327 : https://github.com/official-stockfish/Stockfish/pull/2327 Bench: 3618154 --- src/misc.cpp | 71 ---------------------------------------------------- src/misc.h | 1 - src/uci.cpp | 9 +++---- 3 files changed, 4 insertions(+), 77 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index a5717e7a..b1539ce2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -144,77 +144,6 @@ 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 0efdd562..ddd05e4e 100644 --- a/src/misc.h +++ b/src/misc.h @@ -30,7 +30,6 @@ #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 6e560572..a4235f2b 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -230,11 +230,10 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "isready") sync_cout << "readyok" << sync_endl; // Additional custom non-UCI commands, mainly for debugging - 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 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 sync_cout << "Unknown command: " << cmd << sync_endl; From d703d2b5e760edf4d34b6664f2d0552ffe424b12 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 16 Sep 2019 07:51:25 +0200 Subject: [PATCH 086/281] Remove custom mutex implementation As part of the investigation of the hang caused by an incorrect implementation of condition_variable in libwinpthread, it was realized that our custom Mutex implementation is no longer needed. Prior to lazySMP this custom implementation resulted in a 30% speedup, but now no speed difference can be measured as no mutex is used on the hot path in lazySMP. https://github.com/official-stockfish/Stockfish/issues/2291 https://github.com/official-stockfish/Stockfish/issues/2309#issuecomment-533733393 https://github.com/official-stockfish/Stockfish/issues/2309#issuecomment-533737515 The interest of this patch is that it removes platform-specific code, which is always less tested. No functional change. --- src/misc.cpp | 2 +- src/syzygy/tbprobe.cpp | 10 +++++--- src/thread.cpp | 6 ++--- src/thread.h | 4 +-- src/thread_win32_osx.h | 55 +++--------------------------------------- 5 files changed, 16 insertions(+), 61 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index b1539ce2..17644eed 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -168,7 +168,7 @@ void dbg_print() { std::ostream& operator<<(std::ostream& os, SyncCout sc) { - static Mutex m; + static std::mutex m; if (sc == IO_LOCK) m.lock(); diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 10864744..c7d20788 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -27,12 +27,12 @@ #include #include #include +#include #include "../bitboard.h" #include "../movegen.h" #include "../position.h" #include "../search.h" -#include "../thread_win32_osx.h" #include "../types.h" #include "../uci.h" @@ -45,7 +45,9 @@ #include #else #define WIN32_LEAN_AND_MEAN -#define NOMINMAX +#ifndef NOMINMAX +# define NOMINMAX // Disable macros min() and max() +#endif #include #endif @@ -1124,14 +1126,14 @@ void set(T& e, uint8_t* data) { template void* mapped(TBTable& e, const Position& pos) { - static Mutex mutex; + static std::mutex mutex; // Use 'acquire' to avoid a thread reading 'ready' == true while // another is still working. (compiler reordering may cause this). if (e.ready.load(std::memory_order_acquire)) return e.baseAddress; // Could be nullptr if file does not exist - std::unique_lock lk(mutex); + std::unique_lock lk(mutex); if (e.ready.load(std::memory_order_relaxed)) // Recheck under lock return e.baseAddress; diff --git a/src/thread.cpp b/src/thread.cpp index 5165fd90..f7445f98 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -81,7 +81,7 @@ void Thread::clear() { void Thread::start_searching() { - std::lock_guard lk(mutex); + std::lock_guard lk(mutex); searching = true; cv.notify_one(); // Wake up the thread in idle_loop() } @@ -92,7 +92,7 @@ void Thread::start_searching() { void Thread::wait_for_search_finished() { - std::unique_lock lk(mutex); + std::unique_lock lk(mutex); cv.wait(lk, [&]{ return !searching; }); } @@ -112,7 +112,7 @@ void Thread::idle_loop() { while (true) { - std::unique_lock lk(mutex); + std::unique_lock lk(mutex); searching = false; cv.notify_one(); // Wake up anyone waiting for search finished cv.wait(lk, [&]{ return searching; }); diff --git a/src/thread.h b/src/thread.h index ed427b10..79c6e43f 100644 --- a/src/thread.h +++ b/src/thread.h @@ -42,8 +42,8 @@ class Thread { - Mutex mutex; - ConditionVariable cv; + std::mutex mutex; + std::condition_variable cv; size_t idx; bool exit = false, searching = true; // Set before starting std::thread NativeThread stdThread; diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index 5583a06e..f8cb466b 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -21,60 +21,13 @@ #ifndef THREAD_WIN32_OSX_H_INCLUDED #define THREAD_WIN32_OSX_H_INCLUDED -/// STL thread library used by mingw and gcc when cross compiling for Windows -/// relies on libwinpthread. Currently libwinpthread implements mutexes directly -/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel -/// mode transition in order to lock or unlock, which is very slow compared to -/// interlocked operations (about 30% slower on bench test). To work around this -/// issue, we define our wrappers to the low level Win32 calls. We use critical -/// sections to support Windows XP and older versions. Unfortunately, cond_wait() -/// is racy between unlock() and WaitForSingleObject() but they have the same -/// speed performance as the SRW locks. - -#include -#include #include -#if defined(_WIN32) && !defined(_MSC_VER) - -#ifndef NOMINMAX -# define NOMINMAX // Disable macros min() and max() -#endif - -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN -#undef NOMINMAX - -/// Mutex and ConditionVariable struct are wrappers of the low level locking -/// machinery and are modeled after the corresponding C++11 classes. - -struct Mutex { - Mutex() { InitializeCriticalSection(&cs); } - ~Mutex() { DeleteCriticalSection(&cs); } - void lock() { EnterCriticalSection(&cs); } - void unlock() { LeaveCriticalSection(&cs); } - -private: - CRITICAL_SECTION cs; -}; - -typedef std::condition_variable_any ConditionVariable; - -#else // Default case: use STL classes - -typedef std::mutex Mutex; -typedef std::condition_variable ConditionVariable; - -#endif - /// On OSX threads other than the main thread are created with a reduced stack -/// size of 512KB by default, this is dangerously low for deep searches, so -/// adjust it to TH_STACK_SIZE. The implementation calls pthread_create() with -/// proper stack size parameter. - -/// On toolchains where pthread is always available, ensure minimum stack size -/// instead of relying on linker defaults which may be platform-specific. +/// size of 512KB by default, this is too low for deep searches, which require +/// somewhat more than 1MB stack, so adjust it to TH_STACK_SIZE. +/// The implementation calls pthread_create() with the stack size parameter +/// equal to the linux 8MB default, on platforms that support it. #if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__) From 28dcd700a9dd3c776b66b2032cf0cf6df88b671d Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Wed, 25 Sep 2019 23:23:07 -0400 Subject: [PATCH 087/281] Simplify RookOnPawn Remove the RookOnPawn logic (for rook on rank 5 and above aligning with pawns on same row or file) which was overlapping with a few other parameters. Inspired by @31m059 interesting result hinting that a direct attack on pawns instead of PseudoAttacks might work. http://tests.stockfishchess.org/tests/view/5d89a7c70ebc595091801b8d After a few attempts by me and @31m059, and some long STC greens but red LTC, as a proof of concept I first tried a local SPSA at VSTC trying to tune related rook psqt rows, and mainly some rook related stuff in evaluate.cpp. Result was STC green, but still red LTC, Finally a 100M fishtest SPSA at LTC proved successful both at STC and LTC. All this was possible with the awesome fishtest contributors. At some point, I had 850 workers on the last test ! Run as a simplification STC http://tests.stockfishchess.org/tests/view/5d8d68f40ebc590f3beaf171 LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 7399 W: 1693 L: 1543 D: 4163 LTC http://tests.stockfishchess.org/tests/view/5d8d70270ebc590f3beaf63c LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 41617 W: 6981 L: 6894 D: 27742 Closes https://github.com/official-stockfish/Stockfish/pull/2329 bench: 4037914 --- src/evaluate.cpp | 15 +++++---------- src/psqt.cpp | 16 ++++++++-------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f37820af..880aa137 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -78,7 +78,7 @@ namespace { constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type - constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 77, 55, 44, 10 }; + constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; @@ -108,17 +108,17 @@ namespace { // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. - constexpr Score RookOnFile[] = { S(18, 7), S(44, 20) }; + constexpr Score RookOnFile[] = { S(21, 4), S(47, 25) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(0, 31), S(39, 42), S(57, 44), S(68, 112), S(62, 120) + S(0, 0), S(6, 28), S(39, 42), S(57, 44), S(68, 112), S(62, 120) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(0, 24), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -139,8 +139,7 @@ namespace { constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnPawn = S( 10, 32); - constexpr Score RookOnQueenFile = S( 11, 4); + constexpr Score RookOnQueenFile = S( 7, 6); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); @@ -343,10 +342,6 @@ namespace { if (Pt == ROOK) { - // Bonus for aligning rook with enemy pawns on the same rank/file - if (relative_rank(Us, s) >= RANK_5) - score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); - // Bonus for rook on the same file as a queen if (file_bb(s) & pos.pieces(QUEEN)) score += RookOnQueenFile; diff --git a/src/psqt.cpp b/src/psqt.cpp index 83d11cf1..655eb993 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -59,14 +59,14 @@ constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = { { S(-48,-51), S( -3,-40), S(-12,-39), S(-25,-20) } }, { // Rook - { S(-24, -2), S(-13,-6), S(-7, -3), S( 2,-2) }, - { S(-18,-10), S(-10,-7), S(-5, 1), S( 9, 0) }, - { S(-21, 10), S( -7,-4), S( 3, 2), S( 7,-2) }, - { S(-13, -5), S( -5, 2), S(-4, -8), S(-6, 8) }, - { S(-24, -8), S(-12, 5), S(-1, 4), S( 6,-9) }, - { S(-24, 3), S( -4,-2), S( 4,-10), S(10, 7) }, - { S( -8, 1), S( 6, 2), S(10, 17), S(12,-8) }, - { S(-22, 12), S(-24,-6), S(-6, 13), S( 4, 7) } + { 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 3a3ca6af0390d74427c218f29cb5fe1a913efb42 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Fri, 27 Sep 2019 02:45:28 -0400 Subject: [PATCH 088/281] Extend castling independently of singular extension A curious feature of Stockfish's current extension code is its repeated use of "else if." In most cases, this makes no functional difference, because no more than one extension is applied; once one extension has been applied, the remaining ones can be safely ignored. However, if most singular extension search conditions are true, except "value < singularBeta", no non-singular extensions (e.g., castling) can be performed! Three tests were submitted, for three of Stockfish's four non-singular extensions. I excluded the shuffle extension, because historically there have been concerns about the fragility of its conditions, and I did not want to risk causing any serious search problems. - Modifying the passed pawn extension appeared roughly neutral at STC. At best, it appeared to be an improvement of less than 1 Elo. - Modifying check extension performed very poorly at STC - Modifying castling extension (this patch) produced a long "yellow" run at STC (insufficient to pass, but positive score) and a strong LTC. In simple terms, prior to this patch castling extension was occasionally not applied during search--on castling moves. The effect of this patch is to perform castling extension on more castling moves. It does so without adding any code complexity, simply by replacing an "else if" with "if" and reordering some existing code. STC: LLR: -2.96 (-2.94,2.94) [0.00,4.00] Total: 108114 W: 23877 L: 23615 D: 60622 http://tests.stockfishchess.org/tests/view/5d8d86bd0ebc590f3beb0c88 LTC: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 20862 W: 3517 L: 3298 D: 14047 http://tests.stockfishchess.org/tests/view/5d8d99cd0ebc590f3beb1899 Bench: 3728191 -------- Where do we go from here? - It seems strange to me that check extension performed so poorly -- clearly some of the singular extension conditions are also very important for check extension. I am not an expert in search, and I do not have any intuition about which of the eight conditions is/are the culprit. I will try a succession of eight STC tests to identify the relevant conditions, then try to replicate this PR for check extension. - Recent tests interacting with the castle extension may deserve retesting. I will shortly resubmit a few of my recent castling extension tweaks, rebased on this PR/commit. My deepest thanks to @noobpwnftw for the extraordinary CPU donation, and to all our other fishtest volunteers, who made it possible for a speculative LTC to pass in 70 minutes! Closes https://github.com/official-stockfish/Stockfish/pull/2331 --- src/search.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2d5fb630..01de12a4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -997,10 +997,6 @@ moves_loop: // When in check, search starts from here && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))) extension = ONE_PLY; - // Castling extension - else if (type_of(move) == CASTLING) - extension = ONE_PLY; - // Shuffle extension else if ( PvNode && pos.rule50_count() > 18 @@ -1013,6 +1009,10 @@ moves_loop: // When in check, search starts from here && pos.advanced_pawn_push(move) && pos.pawn_passed(us, to_sq(move))) extension = ONE_PLY; + + // Castling extension + if (type_of(move) == CASTLING) + extension = ONE_PLY; // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; From 70a38d726410dae06949e9cfd6be2fd58743101a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 27 Sep 2019 19:25:22 +0200 Subject: [PATCH 089/281] Remove depth dependence in value_draw(). The condition "depth >= 4 * ONE_PLY" does not seem needed at this point. passed STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 32751 W: 7178 L: 7078 D: 18495 http://tests.stockfishchess.org/tests/view/5d8e46660ebc590f3bebad5e passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 31693 W: 5299 L: 5196 D: 21198 http://tests.stockfishchess.org/tests/view/5d8e4b4f0ebc590f3bebb165 Bench: 4062526 --- src/search.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 01de12a4..2ad535cc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -86,9 +86,8 @@ namespace { } // Add a small random component to draw evaluations to avoid 3fold-blindness - Value value_draw(Depth depth, Thread* thisThread) { - return depth < 4 * ONE_PLY ? VALUE_DRAW - : VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); + Value value_draw(Thread* thisThread) { + return VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); } // Skill structure is used to implement strength limit @@ -574,7 +573,7 @@ namespace { && !rootNode && pos.has_game_cycle(ss->ply)) { - alpha = value_draw(depth, pos.this_thread()); + alpha = value_draw(pos.this_thread()); if (alpha >= beta) return alpha; } @@ -624,7 +623,7 @@ namespace { || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) - : value_draw(depth, pos.this_thread()); + : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because @@ -763,7 +762,7 @@ namespace { ss->staticEval = eval = evaluate(pos); if (eval == VALUE_DRAW) - eval = value_draw(depth, thisThread); + eval = value_draw(thisThread); // Can ttValue be used as a better position evaluation? if ( ttValue != VALUE_NONE From abd4400c874ab178d04c08d3668f3843aece114e Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 30 Sep 2019 15:10:44 -0600 Subject: [PATCH 090/281] Remove ThreatByRank This is a functional simplification that removes ThreatByRank. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 48009 W: 10630 L: 10560 D: 26819 http://tests.stockfishchess.org/tests/view/5d92095c0ebc594fb88eb61e LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 18682 W: 3177 L: 3053 D: 12452 http://tests.stockfishchess.org/tests/view/5d9231120ebc594fb88ebacd Moving forward, it's possible that ThreatByMinor and ThreatByRook could be combined, but I haven't really contemplated that yet. Closes https://github.com/official-stockfish/Stockfish/pull/2336 bench 4088701 --- src/evaluate.cpp | 17 +++-------------- src/search.cpp | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 880aa137..fadc0fea 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -114,7 +114,7 @@ namespace { // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(6, 28), S(39, 42), S(57, 44), S(68, 112), S(62, 120) + S(0, 0), S(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { @@ -143,7 +143,6 @@ namespace { constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); - constexpr Score ThreatByRank = S( 13, 0); constexpr Score ThreatBySafePawn = S(173, 94); constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); @@ -510,21 +509,11 @@ namespace { { b = (defended | weak) & (attackedBy[Us][KNIGHT] | attackedBy[Us][BISHOP]); while (b) - { - Square s = pop_lsb(&b); - score += ThreatByMinor[type_of(pos.piece_on(s))]; - if (type_of(pos.piece_on(s)) != PAWN) - score += ThreatByRank * (int)relative_rank(Them, s); - } + score += ThreatByMinor[type_of(pos.piece_on(pop_lsb(&b)))]; b = weak & attackedBy[Us][ROOK]; while (b) - { - Square s = pop_lsb(&b); - score += ThreatByRook[type_of(pos.piece_on(s))]; - if (type_of(pos.piece_on(s)) != PAWN) - score += ThreatByRank * (int)relative_rank(Them, s); - } + score += ThreatByRook[type_of(pos.piece_on(pop_lsb(&b)))]; if (weak & attackedBy[Us][KING]) score += ThreatByKing; diff --git a/src/search.cpp b/src/search.cpp index 2ad535cc..d34e1823 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1008,7 +1008,7 @@ moves_loop: // When in check, search starts from here && pos.advanced_pawn_push(move) && pos.pawn_passed(us, to_sq(move))) extension = ONE_PLY; - + // Castling extension if (type_of(move) == CASTLING) extension = ONE_PLY; From 005ad170c1dccdcd4ce73074302828ea22628b70 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 25 Sep 2019 21:24:05 +0200 Subject: [PATCH 091/281] Adjust reductions based on the number of threads In lazySMP it makes sense to prune a little more, as multiple threads search wider. We thus increase the prefactor of the reductions slowly as a function of the threads. The prefactor of the log(threads) term is a parameter, this pull request uses 1/2 after testing. passed STC @ 8threads: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 118125 W: 23151 L: 22462 D: 72512 http://tests.stockfishchess.org/tests/view/5d8bbf4d0ebc59509180f217 passed LTC @ 8threads: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 67546 W: 10630 L: 10279 D: 46637 http://tests.stockfishchess.org/tests/view/5d8c463b0ebc5950918167e8 passed ~LTC @ 14threads: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 74271 W: 12421 L: 12040 D: 49810 http://tests.stockfishchess.org/tests/view/5d8db1f50ebc590f3beb24ef Note: A larger prefactor (1) passed similar tests at STC and LTC (8 threads), while a very large one (2) passed STC quickly but failed LTC (8 threads). For the single-threaded case there is no functional change. Closes https://github.com/official-stockfish/Stockfish/pull/2337 Bench: 4088701 Fixup: remove redundant code. --- src/main.cpp | 1 - src/search.cpp | 2 +- src/thread.cpp | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f94a322c..40081e8d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,7 +43,6 @@ int main(int argc, char* argv[]) { Position::init(); Bitbases::init(); Endgames::init(); - Search::init(); Threads.set(Options["Threads"]); Search::clear(); // After threads are up diff --git a/src/search.cpp b/src/search.cpp index d34e1823..55df6172 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -191,7 +191,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int(23.4 * std::log(i)); + Reductions[i] = int((23.4 + std::log(Threads.size()) / 2) * std::log(i)); } diff --git a/src/thread.cpp b/src/thread.cpp index f7445f98..90ec274d 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -148,6 +148,9 @@ void ThreadPool::set(size_t requested) { // Reallocate the hash with the new threadpool size TT.resize(Options["Hash"]); + + // Init thread number dependent search params. + Search::init(); } } From e6f4b5f46344d638c5e3b27cdbc966899e80e8d6 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Fri, 27 Sep 2019 10:18:22 +0200 Subject: [PATCH 092/281] More accurate pawn attack span definition Tweak the pawn attack span for backward pawns and the zone behind opponent opposing pawns. This is important in positional play and one of weaknesses of the engine in recent high level games. STC LLR: -2.95 (-2.94,2.94) [0.50,4.50] Total: 66843 W: 14884 L: 14717 D: 37242 http://tests.stockfishchess.org/tests/view/5d8dcb1b0ebc590f3beb2956 LTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 77699 W: 12993 L: 12602 D: 52104 http://tests.stockfishchess.org/tests/view/5d8de9bc0ebc590f3beb3d00 See discussion in https://github.com/official-stockfish/Stockfish/pull/2332 Bench: 4012371 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fadc0fea..ee98da90 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -135,7 +135,7 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 18, 6); + constexpr Score Outpost = S( 16, 5); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); diff --git a/src/pawns.cpp b/src/pawns.cpp index 50eb3aa3..8022ae51 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -71,10 +71,10 @@ namespace { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - Bitboard neighbours, stoppers, support, phalanx; + Bitboard neighbours, stoppers, support, phalanx, opposed; Bitboard lever, leverPush; Square s; - bool opposed, backward, passed, doubled; + bool backward, passed, doubled; Score score = SCORE_ZERO; const Square* pl = pos.squares(Us); @@ -94,8 +94,6 @@ namespace { Rank r = relative_rank(Us, s); - e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); - // Flag the pawn opposed = theirPawns & forward_file_bb(Us, s); stoppers = theirPawns & passed_pawn_span(Us, s); @@ -112,6 +110,17 @@ namespace { backward = !(neighbours & forward_ranks_bb(Them, s)) && (stoppers & (leverPush | (s + Up))); + // Span of backward pawns and span behind opposing pawns are not included + // in the pawnAttacksSpan bitboard. + if (!backward || phalanx) + { + if (opposed) + e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s) & + ~pawn_attack_span(Us, frontmost_sq(Them, opposed)); + else + e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); + } + // A pawn is passed if one of the three following conditions is true: // (a) there is no stoppers except some levers // (b) the only stoppers are the leverPush, but we outnumber them @@ -130,17 +139,19 @@ namespace { // Score this pawn if (support | phalanx) { - int v = Connected[r] * (2 + bool(phalanx) - opposed) + int v = Connected[r] * (2 + bool(phalanx) - bool(opposed)) + 21 * popcount(support); score += make_score(v, v * (r - 2) / 4); } else if (!neighbours) - score -= Isolated + WeakUnopposed * !opposed; + score -= Isolated + + WeakUnopposed * !opposed; else if (backward) - score -= Backward + WeakUnopposed * !opposed; + score -= Backward + + WeakUnopposed * !opposed; if (!support) score -= Doubled * doubled From 5d1568632ca42b400dff73f5e74ae613e73ed889 Mon Sep 17 00:00:00 2001 From: mstembera Date: Sat, 24 Aug 2019 15:04:41 -0700 Subject: [PATCH 093/281] Remove temporary shelter array Remove temporary array of shelters and avoid iterating over it each time to find if the shelter values after castling are better than the current value. Work done on top of https://github.com/official-stockfish/Stockfish/pull/2277 Speed benchmark did not measure any difference. No functional change --- src/pawns.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 8022ae51..bc1cf38a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -231,21 +231,17 @@ Score Entry::do_king_safety(const Position& pos) { Square ksq = pos.square(Us); kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); + auto compare = [](Score a, Score b) { return mg_value(a) <= mg_value(b); }; - Score shelters[3] = { evaluate_shelter(pos, ksq), - make_score(-VALUE_INFINITE, 0), - make_score(-VALUE_INFINITE, 0) }; + Score shelter = evaluate_shelter(pos, ksq); // If we can castle use the bonus after castling if it is bigger + if (pos.can_castle(Us & KING_SIDE)) - shelters[1] = evaluate_shelter(pos, relative_square(Us, SQ_G1)); + shelter = std::max(shelter, evaluate_shelter(pos, relative_square(Us, SQ_G1)), compare); if (pos.can_castle(Us & QUEEN_SIDE)) - shelters[2] = evaluate_shelter(pos, relative_square(Us, SQ_C1)); - - for (int i : {1, 2}) - if (mg_value(shelters[i]) > mg_value(shelters[0])) - shelters[0] = shelters[i]; + shelter = std::max(shelter, evaluate_shelter(pos, relative_square(Us, SQ_C1)), compare); // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); @@ -256,7 +252,7 @@ Score Entry::do_king_safety(const Position& pos) { else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); - return shelters[0] - make_score(0, 16 * minPawnDist); + return shelter - make_score(0, 16 * minPawnDist); } // Explicit template instantiation From 328bdd0947ea7903ee1061c8eb60bc3121a4eb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sat, 5 Oct 2019 11:15:24 +0200 Subject: [PATCH 094/281] Fix compare function in previous patch Bench: 4012371 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index bc1cf38a..1e5b4f43 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -231,7 +231,7 @@ Score Entry::do_king_safety(const Position& pos) { Square ksq = pos.square(Us); kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); - auto compare = [](Score a, Score b) { return mg_value(a) <= mg_value(b); }; + auto compare = [](Score a, Score b) { return mg_value(a) < mg_value(b); }; Score shelter = evaluate_shelter(pos, ksq); From ca7d4e9ac7b5ca74be8aa807fbdf139b2a0860ab Mon Sep 17 00:00:00 2001 From: Brian Sheppard Date: Sat, 28 Sep 2019 16:27:23 -0400 Subject: [PATCH 095/281] Eliminate ONE_PLY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplification that eliminates ONE_PLY, based on a suggestion in the forum that support for fractional plies has never been used, and @mcostalba's openness to the idea of eliminating it. We lose a little bit of type safety by making Depth an integer, but in return we simplify the code in search.cpp quite significantly. No functional change ------------------------------------------ The argument favoring eliminating ONE_PLY: * The term “ONE_PLY” comes up in a lot of forum posts (474 to date) https://groups.google.com/forum/?fromgroups=#!searchin/fishcooking/ONE_PLY%7Csort:relevance * There is occasionally a commit that breaks invariance of the code with respect to ONE_PLY https://groups.google.com/forum/?fromgroups=#!searchin/fishcooking/ONE_PLY%7Csort:date/fishcooking/ZIPdYj6k0fk/KdNGcPWeBgAJ * To prevent such commits, there is a Travis CI hack that doubles ONE_PLY and rechecks bench * Sustaining ONE_PLY has, alas, not resulted in any improvements to the engine, despite many individuals testing many experiments over 5 years. The strongest argument in favor of preserving ONE_PLY comes from @locutus: “If we use par example ONE_PLY=256 the parameter space is increases by the factor 256. So it seems very unlikely that the optimal setting is in the subspace of ONE_PLY=1.” There is a strong theoretical impediment to fractional depth systems: the transposition table uses depth to determine when a stored result is good enough to supply an answer for a current search. If you have fractional depths, then different pathways to the position can be at fractionally different depths. In the end, there are three separate times when a proposal to remove ONE_PLY was defeated by the suggestion to “give it a few more months.” So… it seems like time to remove this distraction from the community. See the pull request here: https://github.com/official-stockfish/Stockfish/pull/2289 --- .travis.yml | 3 - src/movepick.cpp | 6 +- src/search.cpp | 148 +++++++++++++++++++++++------------------------ src/thread.cpp | 2 +- src/tt.cpp | 8 +-- src/tt.h | 2 +- src/types.h | 17 ++---- 7 files changed, 86 insertions(+), 100 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d56a23e..a59ea425 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,9 +56,6 @@ script: - make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref - make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref - # Verify bench number is ONE_PLY independent by doubling its value - - sed -i'.bak' 's/.*\(ONE_PLY = [0-9]*\),.*/\1 * 2,/g' types.h - - make clean && make -j2 ARCH=x86-64 build && ../tests/signature.sh $benchref # # Check perft and reproducible search - ../tests/perft.sh diff --git a/src/movepick.cpp b/src/movepick.cpp index 64380da9..fab8cea8 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -61,7 +61,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) { - assert(d > DEPTH_ZERO); + assert(d > 0); stage = pos.checkers() ? EVASION_TT : MAIN_TT; ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; @@ -73,7 +73,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) { - assert(d <= DEPTH_ZERO); + assert(d <= 0); stage = pos.checkers() ? EVASION_TT : QSEARCH_TT; ttMove = ttm @@ -206,7 +206,7 @@ top: endMoves = generate(pos, cur); score(); - partial_insertion_sort(cur, endMoves, -4000 * depth / ONE_PLY); + partial_insertion_sort(cur, endMoves, -4000 * depth); } ++stage; diff --git a/src/search.cpp b/src/search.cpp index 55df6172..c05e72e0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -64,15 +64,15 @@ namespace { // Razor and futility margins constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { - return Value(198 * (d / ONE_PLY - improving)); + return Value(198 * (d - improving)); } // Reductions lookup table, initialized at startup int Reductions[MAX_MOVES]; // [depth or moveNumber] Depth reduction(bool i, Depth d, int mn) { - int r = Reductions[d / ONE_PLY] * Reductions[mn]; - return ((r + 520) / 1024 + (!i && r > 999)) * ONE_PLY; + int r = Reductions[d] * Reductions[mn]; + return (r + 520) / 1024 + (!i && r > 999); } constexpr int futility_move_count(bool improving, int depth) { @@ -80,8 +80,7 @@ namespace { } // History and stats update bonus, based on depth - int stat_bonus(Depth depth) { - int d = depth / ONE_PLY; + int stat_bonus(Depth d) { return d > 17 ? -8 : 22 * d * d + 151 * d - 140; } @@ -94,7 +93,7 @@ namespace { struct Skill { explicit Skill(int l) : level(l) {} bool enabled() const { return level < 20; } - bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; } + bool time_to_pick(Depth depth) const { return depth == 1 + level; } Move pick_best(size_t multiPV); int level; @@ -148,7 +147,7 @@ namespace { Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); template - Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = DEPTH_ZERO); + 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); @@ -164,16 +163,16 @@ namespace { StateInfo st; uint64_t cnt, nodes = 0; - const bool leaf = (depth == 2 * ONE_PLY); + const bool leaf = (depth == 2); for (const auto& m : MoveList(pos)) { - if (Root && depth <= ONE_PLY) + if (Root && depth <= 1) cnt = 1, nodes++; else { pos.do_move(m, st); - cnt = leaf ? MoveList(pos).size() : perft(pos, depth - ONE_PLY); + cnt = leaf ? MoveList(pos).size() : perft(pos, depth - 1); nodes += cnt; pos.undo_move(m); } @@ -215,7 +214,7 @@ void MainThread::search() { if (Limits.perft) { - nodes = perft(rootPos, Limits.perft * ONE_PLY); + nodes = perft(rootPos, Limits.perft); sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl; return; } @@ -328,7 +327,7 @@ void Thread::search() { Move pv[MAX_PLY+1]; Value bestValue, alpha, beta, delta; Move lastBestMove = MOVE_NONE; - Depth lastBestMoveDepth = DEPTH_ZERO; + Depth lastBestMoveDepth = 0; MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); double timeReduction = 1, totBestMoveChanges = 0; Color us = rootPos.side_to_move(); @@ -378,9 +377,9 @@ void Thread::search() { : -make_score(ct, ct / 2)); // Iterative deepening loop until requested to stop or the target depth is reached - while ( (rootDepth += ONE_PLY) < DEPTH_MAX + while ( ++rootDepth < MAX_PLY && !Threads.stop - && !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth)) + && !(Limits.depth && mainThread && rootDepth > Limits.depth)) { // Age out PV variability metric if (mainThread) @@ -409,7 +408,7 @@ void Thread::search() { selDepth = 0; // Reset aspiration window starting size - if (rootDepth >= 4 * ONE_PLY) + if (rootDepth >= 4) { Value previousScore = rootMoves[pvIdx].previousScore; delta = Value(23); @@ -429,7 +428,7 @@ void Thread::search() { int failedHighCnt = 0; while (true) { - Depth adjustedDepth = std::max(ONE_PLY, rootDepth - failedHighCnt * ONE_PLY); + Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt); bestValue = ::search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting @@ -519,7 +518,7 @@ void Thread::search() { fallingEval = clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 9 * ONE_PLY < completedDepth ? 1.97 : 0.98; + timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.97 : 0.98; double reduction = (1.36 + mainThread->previousTimeReduction) / (2.29 * timeReduction); // Use part of the gained time from a previous stable move for the current move @@ -579,14 +578,13 @@ namespace { } // Dive into quiescence search when the depth reaches zero - if (depth < ONE_PLY) + if (depth <= 0) return qsearch(pos, ss, alpha, beta); assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); - assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); + assert(0 < depth && depth < MAX_PLY); assert(!(PvNode && cutNode)); - assert(depth / ONE_PLY * ONE_PLY == depth); Move pv[MAX_PLY+1], capturesSearched[32], quietsSearched[64]; StateInfo st; @@ -683,7 +681,7 @@ namespace { // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !pos.captured_piece()) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); } // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) @@ -730,7 +728,7 @@ namespace { || (b == BOUND_LOWER ? value >= beta : value <= alpha)) { tte->save(posKey, value_to_tt(value, ss->ply), ttPv, b, - std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), + std::min(MAX_PLY - 1, depth + 6), MOVE_NONE, VALUE_NONE); return value; @@ -785,7 +783,7 @@ namespace { // Step 7. Razoring (~2 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch - && depth < 2 * ONE_PLY + && depth < 2 && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); @@ -794,7 +792,7 @@ namespace { // Step 8. Futility pruning: child node (~30 Elo) if ( !PvNode - && depth < 7 * ONE_PLY + && depth < 7 && eval - futility_margin(depth, improving) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; @@ -805,7 +803,7 @@ namespace { && (ss-1)->statScore < 22661 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30 + && ss->staticEval >= beta - 33 * depth + 299 - improving * 30 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -813,7 +811,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = ((835 + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY; + Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; @@ -830,14 +828,14 @@ namespace { if (nullValue >= VALUE_MATE_IN_MAX_PLY) nullValue = beta; - if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13 * ONE_PLY)) + if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13)) return nullValue; assert(!thisThread->nmpMinPly); // Recursive verification is not allowed // Do verification search at high depths, with null move pruning disabled // for us, until ply exceeds nmpMinPly. - thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / (4 * ONE_PLY); + thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / 4; thisThread->nmpColor = us; Value v = search(pos, ss, beta-1, beta, depth-R, false); @@ -853,7 +851,7 @@ namespace { // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth >= 5 * ONE_PLY + && depth >= 5 && abs(beta) < VALUE_MATE_IN_MAX_PLY) { Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE); @@ -869,7 +867,7 @@ namespace { ss->currentMove = move; ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)]; - assert(depth >= 5 * ONE_PLY); + assert(depth >= 5); pos.do_move(move, st); @@ -878,7 +876,7 @@ namespace { // If the qsearch held, perform the regular search if (value >= raisedBeta) - value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4 * ONE_PLY, !cutNode); + value = -search(pos, ss+1, -raisedBeta, -raisedBeta+1, depth - 4, !cutNode); pos.undo_move(move); @@ -888,9 +886,9 @@ namespace { } // Step 11. Internal iterative deepening (~2 Elo) - if (depth >= 7 * ONE_PLY && !ttMove) + if (depth >= 7 && !ttMove) { - search(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode); + search(pos, ss, alpha, beta, depth - 7, cutNode); tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; @@ -938,13 +936,13 @@ moves_loop: // When in check, search starts from here ss->moveCount = ++moveCount; if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000) - sync_cout << "info depth " << depth / ONE_PLY + sync_cout << "info depth " << depth << " currmove " << UCI::move(move, pos.is_chess960()) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; if (PvNode) (ss+1)->pv = nullptr; - extension = DEPTH_ZERO; + extension = 0; captureOrPromotion = pos.capture_or_promotion(move); movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); @@ -956,28 +954,28 @@ moves_loop: // When in check, search starts from here // 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 // result is lower than ttValue minus a margin then we will extend the ttMove. - if ( depth >= 6 * ONE_PLY + if ( depth >= 6 && move == ttMove && !rootNode && !excludedMove // Avoid recursive singular search /* && ttValue != VALUE_NONE Already implicit in the next condition */ && abs(ttValue) < VALUE_KNOWN_WIN && (tte->bound() & BOUND_LOWER) - && tte->depth() >= depth - 3 * ONE_PLY + && tte->depth() >= depth - 3 && pos.legal(move)) { - Value singularBeta = ttValue - 2 * depth / ONE_PLY; - Depth halfDepth = depth / (2 * ONE_PLY) * ONE_PLY; // ONE_PLY invariant + Value singularBeta = ttValue - 2 * depth; + Depth halfDepth = depth / 2; ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); ss->excludedMove = MOVE_NONE; if (value < singularBeta) { - extension = ONE_PLY; + extension = 1; singularLMR++; - if (value < singularBeta - std::min(4 * depth / ONE_PLY, 36)) + if (value < singularBeta - std::min(4 * depth, 36)) singularLMR++; } @@ -994,27 +992,27 @@ moves_loop: // When in check, search starts from here // Check extension (~2 Elo) else if ( givesCheck && (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))) - extension = ONE_PLY; + extension = 1; // Shuffle extension else if ( PvNode && pos.rule50_count() > 18 - && depth < 3 * ONE_PLY + && depth < 3 && ++thisThread->shuffleExts < thisThread->nodes.load(std::memory_order_relaxed) / 4) // To avoid too many extensions - extension = ONE_PLY; + extension = 1; // Passed pawn extension else if ( move == ss->killers[0] && pos.advanced_pawn_push(move) && pos.pawn_passed(us, to_sq(move))) - extension = ONE_PLY; + extension = 1; // Castling extension if (type_of(move) == CASTLING) - extension = ONE_PLY; + extension = 1; // Calculate new depth for this move - newDepth = depth - ONE_PLY + extension; + newDepth = depth - 1 + extension; // Step 14. Pruning at shallow depth (~170 Elo) if ( !rootNode @@ -1022,7 +1020,7 @@ moves_loop: // When in check, search starts from here && bestValue > VALUE_MATED_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth / ONE_PLY); + moveCountPruning = moveCount >= futility_move_count(improving, depth); if ( !captureOrPromotion && !givesCheck @@ -1033,8 +1031,7 @@ moves_loop: // When in check, search starts from here continue; // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO); - lmrDepth /= ONE_PLY; + 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) @@ -1053,7 +1050,7 @@ moves_loop: // When in check, search starts from here continue; } else if ( !(givesCheck && extension) - && !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo) + && !pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) continue; } @@ -1076,7 +1073,7 @@ moves_loop: // When in check, search starts from here // Step 16. Reduced depth search (LMR). If the move fails high it will be // re-searched at full depth. - if ( depth >= 3 * ONE_PLY + if ( depth >= 3 && moveCount > 1 + 2 * rootNode && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion @@ -1088,35 +1085,35 @@ moves_loop: // When in check, search starts from here // Reduction if other threads are searching this position. if (th.marked()) - r += ONE_PLY; + r++; // Decrease reduction if position is or has been on the PV if (ttPv) - r -= 2 * ONE_PLY; + r -= 2; // Decrease reduction if opponent's move count is high (~10 Elo) if ((ss-1)->moveCount > 15) - r -= ONE_PLY; + r--; // Decrease reduction if ttMove has been singularly extended - r -= singularLMR * ONE_PLY; + r -= singularLMR; if (!captureOrPromotion) { // Increase reduction if ttMove is a capture (~0 Elo) if (ttCapture) - r += ONE_PLY; + r++; // Increase reduction for cut nodes (~5 Elo) if (cutNode) - r += 2 * ONE_PLY; + 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) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) - r -= 2 * ONE_PLY; + r -= 2; ss->statScore = thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] @@ -1133,16 +1130,16 @@ moves_loop: // When in check, search starts from here // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) if (ss->statScore >= -99 && (ss-1)->statScore < -116) - r -= ONE_PLY; + r--; else if ((ss-1)->statScore >= -117 && ss->statScore < -144) - r += ONE_PLY; + r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 16384 * ONE_PLY; + r -= ss->statScore / 16384; } - Depth d = clamp(newDepth - r, ONE_PLY, newDepth); + Depth d = clamp(newDepth - r, 1, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); @@ -1276,18 +1273,18 @@ moves_loop: // When in check, search starts from here // 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 ? ONE_PLY : DEPTH_ZERO))); + stat_bonus(depth + (bestValue > beta + PawnValueMg))); - update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + ONE_PLY)); + 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])) && !pos.captured_piece()) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); + 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 * ONE_PLY || PvNode) + else if ( (depth >= 3 || PvNode) && !pos.captured_piece()) update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth)); @@ -1315,8 +1312,7 @@ moves_loop: // When in check, search starts from here assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); - assert(depth <= DEPTH_ZERO); - assert(depth / ONE_PLY * ONE_PLY == depth); + assert(depth <= 0); Move pv[MAX_PLY+1]; StateInfo st; @@ -1455,7 +1451,7 @@ moves_loop: // When in check, search starts from here // Detect non-capture evasions that are candidates to be pruned evasionPrunable = inCheck - && (depth != DEPTH_ZERO || moveCount > 2) + && (depth != 0 || moveCount > 2) && bestValue > VALUE_MATED_IN_MAX_PLY && !pos.capture(move); @@ -1480,7 +1476,7 @@ moves_loop: // When in check, search starts from here // Make and search the move pos.do_move(move, st, givesCheck); - value = -qsearch(pos, ss+1, -beta, -alpha, depth - ONE_PLY); + value = -qsearch(pos, ss+1, -beta, -alpha, depth - 1); pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); @@ -1707,10 +1703,10 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { { bool updated = (i <= pvIdx && rootMoves[i].score != -VALUE_INFINITE); - if (depth == ONE_PLY && !updated) + if (depth == 1 && !updated) continue; - Depth d = updated ? depth : depth - ONE_PLY; + Depth d = updated ? depth : depth - 1; Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; @@ -1720,7 +1716,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { ss << "\n"; ss << "info" - << " depth " << d / ONE_PLY + << " depth " << d << " seldepth " << rootMoves[i].selDepth << " multipv " << i + 1 << " score " << UCI::value(v); @@ -1779,7 +1775,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { RootInTB = false; UseRule50 = bool(Options["Syzygy50MoveRule"]); - ProbeDepth = int(Options["SyzygyProbeDepth"]) * ONE_PLY; + ProbeDepth = int(Options["SyzygyProbeDepth"]); Cardinality = int(Options["SyzygyProbeLimit"]); bool dtz_available = true; @@ -1788,7 +1784,7 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { if (Cardinality > MaxCardinality) { Cardinality = MaxCardinality; - ProbeDepth = DEPTH_ZERO; + ProbeDepth = 0; } if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) diff --git a/src/thread.cpp b/src/thread.cpp index 90ec274d..19687aad 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -204,7 +204,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, for (Thread* th : *this) { th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0; - th->rootDepth = th->completedDepth = DEPTH_ZERO; + th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); } diff --git a/src/tt.cpp b/src/tt.cpp index 6121b3ad..d3cd094e 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -35,24 +35,22 @@ TranspositionTable TT; // Our global transposition table void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { - assert(d / ONE_PLY * ONE_PLY == d); - // Preserve any existing move for the same position if (m || (k >> 48) != key16) move16 = (uint16_t)m; // Overwrite less valuable entries if ( (k >> 48) != key16 - ||(d - DEPTH_OFFSET) / ONE_PLY > depth8 - 4 + || d - DEPTH_OFFSET > depth8 - 4 || b == BOUND_EXACT) { - assert((d - DEPTH_OFFSET) / ONE_PLY >= 0); + assert(d >= DEPTH_OFFSET); key16 = (uint16_t)(k >> 48); value16 = (int16_t)v; eval16 = (int16_t)ev; genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b); - depth8 = (uint8_t)((d - DEPTH_OFFSET) / ONE_PLY); + depth8 = (uint8_t)(d - DEPTH_OFFSET); } } diff --git a/src/tt.h b/src/tt.h index 3a5ba5da..d087cc38 100644 --- a/src/tt.h +++ b/src/tt.h @@ -40,7 +40,7 @@ struct TTEntry { Move move() const { return (Move )move16; } Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } - Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_OFFSET; } + Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; } bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --git a/src/types.h b/src/types.h index 6d2c09a6..cc4008b3 100644 --- a/src/types.h +++ b/src/types.h @@ -203,22 +203,18 @@ enum Piece { extern Value PieceValue[PHASE_NB][PIECE_NB]; -enum Depth : int { +typedef int Depth; - ONE_PLY = 1, +enum : int { - DEPTH_ZERO = 0 * ONE_PLY, - DEPTH_QS_CHECKS = 0 * ONE_PLY, - DEPTH_QS_NO_CHECKS = -1 * ONE_PLY, - DEPTH_QS_RECAPTURES = -5 * ONE_PLY, + DEPTH_QS_CHECKS = 0, + DEPTH_QS_NO_CHECKS = -1, + DEPTH_QS_RECAPTURES = -5, - DEPTH_NONE = -6 * ONE_PLY, + DEPTH_NONE = -6, DEPTH_OFFSET = DEPTH_NONE, - DEPTH_MAX = MAX_PLY * ONE_PLY }; -static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); - enum Square : int { SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, @@ -298,7 +294,6 @@ inline T& operator*=(T& d, int i) { return d = T(int(d) * i); } \ inline T& operator/=(T& d, int i) { return d = T(int(d) / i); } ENABLE_FULL_OPERATORS_ON(Value) -ENABLE_FULL_OPERATORS_ON(Depth) ENABLE_FULL_OPERATORS_ON(Direction) ENABLE_INCR_OPERATORS_ON(PieceType) From 2e96c513ad6113abb6bc4fdd4962cc1f6eed3d4a Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Sat, 5 Oct 2019 10:42:36 -0400 Subject: [PATCH 096/281] Introduce separate counter-move tables for captures Enhance counter-move history table by adding a capture/no-capture dimension, depending wether the previous move was a quiet move or a capture. This doubles the size of the table but provides more accurate move ordering. STC: LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 79702 W: 17720 L: 17164 D: 44818 http://tests.stockfishchess.org/tests/view/5d97945e0ebc590c21aa724b LTC: LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 29147 W: 4907 L: 4651 D: 19589 http://tests.stockfishchess.org/tests/view/5d97ccb90ebc590c21aa7bc0 Closes https://github.com/official-stockfish/Stockfish/pull/2344 Bench: 4131643 --- src/movepick.cpp | 12 ++++++------ src/movepick.h | 2 +- src/search.cpp | 22 +++++++++++++--------- src/thread.cpp | 10 ++++++---- src/thread.h | 2 +- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index fab8cea8..e39f2afa 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -111,11 +111,11 @@ void MovePicker::score() { + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; else if (Type == QUIETS) - m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] - + (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] / 2; + m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] + + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; else // Type == EVASIONS { @@ -206,7 +206,7 @@ top: endMoves = generate(pos, cur); score(); - partial_insertion_sort(cur, endMoves, -4000 * depth); + partial_insertion_sort(cur, endMoves, -3000 * depth); } ++stage; diff --git a/src/movepick.h b/src/movepick.h index e916514d..105c95d7 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -80,7 +80,7 @@ struct Stats : public std::array, Size> {}; /// In stats table, D=0 means that the template parameter is not used enum StatsParams { NOT_USED = 0 }; - +enum StatsType { NoCaptures, Captures }; /// ButterflyHistory records how often quiet moves have been successful or /// unsuccessful during the current search, and is used for reduction and move diff --git a/src/search.cpp b/src/search.cpp index c05e72e0..156f6d1c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -334,7 +334,8 @@ void Thread::search() { std::memset(ss-7, 0, 10 * sizeof(Stack)); for (int i = 7; i > 0; i--) - (ss-i)->continuationHistory = &this->continuationHistory[NO_PIECE][0]; // Use as sentinel + (ss-i)->continuationHistory = &this->continuationHistory[0][NO_PIECE][0]; // Use as a sentinel + ss->pv = pv; bestValue = delta = alpha = -VALUE_INFINITE; @@ -595,12 +596,13 @@ namespace { Value bestValue, value, ttValue, eval, maxValue; bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; - Piece movedPiece; + Piece movedPiece, priorCapture; int moveCount, captureCount, quietCount, singularLMR; // 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; bestValue = -VALUE_INFINITE; @@ -680,7 +682,7 @@ namespace { update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); // Extra penalty for early quiet moves of the previous ply - if ((ss-1)->moveCount <= 2 && !pos.captured_piece()) + if ((ss-1)->moveCount <= 2 && !priorCapture) update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); } // Penalty for a quiet ttMove that fails low @@ -814,7 +816,7 @@ namespace { Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); ss->currentMove = MOVE_NULL; - ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; + ss->continuationHistory = &thisThread->continuationHistory[0][NO_PIECE][0]; pos.do_null_move(st); @@ -865,7 +867,7 @@ namespace { probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][pos.moved_piece(move)][to_sq(move)]; assert(depth >= 5); @@ -1066,7 +1068,7 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[movedPiece][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][movedPiece][to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@ -1279,13 +1281,13 @@ moves_loop: // When in check, search starts from here // 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()) + && !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) - && !pos.captured_piece()) + && !priorCapture) update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth)); if (PvNode) @@ -1321,6 +1323,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; + Piece priorCapture; bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable; int moveCount; @@ -1335,6 +1338,7 @@ moves_loop: // When in check, search starts from here (ss+1)->ply = ss->ply + 1; bestMove = MOVE_NONE; inCheck = pos.checkers(); + priorCapture = pos.captured_piece(); moveCount = 0; // Check for an immediate draw or maximum ply reached @@ -1472,7 +1476,7 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][pos.moved_piece(move)][to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); diff --git a/src/thread.cpp b/src/thread.cpp index 19687aad..3c9473c2 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -70,11 +70,13 @@ void Thread::clear() { mainHistory.fill(0); captureHistory.fill(0); - for (auto& to : continuationHistory) - for (auto& h : to) - h->fill(0); + for (StatsType c : { NoCaptures, Captures }) + for (auto& to : continuationHistory[c]) + for (auto& h : to) + h->fill(0); - continuationHistory[NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + for (StatsType c : { NoCaptures, Captures }) + continuationHistory[c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); } /// Thread::start_searching() wakes up the thread that will start the search diff --git a/src/thread.h b/src/thread.h index 79c6e43f..0a77d5b8 100644 --- a/src/thread.h +++ b/src/thread.h @@ -71,7 +71,7 @@ public: CounterMoveHistory counterMoves; ButterflyHistory mainHistory; CapturePieceToHistory captureHistory; - ContinuationHistory continuationHistory; + ContinuationHistory continuationHistory[2]; Score contempt; }; From c78f8ddd868966b43b20ae4ef585b6cf1f7ab595 Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Sun, 6 Oct 2019 09:57:20 +0200 Subject: [PATCH 097/281] Make priorCapture a bool It is always used as a bool, so let's make it a bool straight away. We can always redefine it as a Piece in a later patch if we want to use the piece type or the piece color. No functional change. --- src/search.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 156f6d1c..6cf99938 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -594,9 +594,9 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR; + bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; - Piece movedPiece, priorCapture; + Piece movedPiece; int moveCount, captureCount, quietCount, singularLMR; // Step 1. Initialize node @@ -867,7 +867,7 @@ namespace { probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[priorCapture][pos.moved_piece(move)][to_sq(move)]; assert(depth >= 5); @@ -1068,7 +1068,7 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][movedPiece][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[priorCapture][movedPiece][to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@ -1323,8 +1323,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - Piece priorCapture; - bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable; + bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable, priorCapture; int moveCount; if (PvNode) @@ -1476,7 +1475,7 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[!!priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[priorCapture][pos.moved_piece(move)][to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); From 7264540107b7f20d16628ac8615070fe3334f5f5 Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Mon, 7 Oct 2019 00:48:19 +0200 Subject: [PATCH 098/281] Adjust pawn span Run as a simplification a) insures that pawn attacks are always included in the pawn span (this "fixes" the case where some outpost or reachable outpost bonus were awarded on squares controlled by enemy pawns). b) compute the full span only if not "backward" or not "blocked". By looking at "blocked" instead of "opposed", we get a nice simpli- fication and the "new" outpost detection is almost identical, except a few borderline cases on rank 4. passed STC http://tests.stockfishchess.org/tests/view/5d9950730ebc5902b6cefb90 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 79113 W: 17168 L: 17159 D: 44786 passed LTC http://tests.stockfishchess.org/tests/view/5d99d14e0ebc5902b6cf0692 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 41286 W: 6819 L: 6731 D: 27736 See https://github.com/official-stockfish/Stockfish/pull/2348 bench: 3812891 --- src/pawns.cpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 1e5b4f43..1825b6e2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -72,7 +72,7 @@ namespace { constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); Bitboard neighbours, stoppers, support, phalanx, opposed; - Bitboard lever, leverPush; + Bitboard lever, leverPush, blocked; Square s; bool backward, passed, doubled; Score score = SCORE_ZERO; @@ -83,9 +83,9 @@ namespace { Bitboard doubleAttackThem = pawn_double_attacks_bb(theirPawns); - e->passedPawns[Us] = e->pawnAttacksSpan[Us] = 0; + e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; - e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); + e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -96,6 +96,7 @@ namespace { // Flag the pawn opposed = theirPawns & forward_file_bb(Us, s); + blocked = theirPawns & (s + Up); stoppers = theirPawns & passed_pawn_span(Us, s); lever = theirPawns & PawnAttacks[Us][s]; leverPush = theirPawns & PawnAttacks[Us][s + Up]; @@ -105,21 +106,13 @@ namespace { support = neighbours & rank_bb(s - Up); // A pawn is backward when it is behind all pawns of the same color on - // the adjacent files and cannot safely advance. Phalanx and isolated - // pawns will be excluded when the pawn is scored. - backward = !(neighbours & forward_ranks_bb(Them, s)) - && (stoppers & (leverPush | (s + Up))); + // the adjacent files and cannot safely advance. + backward = !(neighbours & forward_ranks_bb(Them, s + Up)) + && (stoppers & (leverPush | blocked)); - // Span of backward pawns and span behind opposing pawns are not included - // in the pawnAttacksSpan bitboard. - if (!backward || phalanx) - { - if (opposed) - e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s) & - ~pawn_attack_span(Us, frontmost_sq(Them, opposed)); - else - e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); - } + // Compute additional span if pawn is not backward nor blocked + if (!backward && !blocked) + e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); // A pawn is passed if one of the three following conditions is true: // (a) there is no stoppers except some levers @@ -128,7 +121,7 @@ namespace { passed = !(stoppers ^ lever) || ( !(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush)) - || ( stoppers == square_bb(s + Up) && r >= RANK_5 + || ( stoppers == blocked && r >= RANK_5 && (shift(support) & ~(theirPawns | doubleAttackThem))); // Passed pawns will be properly scored later in evaluation when we have From 0b0b21c608a9c096af6155e39270a29ebfba240f Mon Sep 17 00:00:00 2001 From: SFisGOD Date: Mon, 7 Oct 2019 12:30:57 +0800 Subject: [PATCH 099/281] Tweak kingFlankAttacks factor in kingDanger Increase kingFlankAttacks factor in kingDanger from 5/16 to 6/16. Failed STC: LLR: -2.96 (-2.94,2.94) [0.00,4.00] Total: 77947 W: 16989 L: 16848 D: 44110 http://tests.stockfishchess.org/tests/view/5d9ac0280ebc5902b6cf63cd Passed LTC 1: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 13443 W: 2231 L: 2037 D: 9175 http://tests.stockfishchess.org/tests/view/5d9ac88d0ebc5902b6cf6ffb Passed LTC 2: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 23340 W: 3842 L: 3617 D: 15881 http://tests.stockfishchess.org/tests/view/5d9acf7f0ebc5902b6cf7c27 Closes https://github.com/official-stockfish/Stockfish/pull/2349 Bench: 4042155 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ee98da90..0963ddd6 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -457,7 +457,7 @@ namespace { - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) - + 5 * kingFlankAttacks * kingFlankAttacks / 16 + + 3 * kingFlankAttacks * kingFlankAttacks / 8 - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation From 0150da5c2bd4661996b05dec4a1eca473515e9d7 Mon Sep 17 00:00:00 2001 From: Alayan Date: Mon, 7 Oct 2019 19:02:33 +0200 Subject: [PATCH 100/281] Adjust aspiration window with eval This patch changes the base aspiration window size depending on the absolute value of the previous iteration score, increasing it away from zero. This stems from the observation that the further away from zero, the more likely the evaluation is to change significantly with more depth. Conversely, a tighter aspiration window is more efficient when close to zero. A beneficial side-effect is that analysis of won positions without a quick mate is less prone to waste nodes in repeated fail-high that change the eval by tiny steps. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 60102 W: 13327 L: 12868 D: 33907 http://tests.stockfishchess.org/tests/view/5d9a70d40ebc5902b6cf39ba LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 155553 W: 25745 L: 25141 D: 104667 http://tests.stockfishchess.org/tests/view/5d9a7ca30ebc5902b6cf4028 Future work : the values used in this patch were only a reasonable guess. Further testing should unveil more optimal values. However, the aspiration window is rather tight with a minimum of 21 internal units, so discrete integers put a practical limitation to such tweaking. More exotic experiments around the aspiration window parameters could also be tried, but efficient conditions to adjust the base aspiration window size or allow it to not be centered on the current evaluation are not obvious. The aspiration window increases after a fail-high or a fail-low is another avenue to explore for potential enhancements. Bench: 4043748 --- AUTHORS | 2 +- src/search.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index aff6a6c9..8317f545 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,7 +9,7 @@ Aditya (absimaldata) Adrian Petrescu (apetresc) Ajith Chandy Jose (ajithcj) Alain Savard (Rocky640) -alayan-stk-2 +Alayan Feh (Alayan-stk-2) Alexander Kure Alexander Pagel (Lolligerhans) Ali AlZhrani (Cooffe) diff --git a/src/search.cpp b/src/search.cpp index 6cf99938..1742c676 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -412,7 +412,7 @@ void Thread::search() { if (rootDepth >= 4) { Value previousScore = rootMoves[pvIdx].previousScore; - delta = Value(23); + delta = Value(21 + abs(previousScore) / 128); alpha = std::max(previousScore - delta,-VALUE_INFINITE); beta = std::min(previousScore + delta, VALUE_INFINITE); From 23a022980baadd5315d59a1480d26925a427aeb9 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Mon, 7 Oct 2019 14:47:43 -0400 Subject: [PATCH 101/281] No reachable outpost bonus for bishops Previously, we used various control statements and ternary operators to divide Outpost into four bonuses, based on whether the outpost was for a knight or bishop, and whether it was currently an Outpost or merely a potential ("reachable") one in the future. Bishop outposts, however, have traditionally been worth far less Elo in testing. An attempt to remove them altogether passed STC, but failed LTC. Here we include a narrower simplification, removing the reachable Outpost bonus for bishops. This bonus was always suspect, given that its current implementation conflicts directly with BishopPawns. BishopPawns penalizes our bishops based on the number of friendly pawns on the same color of square, but by definition, Outposts must be pawn-protected! This PR helps to alleviate this conceptual contradiction without loss of Elo and with slightly simpler code. On a code level, this allows us to simplify a ternary operator into the previous "if" block and distribute a multiplication into an existing constant Score. On a conceptual level, we retire one of the four traditional Outpost bonuses. STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 22277 W: 4882 L: 4762 D: 12633 http://tests.stockfishchess.org/tests/view/5d9aeed60ebc5902b6cf9751 LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 51206 W: 8353 L: 8280 D: 34573 http://tests.stockfishchess.org/tests/view/5d9af1940ebc5902b6cf9cd5 Closes https://github.com/official-stockfish/Stockfish/pull/2352 Bench: 3941591 --- src/evaluate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0963ddd6..a0ad09f0 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -135,7 +135,7 @@ namespace { constexpr Score KnightOnQueen = S( 16, 12); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 16, 5); + constexpr Score Outpost = S( 32, 10); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); @@ -298,11 +298,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 (bb & s) - score += Outpost * (Pt == KNIGHT ? 4 : 2); - - else if (bb & b & ~pos.pieces(Us)) score += Outpost * (Pt == KNIGHT ? 2 : 1); + else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) + score += Outpost; + // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; From 80d59eea392fc073f6d0ba29cb9a97e3d705ee58 Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Tue, 8 Oct 2019 10:44:01 -0400 Subject: [PATCH 102/281] Introduce separate counter-move tables for inCheck Enhance counter-move history table by adding a inCheck dimension. This doubles the size of the table but provides more accurate move ordering. STC: (yellow) LLR: -2.94 (-2.94,2.94) [0.50,4.50] Total: 36217 W: 7790 L: 7777 D: 20650 http://tests.stockfishchess.org/tests/view/5d9b9a290ebc5902b6d04fe0 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 36665 W: 6063 L: 5788 D: 24814 http://tests.stockfishchess.org/tests/view/5d9b9fcc0ebc5902b6d05985 Closes https://github.com/official-stockfish/Stockfish/pull/2353 Bench: 4053577 --- src/search.cpp | 10 +++++----- src/thread.cpp | 14 ++++++++------ src/thread.h | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 1742c676..7e2df215 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -334,7 +334,7 @@ void Thread::search() { std::memset(ss-7, 0, 10 * sizeof(Stack)); for (int i = 7; i > 0; i--) - (ss-i)->continuationHistory = &this->continuationHistory[0][NO_PIECE][0]; // Use as a sentinel + (ss-i)->continuationHistory = &this->continuationHistory[0][0][NO_PIECE][0]; // Use as a sentinel ss->pv = pv; @@ -816,7 +816,7 @@ namespace { Depth R = (835 + 70 * depth) / 256 + std::min(int(eval - beta) / 185, 3); ss->currentMove = MOVE_NULL; - ss->continuationHistory = &thisThread->continuationHistory[0][NO_PIECE][0]; + ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; pos.do_null_move(st); @@ -867,7 +867,7 @@ namespace { probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; assert(depth >= 5); @@ -1068,7 +1068,7 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[priorCapture][movedPiece][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][movedPiece][to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@ -1475,7 +1475,7 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); diff --git a/src/thread.cpp b/src/thread.cpp index 3c9473c2..476f1d64 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -70,13 +70,15 @@ void Thread::clear() { mainHistory.fill(0); captureHistory.fill(0); - for (StatsType c : { NoCaptures, Captures }) - for (auto& to : continuationHistory[c]) - for (auto& h : to) - h->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 }) - continuationHistory[c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + for (bool inCheck : { false, true }) + for (StatsType c : { NoCaptures, Captures }) + continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); } /// Thread::start_searching() wakes up the thread that will start the search diff --git a/src/thread.h b/src/thread.h index 0a77d5b8..0517afc5 100644 --- a/src/thread.h +++ b/src/thread.h @@ -71,7 +71,7 @@ public: CounterMoveHistory counterMoves; ButterflyHistory mainHistory; CapturePieceToHistory captureHistory; - ContinuationHistory continuationHistory[2]; + ContinuationHistory continuationHistory[2][2]; Score contempt; }; From b8e5092d07aaf736894d7d80b19d0185a1789084 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 1 Oct 2019 22:11:12 +0200 Subject: [PATCH 103/281] Add four positions to bench The current bench is missing a position with high 50 moves rule counter, making most 'shuffle' tests based on 50mr > N seem non-functional. This patch adds one FEN with high 50mr counter to address this issue (taken from a recent tcec game). Four new FENs: - position with high 50mr counter - tactical position with many captures, checks, extensions, fails high/low - two losses by Stockfish in the S16 bonus games against Houdini See the pull request for nice comments by @Alayan-stk-2 about each position in bench: https://github.com/official-stockfish/Stockfish/pull/2338 Bench: 4590210 --- src/benchmark.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index b23c5d17..8f30bee4 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -61,6 +61,10 @@ const vector Defaults = { "1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1", "6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1", "8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1", + "5rk1/q6p/2p3bR/1pPp1rP1/1P1Pp3/P3B1Q1/1K3P2/R7 w - - 93 90", + "4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21", + "r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16", + "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40", // 5-man positions "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate From 472de897cb7efb66cb3518f3f4924716bd8abaee Mon Sep 17 00:00:00 2001 From: VoyagerOne Date: Fri, 18 Oct 2019 09:23:00 -0400 Subject: [PATCH 104/281] Current capture for Counter-Move history Use current capture to index the CMH table instead of prior capture. STC: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 61908 W: 13626 L: 13220 D: 35062 http://tests.stockfishchess.org/tests/view/5da8aa670ebc597ba8eda558 LTC: LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 49057 W: 8071 L: 7765 D: 33221 http://tests.stockfishchess.org/tests/view/5da8e99d0ebc597ba8eda9ca Closes https://github.com/official-stockfish/Stockfish/pull/2362 Bench: 4423737 --- src/search.cpp | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 7e2df215..6e59bb54 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -864,12 +864,17 @@ namespace { && probCutCount < 2 + 2 * cutNode) if (move != excludedMove && pos.legal(move)) { + assert(pos.capture_or_promotion(move)); + assert(depth >= 5); + + captureOrPromotion = true; probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; - - assert(depth >= 5); + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [pos.moved_piece(move)] + [to_sq(move)]; pos.do_move(move, st); @@ -900,8 +905,8 @@ namespace { moves_loop: // When in check, search starts from here const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, - nullptr, (ss-4)->continuationHistory, - nullptr, (ss-6)->continuationHistory }; + nullptr , (ss-4)->continuationHistory, + nullptr , (ss-6)->continuationHistory }; Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; @@ -911,7 +916,7 @@ moves_loop: // When in check, search starts from here countermove, ss->killers); - value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc + value = bestValue; moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); @@ -1068,7 +1073,10 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][movedPiece][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [movedPiece] + [to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@ -1323,7 +1331,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable, priorCapture; + bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion, evasionPrunable; int moveCount; if (PvNode) @@ -1337,7 +1345,6 @@ moves_loop: // When in check, search starts from here (ss+1)->ply = ss->ply + 1; bestMove = MOVE_NONE; inCheck = pos.checkers(); - priorCapture = pos.captured_piece(); moveCount = 0; // Check for an immediate draw or maximum ply reached @@ -1408,8 +1415,8 @@ moves_loop: // When in check, search starts from here } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, - nullptr, (ss-4)->continuationHistory, - nullptr, (ss-6)->continuationHistory }; + nullptr , (ss-4)->continuationHistory, + nullptr , (ss-6)->continuationHistory }; // Initialize a MovePicker object for the current position, and prepare // to search the moves. Because the depth is <= 0 here, only captures, @@ -1426,6 +1433,7 @@ moves_loop: // When in check, search starts from here assert(is_ok(move)); givesCheck = pos.gives_check(move); + captureOrPromotion = pos.capture_or_promotion(move); moveCount++; @@ -1475,7 +1483,10 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [pos.moved_piece(move)] + [to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); From 12d58adc68b1aa084d383d06bc47abbb3495ce3e Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 19 Sep 2019 17:10:46 +0100 Subject: [PATCH 105/281] Remove uithread With the current questions and issues around threading, I had a look at https://github.com/official-stockfish/Stockfish/issues/2299. It seems there was a problem with data races when requesting eval via UCI while a search was already running. To fix this an extra thread uithread was created, presumably to avoid an overlap with Threads.main() that was causing problems. Making this eval request seems to be outside the scope of UCI, and @vondele also reports that the data race is not even fixed reliably by this change. I suggest we simplify the threading here by removing this uithread and adding a comment signaling that user should not request eval when a search is already running. Closes https://github.com/official-stockfish/Stockfish/pull/2310 No functional change. --- src/uci.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uci.cpp b/src/uci.cpp index a4235f2b..99bf1a13 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -191,9 +191,8 @@ void UCI::loop(int argc, char* argv[]) { Position pos; string token, cmd; StateListPtr states(new std::deque(1)); - auto uiThread = std::make_shared(0); - pos.set(StartFEN, false, &states->back(), uiThread.get()); + pos.set(StartFEN, false, &states->back(), Threads.main()); for (int i = 1; i < argc; ++i) cmd += std::string(argv[i]) + " "; @@ -229,7 +228,8 @@ void UCI::loop(int argc, char* argv[]) { else if (token == "ucinewgame") Search::clear(); else if (token == "isready") sync_cout << "readyok" << sync_endl; - // Additional custom non-UCI commands, mainly for debugging + // 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; From 215cd19108d97376284192c29790b42a0b0e618a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 21 Oct 2019 08:05:14 +0200 Subject: [PATCH 106/281] 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 107/281] 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 108/281] 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 109/281] 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 110/281] 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 111/281] 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 112/281] 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 113/281] 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 114/281] 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 115/281] 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 116/281] 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 117/281] 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 118/281] 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 119/281] 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 120/281] 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 121/281] 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 122/281] 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 123/281] 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 124/281] 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 125/281] 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 126/281] 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 127/281] 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 128/281] 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 129/281] 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 130/281] 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 131/281] 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 132/281] 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 133/281] 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 134/281] 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 135/281] 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 136/281] 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 137/281] 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 138/281] 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 139/281] 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 140/281] 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 141/281] 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 142/281] 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 143/281] 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 144/281] 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 145/281] 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 146/281] 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 147/281] 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 148/281] 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 149/281] 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 150/281] 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 151/281] 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 152/281] 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 153/281] 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 154/281] 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 155/281] 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 156/281] 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 157/281] 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 158/281] 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 159/281] 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 160/281] 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 161/281] 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 162/281] 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 163/281] 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 164/281] 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 From bcf9282844f17dbb451231d8ae0a957d1b7be43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Thu, 23 Jan 2020 17:17:26 +0100 Subject: [PATCH 165/281] Restore development version No functional change --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 95862ebb..053ee67e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -56,7 +56,7 @@ namespace { /// Version number. If Version is left empty, then compile date in the format /// DD-MM-YY and show in engine_info. -const string Version = "11"; +const string Version = ""; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We From 7a7bcd6359b38651e1bfecf78aa07e633abed5b2 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sat, 21 Dec 2019 15:36:29 -0700 Subject: [PATCH 166/281] Simplify signature of remove_piece() This is a non-functional simplification. Instead of passing the piece type for remove_piece, we can rely on the board. The only exception is en-passant which must be explicitly set because the destination square for the capture is not the same as the piece to remove. Verified also in the Chess960 castling case by running a couple of perft, see the pull request discussion: https://github.com/official-stockfish/Stockfish/pull/2460 STC LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 18624 W: 4147 L: 4070 D: 10407 Ptnml(0-2): 223, 1933, 4945, 1938, 260 http://tests.stockfishchess.org/tests/view/5dfeaa93e70446e17e451163 No functional change --- src/position.cpp | 21 +++++++++++---------- src/position.h | 10 ++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 53d9b64e..de9722ff 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -743,8 +743,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { assert(relative_rank(us, to) == RANK_6); assert(piece_on(to) == NO_PIECE); assert(piece_on(capsq) == make_piece(them, PAWN)); - - board[capsq] = NO_PIECE; // Not done by remove_piece() } st->pawnKey ^= Zobrist::psq[captured][capsq]; @@ -753,7 +751,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { st->nonPawnMaterial[them] -= PieceValue[MG][captured]; // Update board and piece lists - remove_piece(captured, capsq); + remove_piece(capsq); + + if (type_of(m) == ENPASSANT) + board[capsq] = NO_PIECE; // Update material hash key and prefetch access to materialTable k ^= Zobrist::psq[captured][capsq]; @@ -784,7 +785,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // Move the piece. The tricky Chess960 castling is handled earlier if (type_of(m) != CASTLING) - move_piece(pc, from, to); + move_piece(from, to); // If the moving piece is a pawn do some special extra work if (type_of(pc) == PAWN) @@ -804,7 +805,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { assert(relative_rank(us, to) == RANK_8); assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN); - remove_piece(pc, to); + remove_piece(to); put_piece(promotion, to); // Update hash keys @@ -884,7 +885,7 @@ void Position::undo_move(Move m) { assert(type_of(pc) == promotion_type(m)); assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN); - remove_piece(pc, to); + remove_piece(to); pc = make_piece(us, PAWN); put_piece(pc, to); } @@ -896,7 +897,7 @@ void Position::undo_move(Move m) { } else { - move_piece(pc, to, from); // Put the piece back at the source square + move_piece(to, from); // Put the piece back at the source square if (st->capturedPiece) { @@ -936,9 +937,9 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); // Remove both pieces first since squares could overlap in Chess960 - remove_piece(make_piece(us, KING), Do ? from : to); - remove_piece(make_piece(us, ROOK), Do ? rfrom : rto); - board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do it for us + remove_piece(Do ? from : to); + remove_piece(Do ? rfrom : rto); + board[Do ? from : to] = board[Do ? rfrom : rto] = NO_PIECE; // Since remove_piece doesn't do this for us put_piece(make_piece(us, KING), Do ? to : from); put_piece(make_piece(us, ROOK), Do ? rto : rfrom); } diff --git a/src/position.h b/src/position.h index 6791455f..e5071d53 100644 --- a/src/position.h +++ b/src/position.h @@ -174,8 +174,8 @@ private: // Other helpers void put_piece(Piece pc, Square s); - void remove_piece(Piece pc, Square s); - void move_piece(Piece pc, Square from, Square to); + void remove_piece(Square s); + void move_piece(Square from, Square to); template void do_castling(Color us, Square from, Square& to, Square& rfrom, Square& rto); @@ -412,12 +412,13 @@ inline void Position::put_piece(Piece pc, Square s) { psq += PSQT::psq[pc][s]; } -inline void Position::remove_piece(Piece pc, Square s) { +inline void Position::remove_piece(Square s) { // WARNING: This is not a reversible operation. If we remove a piece in // do_move() and then replace it in undo_move() we will put it at the end of // the list and not in its original place, it means index[] and pieceList[] // are not invariant to a do_move() + undo_move() sequence. + Piece pc = board[s]; byTypeBB[ALL_PIECES] ^= s; byTypeBB[type_of(pc)] ^= s; byColorBB[color_of(pc)] ^= s; @@ -430,10 +431,11 @@ inline void Position::remove_piece(Piece pc, Square s) { psq -= PSQT::psq[pc][s]; } -inline void Position::move_piece(Piece pc, Square from, Square to) { +inline void Position::move_piece(Square from, Square to) { // index[from] is not updated and becomes stale. This works as long as index[] // is accessed just by known occupied squares. + Piece pc = board[from]; Bitboard fromTo = from | to; byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; From 75dfdeac119d0ce71c36ba5ab4f33318f589b158 Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 10 Jan 2020 15:08:47 -0700 Subject: [PATCH 167/281] Simplify KPK classify This is a non-functional simplification. If we use the "side to move" of the entry instead of the template, one of the classify methods goes away. Furthermore, I've resolved the colors in some of the statements (we're already assuming direction using NORTH), and used stm (side to move) instead of "us," since this is much clearer to me. This is not tested because it is non-functional, only applies building the bitbase and there are no changes to the binary (on my machine). Closes https://github.com/official-stockfish/Stockfish/pull/2485 No functional change --- src/bitbase.cpp | 56 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 78614fa2..7bc4a65c 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -43,8 +43,8 @@ namespace { // bit 12: side to move (WHITE or BLACK) // bit 13-14: white pawn file (from FILE_A to FILE_D) // bit 15-17: white pawn RANK_7 - rank (from RANK_7 - RANK_7 to RANK_7 - RANK_2) - unsigned index(Color us, Square bksq, Square wksq, Square psq) { - return int(wksq) | (bksq << 6) | (us << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); + unsigned index(Color stm, Square bksq, Square wksq, Square psq) { + return int(wksq) | (bksq << 6) | (stm << 12) | (file_of(psq) << 13) | ((RANK_7 - rank_of(psq)) << 15); } enum Result { @@ -60,12 +60,9 @@ namespace { KPKPosition() = default; explicit KPKPosition(unsigned idx); operator Result() const { return result; } - Result classify(const std::vector& db) - { return us == WHITE ? classify(db) : classify(db); } + Result classify(const std::vector& db); - template Result classify(const std::vector& db); - - Color us; + Color stm; Square ksq[COLOR_NB], psq; Result result; }; @@ -73,11 +70,11 @@ namespace { } // namespace -bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color us) { +bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { assert(file_of(wpsq) <= FILE_D); - unsigned idx = index(us, bksq, wksq, wpsq); + unsigned idx = index(stm, bksq, wksq, wpsq); return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); } @@ -110,28 +107,28 @@ namespace { ksq[WHITE] = Square((idx >> 0) & 0x3F); ksq[BLACK] = Square((idx >> 6) & 0x3F); - us = Color ((idx >> 12) & 0x01); + stm = Color ((idx >> 12) & 0x01); psq = make_square(File((idx >> 13) & 0x3), Rank(RANK_7 - ((idx >> 15) & 0x7))); // Check if two pieces are on the same square or if a king can be captured if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 || ksq[WHITE] == psq || ksq[BLACK] == psq - || (us == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) + || (stm == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) result = INVALID; // Immediate win if a pawn can be promoted without getting captured - else if ( us == WHITE + else if ( stm == WHITE && rank_of(psq) == RANK_7 - && ksq[us] != psq + NORTH - && ( distance(ksq[~us], psq + NORTH) > 1 - || (PseudoAttacks[KING][ksq[us]] & (psq + NORTH)))) + && ksq[stm] != psq + NORTH + && ( distance(ksq[~stm], psq + NORTH) > 1 + || (PseudoAttacks[KING][ksq[stm]] & (psq + NORTH)))) result = WIN; // Immediate draw if it is a stalemate or a king captures undefended pawn - else if ( us == BLACK - && ( !(PseudoAttacks[KING][ksq[us]] & ~(PseudoAttacks[KING][ksq[~us]] | PawnAttacks[~us][psq])) - || (PseudoAttacks[KING][ksq[us]] & psq & ~PseudoAttacks[KING][ksq[~us]]))) + else if ( stm == BLACK + && ( !(PseudoAttacks[KING][ksq[stm]] & ~(PseudoAttacks[KING][ksq[~stm]] | PawnAttacks[~stm][psq])) + || (PseudoAttacks[KING][ksq[stm]] & psq & ~PseudoAttacks[KING][ksq[~stm]]))) result = DRAW; // Position will be classified later @@ -139,7 +136,6 @@ namespace { result = UNKNOWN; } - template Result KPKPosition::classify(const std::vector& db) { // White to move: If one move leads to a position classified as WIN, the result @@ -151,27 +147,25 @@ namespace { // of the current position is DRAW. If all moves lead to positions classified // as WIN, the position is classified as WIN, otherwise the current position is // classified as UNKNOWN. - - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Result Good = (Us == WHITE ? WIN : DRAW); - constexpr Result Bad = (Us == WHITE ? DRAW : WIN); + const Result Good = (stm == WHITE ? WIN : DRAW); + const Result Bad = (stm == WHITE ? DRAW : WIN); Result r = INVALID; - Bitboard b = PseudoAttacks[KING][ksq[Us]]; + Bitboard b = PseudoAttacks[KING][ksq[stm]]; while (b) - r |= Us == WHITE ? db[index(Them, ksq[Them] , pop_lsb(&b), psq)] - : db[index(Them, pop_lsb(&b), ksq[Them] , psq)]; + r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)] + : db[index(WHITE, pop_lsb(&b), ksq[WHITE], psq)]; - if (Us == WHITE) + if (stm == WHITE) { if (rank_of(psq) < RANK_7) // Single push - r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH)]; + r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH)]; if ( rank_of(psq) == RANK_2 // Double push - && psq + NORTH != ksq[Us] - && psq + NORTH != ksq[Them]) - r |= db[index(Them, ksq[Them], ksq[Us], psq + NORTH + NORTH)]; + && psq + NORTH != ksq[WHITE] + && psq + NORTH != ksq[BLACK]) + r |= db[index(BLACK, ksq[BLACK], ksq[WHITE], psq + NORTH + NORTH)]; } return result = r & Good ? Good : r & UNKNOWN ? UNKNOWN : Bad; From f3c83ed46cdc2062c30551f457ac53ad635794ea Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 23 Dec 2019 10:58:30 -0700 Subject: [PATCH 168/281] Determine opposite colors mathematically This is a non-functional speed-up: master has to access SquareBB twice while this patch determines opposite_colors just using the values of the squares. It doesn't seem to change the overall speed of bench, but calling opposite_colors(...) 10 Million times: master: 39.4 seconds patch: 11.4 seconds. The only data point I have (other than my own tests), is a quite old failed STC test: LLR: -2.93 (-2.94,2.94) [-1.50,4.50] Total: 24308 W: 5331 L: 5330 D: 13647 Ptnml(0-2): 315, 2577, 6326, 2623, 289 http://tests.stockfishchess.org/tests/view/5e010256c13ac2425c4a9a67 Closes https://github.com/official-stockfish/Stockfish/pull/2498 No functional change --- src/bitboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 440de1ea..d11b7e73 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -129,8 +129,8 @@ constexpr bool more_than_one(Bitboard b) { return b & (b - 1); } -inline bool opposite_colors(Square s1, Square s2) { - return bool(DarkSquares & s1) != bool(DarkSquares & s2); +constexpr bool opposite_colors(Square s1, Square s2) { + return (s1 + rank_of(s1) + s2 + rank_of(s2)) & 1; } From 6f1013794cecc179e7432004b8555e64ddca75a5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 23 Jan 2020 18:18:58 +0100 Subject: [PATCH 169/281] Use a std::bitset for KPKBitbase This is a non-functional simplification. Looks like std::bitset works good for the KPKBitbase. Thanks for Jorg Oster for helping get the speed up (the [] accessor is faster than test()). Speed testing: 10k calls to probe: master 9.8 sec patch 9.8 sec. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 100154 W: 19025 L: 18992 D: 62137 Ptnml(0-2): 1397, 11376, 24572, 11254, 1473 http://tests.stockfishchess.org/tests/view/5e21e601346e35ac603b7d2b Closes https://github.com/official-stockfish/Stockfish/pull/2502 No functional change --- src/bitbase.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 7bc4a65c..ed6ed208 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "bitboard.h" #include "types.h" @@ -31,8 +32,7 @@ namespace { // Positions with the pawn on files E to H will be mirrored before probing. constexpr unsigned MAX_INDEX = 2*24*64*64; // stm * psq * wksq * bksq = 196608 - // Each uint32_t stores results of 32 positions, one per bit - uint32_t KPKBitbase[MAX_INDEX / 32]; + std::bitset KPKBitbase; // A KPK bitbase index is an integer in [0, IndexMax] range // @@ -74,8 +74,7 @@ bool Bitbases::probe(Square wksq, Square wpsq, Square bksq, Color stm) { assert(file_of(wpsq) <= FILE_D); - unsigned idx = index(stm, bksq, wksq, wpsq); - return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); + return KPKBitbase[index(stm, bksq, wksq, wpsq)]; } @@ -94,10 +93,10 @@ void Bitbases::init() { for (repeat = idx = 0; idx < MAX_INDEX; ++idx) repeat |= (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN); - // Map 32 results into one KPKBitbase[] entry + // Fill the bitbase with the decisive results for (idx = 0; idx < MAX_INDEX; ++idx) if (db[idx] == WIN) - KPKBitbase[idx / 32] |= 1 << (idx & 0x1F); + KPKBitbase.set(idx); } From 7ed817d7e4847196a5ba0a3aded0519000074be7 Mon Sep 17 00:00:00 2001 From: Chess13234 <37609326+Chess13234@users.noreply.github.com> Date: Tue, 21 Jan 2020 18:20:00 +0200 Subject: [PATCH 170/281] Minor fixes for misc.cpp Fixes conflict with tune.h STRINGIFY macro. No functional change --- src/misc.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 053ee67e..484d0b21 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -155,9 +155,9 @@ const string engine_info(bool to_uci) { const std::string compiler_info() { - #define STRINGIFY2(x) #x - #define STRINGIFY(x) STRINGIFY2(x) - #define VER_STRING(major, minor, patch) STRINGIFY(major) "." STRINGIFY(minor) "." STRINGIFY(patch) + #define stringify2(x) #x + #define stringify(x) stringify2(x) + #define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch) /// Predefined macros hell: /// @@ -171,20 +171,20 @@ const std::string compiler_info() { #ifdef __clang__ compiler += "clang++ "; - compiler += VER_STRING(__clang_major__, __clang_minor__, __clang_patchlevel__); + compiler += make_version_string(__clang_major__, __clang_minor__, __clang_patchlevel__); #elif __INTEL_COMPILER compiler += "Intel compiler "; compiler += "(version "; - compiler += STRINGIFY(__INTEL_COMPILER) " update " STRINGIFY(__INTEL_COMPILER_UPDATE); + compiler += stringify(__INTEL_COMPILER) " update " stringify(__INTEL_COMPILER_UPDATE); compiler += ")"; #elif _MSC_VER compiler += "MSVC "; compiler += "(version "; - compiler += STRINGIFY(_MSC_FULL_VER) "." STRINGIFY(_MSC_BUILD); + compiler += stringify(_MSC_FULL_VER) "." stringify(_MSC_BUILD); compiler += ")"; #elif __GNUC__ compiler += "g++ (GNUC) "; - compiler += VER_STRING(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); + compiler += make_version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); #else compiler += "Unknown compiler "; compiler += "(unknown version)"; From f63d112c710fcd38c9d4946f38603b9c2b4689a4 Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Thu, 16 Jan 2020 08:39:20 +0100 Subject: [PATCH 171/281] Use (strict) greater-than-operator for 'improving' Currently on a normal bench run in ~0,7% of cases 'improving' is set to true although the static eval isn't improving at all, just keeping equal. It looks like the strict gt-operator is more appropriate here, since it returns to 'improving' its literal meaning without sideffects. STC {-1.00,3.00} failed yellow: https://tests.stockfishchess.org/tests/view/5e1ec38c8fd5f550e4ae1c28 LLR: -2.93 (-2.94,2.94) {-1.00,3.00} Total: 53155 W: 10170 L: 10109 D: 32876 Ptnml(0-2): 863, 6282, 12251, 6283, 892 non-regression LTC passed: https://tests.stockfishchess.org/tests/view/5e1f1c0d8fd5f550e4ae1c41 LLR: 2.98 (-2.94,2.94) {-1.50,0.50} Total: 23961 W: 3114 L: 3018 D: 17829 Ptnml(0-2): 163, 2220, 7114, 2298, 170 CLoses https://github.com/official-stockfish/Stockfish/pull/2496 bench: 4561386 --- src/search.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 0eea4127..21df156c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -625,7 +625,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving , didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -825,8 +825,9 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); - improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval >= (ss-4)->staticEval - || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval >= (ss-2)->staticEval; + // (~13 Elo) + improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval > (ss-4)->staticEval + || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval > (ss-2)->staticEval; // Step 8. Futility pruning: child node (~50 Elo) if ( !PvNode From 56e698ef8382cc837507c8910bf2409ebb4aec77 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 21 Jan 2020 09:28:58 +0100 Subject: [PATCH 172/281] Less reduction for escape moves at ttPv nodes At expected PV nodes or nodes which marked as PV node in the hash table, reduce escape moves even one ply less. STC: LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 31795 W: 6140 L: 5953 D: 19702 Ptnml(0-2): 525, 3625, 7455, 3695, 583 http://tests.stockfishchess.org/tests/view/5e25d77fc3b97aa0d75bc013 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 43975 W: 5708 L: 5454 D: 32813 Ptnml(0-2): 314, 4012, 13070, 4242, 325 http://tests.stockfishchess.org/tests/view/5e2618c1c3b97aa0d75bc03c Closes https://github.com/official-stockfish/Stockfish/pull/2505 Bench: 4475583 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 21df156c..3bd1a92d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -625,7 +625,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving , didLMR, priorCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -825,7 +825,6 @@ namespace { && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); - // (~13 Elo) improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval > (ss-2)->staticEval; @@ -1161,7 +1160,7 @@ moves_loop: // When in check, search starts from here // hence break make_move(). (~2 Elo) else if ( type_of(move) == NORMAL && !pos.see_ge(reverse_move(move))) - r -= 2; + r -= 2 + ttPv; ss->statScore = thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] From 18fc21eba0368fd5e3c4c4b8ee1000c9ac445425 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 22 Jan 2020 03:54:44 +0300 Subject: [PATCH 173/281] Tweak trapped rook penalty This patch greatly increases the endgame penalty for having a trapped rook. Idea was a result of witnessing Stockfish losing some games at CCCC exchanging pieces in the position with a trapped rook which directly lead to a lost endgame. This patch should partially fix such behavior making this penalty high even in deep endgames. Passed STC http://tests.stockfishchess.org/tests/view/5e279d7cc3b97aa0d75bc1c4 LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 8528 W: 1706 L: 1588 D: 5234 Ptnml(0-2): 133, 957, 1985, 1024, 159 Passed LTC http://tests.stockfishchess.org/tests/view/5e27aee4c3b97aa0d75bc1e1 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 88713 W: 11520 L: 11130 D: 66063 Ptnml(0-2): 646, 8170, 26342, 8492, 676 Closes https://github.com/official-stockfish/Stockfish/pull/2510 Bench: 4964462 ---------------------- Comment by Malcolm Campbell: Congrats! I think this might be a common pattern - scores that seem to mainly apply to the midgame are often better with a similar (or at least fairly big) endgame value as well. Maybe there are others eval parameters we can tweak like this... --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7c7ce95c..fad0771d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -145,7 +145,7 @@ namespace { constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); + constexpr Score TrappedRook = S( 52, 30); constexpr Score WeakQueen = S( 49, 15); #undef S From 01b6088af39902001d2d6844561b6a2faa549282 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 23 Jan 2020 15:41:03 +0100 Subject: [PATCH 174/281] History update for pruned captures Use a SEE pruned capture move for history updates: this patch collects pruned capture moves also in the failed captures list, so that they get an update in capture history. STC: LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 11124 W: 2222 L: 2089 D: 6813 Ptnml(0-2): 186, 1280, 2506, 1381, 200 http://tests.stockfishchess.org/tests/view/5e28995fc3b97aa0d75bc294 LTC: LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 25552 W: 3418 L: 3211 D: 18923 Ptnml(0-2): 168, 2354, 7538, 2490, 200 http://tests.stockfishchess.org/tests/view/5e2943734744cfa4d6af415b Closes https://github.com/official-stockfish/Stockfish/pull/2511 Bench: 4810202 --- src/search.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3bd1a92d..1490a266 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1028,7 +1028,11 @@ moves_loop: // When in check, search starts from here continue; } else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - continue; + { + if (captureOrPromotion && captureCount < 32) + capturesSearched[captureCount++] = move; + continue; + } } // Step 14. Extensions (~75 Elo) From 0ae00454ba6928d181b46103e5c83e6d58fcebe5 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Fri, 24 Jan 2020 23:04:35 +0100 Subject: [PATCH 175/281] Tweak RestrictedPiece bonus Double the "RestrictedPiece" bonus for restricted moves targeting occupied squares. STC LLR: 3.58 (-2.94,2.94) {-1.00,3.00} Total: 25504 W: 4887 L: 4697 D: 15920 Ptnml(0-2): 387, 2935, 5947, 3051, 422 https://tests.stockfishchess.org/tests/view/5e2aa15dab2d69d58394f94d LTC LLR: 2.94 (-2.94,2.94) {0.00,2.00} Total: 28572 W: 3826 L: 3621 D: 21125 Ptnml(0-2): 224, 2609, 8403, 2791, 239 https://tests.stockfishchess.org/tests/view/5e2ae7f4ab2d69d58394f9a6 Bench: 4719086 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fad0771d..a1a3b4ed 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -520,11 +520,11 @@ namespace { } // Bonus for restricting their piece moves + // Greater bonus when landing square is occupied b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - - score += RestrictedPiece * popcount(b); + score += RestrictedPiece * (popcount(b) + popcount(b & pos.pieces())); // Protected or unattacked squares safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; From 6d0eabd5fe2961551477820ab7619e2c31e01ffd Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Sat, 25 Jan 2020 07:59:42 -0500 Subject: [PATCH 176/281] Dynamic complexity Instead of computing the initiative bonus on the material score + dynamic score compute it on (material score/2) + dynamic score, Passed STC http://tests.stockfishchess.org/tests/view/5e2c4945ab2d69d58394fa8f LLR: 2.94 (-2.94,2.94) {-1.00,3.00} Total: 39387 W: 7594 L: 7386 D: 24407 Ptnml(0-2): 658, 4519, 9165, 4649, 697 Passed LTC http://tests.stockfishchess.org/tests/view/5e2c85ccab2d69d58394faa7 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 32588 W: 4206 L: 3986 D: 24396 Ptnml(0-2): 244, 2909, 9738, 3111, 253 closes https://github.com/official-stockfish/Stockfish/pull/2516 Bench: 4765486 --- src/evaluate.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a1a3b4ed..be39f8a7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -168,7 +168,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score) const; + Score initiative(Score score, Score materialScore) const; const Position& pos; Material::Entry* me; @@ -696,10 +696,7 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Score score) const { - - Value mg = mg_value(score); - Value eg = eg_value(score); + Score Evaluation::initiative(Score score, Score materialScore) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -724,6 +721,11 @@ namespace { - 43 * almostUnwinnable - 100 ; + // Give more importance to non-material score + score = (score * 2 - materialScore) / 2; + Value mg = mg_value(score); + Value eg = eg_value(score); + // Now apply the bonus: note that we find the attacking side by extracting the // sign of the midgame or endgame values, and that we carefully cap the bonus // so that the midgame and endgame scores do not change sign after the bonus. @@ -792,6 +794,9 @@ namespace { if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; + // Remember this score + Score materialScore = score; + // Main evaluation begins here initialize(); @@ -810,7 +815,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(score); + score += initiative(score, materialScore); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); From 39437f4e55aaa26ef9f0d5a1c762e560e9ffde32 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Sat, 21 Dec 2019 21:41:42 +0200 Subject: [PATCH 177/281] Advise the kernel to use huge pages (Linux) Align the TT allocation by 2M to make it huge page friendly and advise the kernel to use huge pages. Benchmarks on my i7-8700K (6C/12T) box: (3 runs per bench per config) vanilla (nps) hugepages (nps) avg ================================================================================== bench | 3012490 3024364 3036331 3071052 3067544 3071052 +1.5% bench 16 12 20 | 19237932 19050166 19085315 19266346 19207025 19548758 +1.1% bench 16384 12 20 | 18182313 18371581 18336838 19381275 19738012 19620225 +7.0% On my box, huge pages have a significant perf impact when using a big hash size. They also speed up TT initialization big time: vanilla (s) huge pages (s) speed-up ======================================================================= time stockfish bench 16384 1 1 | 5.37 1.48 3.6x In practice, huge pages with auto-defrag may always be enabled in the system, in which case this patch has no effect. This depends on the values in /sys/kernel/mm/transparent_hugepage/enabled and /sys/kernel/mm/transparent_hugepage/defrag. closes https://github.com/official-stockfish/Stockfish/pull/2463 No functional change --- src/misc.cpp | 36 +++++++++++++++++++++++++++++++++++- src/misc.h | 1 + src/tt.cpp | 6 ++---- src/tt.h | 16 +++++++--------- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 484d0b21..0bae9f1e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -47,6 +47,11 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); #include #include +#ifdef __linux__ +#include +#include +#endif + #include "misc.h" #include "thread.h" @@ -190,7 +195,7 @@ const std::string compiler_info() { compiler += "(unknown version)"; #endif - #if defined(__APPLE__) + #if defined(__APPLE__) compiler += " on Apple"; #elif defined(__CYGWIN__) compiler += " on Cygwin"; @@ -288,6 +293,35 @@ void prefetch(void* addr) { #endif + +/// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages. +/// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free. +/// With c++17 some of this functionality can be simplified. +#ifdef __linux__ + +void* aligned_ttmem_alloc(size_t allocSize, void** mem) { + + constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes + size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment + *mem = aligned_alloc(alignment, size); + madvise(*mem, allocSize, MADV_HUGEPAGE); + return *mem; +} + +#else + +void* aligned_ttmem_alloc(size_t allocSize, void** mem) { + + constexpr size_t alignment = 64; // assumed cache line size + size_t size = allocSize + alignment - 1; // allocate some extra space + *mem = malloc(size); + void* ret = reinterpret_cast((uintptr_t(*mem) + alignment - 1) & ~uintptr_t(alignment - 1)); + return ret; +} + +#endif + + namespace WinProcGroup { #ifndef _WIN32 diff --git a/src/misc.h b/src/misc.h index b11c5aa8..45d9951a 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,6 +33,7 @@ const std::string engine_info(bool to_uci = false); const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); +void* aligned_ttmem_alloc(size_t size, void** mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 0b4a59de..080d3a6b 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,11 +63,10 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); - free(mem); - mem = malloc(clusterCount * sizeof(Cluster) + CacheLineSize - 1); + clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); + table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), &mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize @@ -75,7 +74,6 @@ void TranspositionTable::resize(size_t mbSize) { exit(EXIT_FAILURE); } - table = (Cluster*)((uintptr_t(mem) + CacheLineSize - 1) & ~(CacheLineSize - 1)); clear(); } diff --git a/src/tt.h b/src/tt.h index 98b054d3..142afd90 100644 --- a/src/tt.h +++ b/src/tt.h @@ -57,24 +57,22 @@ private: }; -/// A TranspositionTable consists of a power of 2 number of clusters and each -/// cluster consists of ClusterSize number of TTEntry. Each non-empty entry -/// contains information of exactly one position. The size of a cluster should -/// divide the size of a cache line size, to ensure that clusters never cross -/// cache lines. This ensures best cache performance, as the cacheline is -/// prefetched, as soon as possible. +/// A TranspositionTable is an array of Cluster, of size clusterCount. Each +/// cluster consists of ClusterSize number of TTEntry. Each non-empty TTEntry +/// contains information on exactly one position. The size of a Cluster should +/// divide the size of a cache line for best performance, +/// as the cacheline is prefetched when possible. class TranspositionTable { - static constexpr int CacheLineSize = 64; static constexpr int ClusterSize = 3; struct Cluster { TTEntry entry[ClusterSize]; - char padding[2]; // Align to a divisor of the cache line size + char padding[2]; // Pad to 32 bytes }; - static_assert(CacheLineSize % sizeof(Cluster) == 0, "Cluster size incorrect"); + static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); public: ~TranspositionTable() { free(mem); } From 1d3efff47274bd03d4deced8d7ba0360bd1dba8a Mon Sep 17 00:00:00 2001 From: Alain SAVARD Date: Mon, 27 Jan 2020 09:25:41 -0500 Subject: [PATCH 178/281] Dynamic Complexity based on psqt Adjust initiative score by psqt/2 instead of materialScore/2 which simplifies #2516 Passed STC http://tests.stockfishchess.org/tests/view/5e2e667dab2d69d58394fc73 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 23198 W: 4506 L: 4353 D: 14339 Ptnml(0-2): 396, 2615, 5380, 2728, 418 Passed LTC http://tests.stockfishchess.org/tests/view/5e2ed75cab2d69d58394fcbf LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 8519 W: 1179 L: 1062 D: 6278 Ptnml(0-2): 50, 775, 2472, 843, 74 closes https://github.com/official-stockfish/Stockfish/pull/2522 Bench: 4684459 --- src/evaluate.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index be39f8a7..8d7976d5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -168,7 +168,7 @@ namespace { template Score passed() const; template Score space() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Score score, Score materialScore) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@ -696,7 +696,7 @@ namespace { // known attacking/defending status of the players. template - Score Evaluation::initiative(Score score, Score materialScore) const { + Score Evaluation::initiative(Score score) const { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); @@ -722,7 +722,7 @@ namespace { - 100 ; // Give more importance to non-material score - score = (score * 2 - materialScore) / 2; + score = score - pos.psq_score() / 2; Value mg = mg_value(score); Value eg = eg_value(score); @@ -794,9 +794,6 @@ namespace { if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; - // Remember this score - Score materialScore = score; - // Main evaluation begins here initialize(); @@ -815,7 +812,7 @@ namespace { + passed< WHITE>() - passed< BLACK>() + space< WHITE>() - space< BLACK>(); - score += initiative(score, materialScore); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); From d878bc8cda47044f4db37a954f25e6122dc0d0ca Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Mon, 27 Jan 2020 20:48:01 -0500 Subject: [PATCH 179/281] Less NMP if the position was previously in PV. The intention of the patch is to avoid aggressive null move pruning (NMP) in positions that have previously been found to be important (PV nodes). If we already do not apply NMP for current PV nodes, it makes sense to apply it less often for positions that have previously been PV nodes too. STC: LLR: 2.96 (-2.94,2.94) {-1.00,3.00} Total: 14959 W: 2921 L: 2782 D: 9256 Ptnml(0-2): 254, 1679, 3493, 1762, 282 http://tests.stockfishchess.org/tests/view/5e2f6637ab2d69d58394fcfd LTC: LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 6442 W: 899 L: 753 D: 4790 Ptnml(0-2): 42, 549, 1885, 659, 61 http://tests.stockfishchess.org/tests/view/5e2f767bab2d69d58394fd04 closes https://github.com/official-stockfish/Stockfish/pull/2525 Bench: 4725546 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 1490a266..044187e5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -841,7 +841,7 @@ namespace { && (ss-1)->statScore < 23397 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 32 * depth + 292 - improving * 30 + && ss->staticEval >= beta - 32 * depth - 30 * improving + 120 * ttPv + 292 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) From 71e0b5385e2717679a57c6b77d8c7ac5fff3b89f Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Tue, 28 Jan 2020 13:38:03 +0100 Subject: [PATCH 180/281] More bonus for bestMoves on past PV nodes It looks like it is important to keep past PV (ttPv) nodes as close as possible to current PV nodes. Credits to Mark Tenzer (31m059) & Stefan Geschwentner who first tried ideas on ttPv nodes. STC: https://tests.stockfishchess.org/tests/view/5e2ff5efab2d69d58394fd52 LLR: 2.95 (-2.94,2.94) {-1.00,3.00} Total: 13302 W: 2647 L: 2507 D: 8148 Ptnml(0-2): 237, 1540, 2956, 1632, 260 LTC: https://tests.stockfishchess.org/tests/view/5e2fff38ab2d69d58394fd55 LLR: 2.95 (-2.94,2.94) {0.00,2.00} Total: 15797 W: 2137 L: 1960 D: 11700 Ptnml(0-2): 96, 1443, 4628, 1547, 130 closes https://github.com/official-stockfish/Stockfish/pull/2529 bench: 5545845 --- src/search.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 044187e5..84f9bb23 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -158,7 +158,7 @@ namespace { void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV); // perft() is our utility to verify move generation. All the leaf nodes up // to the given depth are generated and counted, and the sum is returned. @@ -713,7 +713,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth + (!PvNode && ttPv))); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -722,7 +722,7 @@ namespace { // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) { - int penalty = -stat_bonus(depth); + int penalty = -stat_bonus(depth + (!PvNode && ttPv)); thisThread->mainHistory[us][from_to(ttMove)] << penalty; update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } @@ -1326,7 +1326,7 @@ moves_loop: // When in check, search starts from here else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, - quietsSearched, quietCount, capturesSearched, captureCount, depth); + quietsSearched, quietCount, capturesSearched, captureCount, depth, (!PvNode && ttPv)); // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) @@ -1602,7 +1602,7 @@ moves_loop: // When in check, search starts from here // update_all_stats() updates stats at the end of search() when a bestMove is found void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV) { int bonus1, bonus2; Color us = pos.side_to_move(); @@ -1612,8 +1612,8 @@ moves_loop: // When in check, search starts from here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : stat_bonus(depth); // smaller bonus + bonus2 = pastPV || bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus if (!pos.capture_or_promotion(bestMove)) { From a910ba71eedde4f67805f05b29215cbeff4fe5f1 Mon Sep 17 00:00:00 2001 From: joergoster Date: Mon, 27 Jan 2020 18:53:25 +0100 Subject: [PATCH 181/281] Simplify hashfull calculation. We can simplify the calculation of the hashfull info by looping over exact 1,000 entries, and then divide the result by ClusterSize. Somewhat memory accesses, somewhat more accurate. Passed non-regression LTC https://tests.stockfishchess.org/tests/view/5e30079dab2d69d58394fd5d LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 30125 W: 3987 L: 3926 D: 22212 Ptnml(0-2): 177, 2504, 9558, 2642, 141 closes https://github.com/official-stockfish/Stockfish/pull/2523 No functional change. --- src/tt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tt.cpp b/src/tt.cpp index 080d3a6b..46860fe9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -148,9 +148,9 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { int TranspositionTable::hashfull() const { int cnt = 0; - for (int i = 0; i < 1000 / ClusterSize; ++i) + for (int i = 0; i < 1000; ++i) for (int j = 0; j < ClusterSize; ++j) cnt += (table[i].entry[j].genBound8 & 0xF8) == generation8; - return cnt * 1000 / (ClusterSize * (1000 / ClusterSize)); + return cnt / ClusterSize; } From 3b70932b0dee0cf1817baf0daa43ac92e18003c4 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 28 Jan 2020 16:17:52 +0100 Subject: [PATCH 182/281] Fix compilation on android Fall back to the default implementation of aligned_ttmem_alloc, which was introduced as part of 39437f4e55aaa26ef9f0d5a1c762e560e9ffde32 Fixes #2524 No functional change. --- src/misc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 0bae9f1e..cf18d2e2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -47,7 +47,7 @@ typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); #include #include -#ifdef __linux__ +#if defined(__linux__) && !defined(__ANDROID__) #include #include #endif @@ -297,7 +297,7 @@ void prefetch(void* addr) { /// aligned_ttmem_alloc will return suitably aligned memory, and if possible use large pages. /// The returned pointer is the aligned one, while the mem argument is the one that needs to be passed to free. /// With c++17 some of this functionality can be simplified. -#ifdef __linux__ +#if defined(__linux__) && !defined(__ANDROID__) void* aligned_ttmem_alloc(size_t allocSize, void** mem) { From 6ccb1cac5aaaf7337da8b1738448793be63fdfdb Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 30 Jan 2020 21:44:04 +0100 Subject: [PATCH 183/281] Revert 5 recent patches Revert 5 patches which were merged, but lead to a regression test that showed negative Elo gain: http://tests.stockfishchess.org/tests/view/5e307251ab2d69d58394fdb9 This was discussed in depth in: https://github.com/official-stockfish/Stockfish/issues/2531 Each patch was removed and tested as a simplification, full list below, and the whole combo as well. After the revert the regression test showed a neutral result: http://tests.stockfishchess.org/tests/view/5e334851708b13464ceea33c As a result of this experience, the SPRT testing bounds will be made more strict. Reverted patches: 1 Dynamic Complexity 6d0eabd5fe2961551477820ab7619e2c31e01ffd : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fcacec661e2e6a340d08 : LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 38130 W: 7326 L: 7189 D: 23615 Ptnml(0-2): 677, 4346, 8843, 4545, 646 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c18fec661e2e6a340d73 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 38675 W: 4941 L: 4866 D: 28868 Ptnml(0-2): 270, 3556, 11429, 3584, 291 3 More bonus for bestMoves on past PV nodes 71e0b5385e2717679a57c6b77d8c7ac5fff3b89f : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fe93ec661e2e6a340d10 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 46100 W: 8853 L: 8727 D: 28520 Ptnml(0-2): 796, 5297, 10749, 5387, 813 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c187ec661e2e6a340d71 : LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 16920 W: 2161 L: 2055 D: 12704 Ptnml(0-2): 115, 1498, 5006, 1569, 130 4 Tweak Restricted Piece Bonus 0ae00454ba6928d181b46103e5c83e6d58fcebe5 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31fefaec661e2e6a340d15 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 88328 W: 17060 L: 16997 D: 54271 Ptnml(0-2): 1536, 10446, 20169, 10422, 1581 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c17aec661e2e6a340d6f : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 34784 W: 4551 L: 4466 D: 25767 Ptnml(0-2): 255, 3279, 10061, 3345, 262 5 History update for pruned captures 01b6088af39902001d2d6844561b6a2faa549282 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31ff5eec661e2e6a340d1a : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 29541 W: 5735 L: 5588 D: 18218 Ptnml(0-2): 483, 3445, 6820, 3469, 545 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c196ec661e2e6a340d75 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 22177 W: 2854 L: 2757 D: 16566 Ptnml(0-2): 143, 2005, 6555, 2055, 164 6 Tweak trapped rook penalty 18fc21eba0368fd5e3c4c4b8ee1000c9ac445425 : STC 10+0.1 https://tests.stockfishchess.org/tests/view/5e31ffb1ec661e2e6a340d1c : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 24476 W: 4727 L: 4569 D: 15180 Ptnml(0-2): 390, 2834, 5659, 2933, 417 LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e32c19eec661e2e6a340d77 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 97332 W: 12492 L: 12466 D: 72374 Ptnml(0-2): 690, 9107, 28738, 9034, 720 All 5 as one simplification : LTC 60+0.6 https://tests.stockfishchess.org/tests/view/5e334098708b13464ceea330 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 7829 W: 1079 L: 964 D: 5786 Ptnml(0-2): 52, 690, 2281, 781, 65 Bench: 5153165 --- src/evaluate.cpp | 5 ++--- src/search.cpp | 18 +++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8d7976d5..bf1eee9b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -145,7 +145,7 @@ namespace { constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 30); + constexpr Score TrappedRook = S( 52, 10); constexpr Score WeakQueen = S( 49, 15); #undef S @@ -524,7 +524,7 @@ namespace { b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; - score += RestrictedPiece * (popcount(b) + popcount(b & pos.pieces())); + score += RestrictedPiece * popcount(b); // Protected or unattacked squares safe = ~attackedBy[Them][ALL_PIECES] | attackedBy[Us][ALL_PIECES]; @@ -722,7 +722,6 @@ namespace { - 100 ; // Give more importance to non-material score - score = score - pos.psq_score() / 2; Value mg = mg_value(score); Value eg = eg_value(score); diff --git a/src/search.cpp b/src/search.cpp index 84f9bb23..985af7bc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -158,7 +158,7 @@ namespace { void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV); + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); // perft() is our utility to verify move generation. All the leaf nodes up // to the given depth are generated and counted, and the sum is returned. @@ -713,7 +713,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth + (!PvNode && ttPv))); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -722,7 +722,7 @@ namespace { // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) { - int penalty = -stat_bonus(depth + (!PvNode && ttPv)); + int penalty = -stat_bonus(depth); thisThread->mainHistory[us][from_to(ttMove)] << penalty; update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } @@ -1028,11 +1028,7 @@ moves_loop: // When in check, search starts from here continue; } else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - { - if (captureOrPromotion && captureCount < 32) - capturesSearched[captureCount++] = move; continue; - } } // Step 14. Extensions (~75 Elo) @@ -1326,7 +1322,7 @@ moves_loop: // When in check, search starts from here else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, - quietsSearched, quietCount, capturesSearched, captureCount, depth, (!PvNode && ttPv)); + quietsSearched, quietCount, capturesSearched, captureCount, depth); // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) @@ -1602,7 +1598,7 @@ moves_loop: // When in check, search starts from here // update_all_stats() updates stats at the end of search() when a bestMove is found void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, - Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth, bool pastPV) { + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { int bonus1, bonus2; Color us = pos.side_to_move(); @@ -1612,8 +1608,8 @@ moves_loop: // When in check, search starts from here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = pastPV || bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : stat_bonus(depth); // smaller bonus + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus if (!pos.capture_or_promotion(bestMove)) { From c390b734c451b3d976b331244e281d261b26ac3a Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 30 Jan 2020 20:42:58 +0000 Subject: [PATCH 184/281] Simplify Tweak late move reductions at root. Revert change from Jan 15. STC 10+0.1 : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 65135 W: 12543 L: 12436 D: 40156 Ptnml(0-2): 1090, 7618, 14947, 7623, 1136 https://tests.stockfishchess.org/tests/view/5e334016708b13464ceea32e LTC 60+0.6 : LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 17768 W: 2286 L: 2191 D: 13291 Ptnml(0-2): 128, 1602, 5273, 1679, 140 https://tests.stockfishchess.org/tests/view/5e34011e57e1ecae66ec2aab closes https://github.com/official-stockfish/Stockfish/pull/2537 Bench: 4914050 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 985af7bc..9562bf86 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1115,7 +1115,7 @@ moves_loop: // When in check, search starts from here // Step 16. Reduced depth search (LMR, ~200 Elo). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 - && moveCount > 1 + rootNode + (rootNode && bestValue < alpha) + && moveCount > 1 + 2 * rootNode && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion || moveCountPruning From 0f37da0e34e02efaaca907878d1a3e0d916f447c Mon Sep 17 00:00:00 2001 From: xoto10 Date: Fri, 31 Jan 2020 15:55:29 +0000 Subject: [PATCH 185/281] Simplify away king infiltration. STC : LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 91438 W: 17496 L: 17438 D: 56504 Ptnml(0-2): 1573, 10711, 21067, 10790, 1563 https://tests.stockfishchess.org/tests/view/5e34812630ae32da08941d65 LTC : LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 40485 W: 5246 L: 5177 D: 30062 Ptnml(0-2): 289, 3818, 11976, 3812, 327 https://tests.stockfishchess.org/tests/view/5e354daee70d848499f6380c closes https://github.com/official-stockfish/Stockfish/pull/2542 Bench: 5047825 --- src/evaluate.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index bf1eee9b..17597648 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -701,9 +701,6 @@ namespace { int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - distance(pos.square(WHITE), pos.square(BLACK)); - bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 - || rank_of(pos.square(BLACK)) < RANK_5; - bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); @@ -715,11 +712,10 @@ namespace { int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking - + 12 * infiltration + 21 * pawnsOnBothFlanks + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 100 ; + - 95 ; // Give more importance to non-material score Value mg = mg_value(score); From ddd4224640e04463c62b5896660f6f6abe4cc1a5 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 4 Feb 2020 20:41:58 +0300 Subject: [PATCH 186/281] Reintroduce king infiltration This patch reintroduces the recently simplified king infiltration bonus in initiative calculation, doubling its effect, and compensating more. passed STC http://tests.stockfishchess.org/tests/view/5e3476f630ae32da08941d5c LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 75323 W: 14434 L: 14140 D: 46749 Ptnml(0-2): 1231, 8729, 17528, 8826, 1331 passed LTC http://tests.stockfishchess.org/tests/view/5e377353e70d848499f638c1 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 171466 W: 22223 L: 21561 D: 127682 Ptnml(0-2): 1204, 15951, 50831, 16397, 1312 closes https://github.com/official-stockfish/Stockfish/pull/2545 Brench: 4869669 --- src/evaluate.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 17597648..df7ff5ea 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -708,14 +708,18 @@ namespace { && outflanking < 0 && !pawnsOnBothFlanks; + bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 + || rank_of(pos.square(BLACK)) < RANK_5; + // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking + 21 * pawnsOnBothFlanks + + 24 * infiltration + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable - - 95 ; + -110 ; // Give more importance to non-material score Value mg = mg_value(score); From 0c878adb36c1013944231083d6a7b3b53aa1ad7e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 5 Feb 2020 15:18:24 +0100 Subject: [PATCH 187/281] Small cleanups. closes https://github.com/official-stockfish/Stockfish/pull/2532 Bench: 4869669 --- src/bitbase.cpp | 1 - src/endgame.h | 2 +- src/evaluate.cpp | 2 -- src/main.cpp | 2 +- src/misc.cpp | 14 +++++++------- src/misc.h | 2 +- src/movegen.cpp | 1 - src/position.cpp | 4 ++-- src/thread.cpp | 17 ++++++++--------- src/thread.h | 2 +- src/tt.cpp | 2 +- 11 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index ed6ed208..bef2dc49 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -19,7 +19,6 @@ */ #include -#include #include #include diff --git a/src/endgame.h b/src/endgame.h index 4642e448..f6135354 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -21,10 +21,10 @@ #ifndef ENDGAME_H_INCLUDED #define ENDGAME_H_INCLUDED -#include #include #include #include +#include #include #include "position.h" diff --git a/src/evaluate.cpp b/src/evaluate.cpp index df7ff5ea..ceba2588 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -520,7 +520,6 @@ namespace { } // Bonus for restricting their piece moves - // Greater bonus when landing square is occupied b = attackedBy[Them][ALL_PIECES] & ~stronglyProtected & attackedBy[Us][ALL_PIECES]; @@ -721,7 +720,6 @@ namespace { - 43 * almostUnwinnable -110 ; - // Give more importance to non-material score Value mg = mg_value(score); Value eg = eg_value(score); diff --git a/src/main.cpp b/src/main.cpp index 148bf248..182cf105 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,12 +21,12 @@ #include #include "bitboard.h" +#include "endgame.h" #include "position.h" #include "search.h" #include "thread.h" #include "tt.h" #include "uci.h" -#include "endgame.h" #include "syzygy/tbprobe.h" namespace PSQT { diff --git a/src/misc.cpp b/src/misc.cpp index cf18d2e2..4d6483e7 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -299,23 +299,23 @@ void prefetch(void* addr) { /// With c++17 some of this functionality can be simplified. #if defined(__linux__) && !defined(__ANDROID__) -void* aligned_ttmem_alloc(size_t allocSize, void** mem) { +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment - *mem = aligned_alloc(alignment, size); - madvise(*mem, allocSize, MADV_HUGEPAGE); - return *mem; + mem = aligned_alloc(alignment, size); + madvise(mem, allocSize, MADV_HUGEPAGE); + return mem; } #else -void* aligned_ttmem_alloc(size_t allocSize, void** mem) { +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 64; // assumed cache line size size_t size = allocSize + alignment - 1; // allocate some extra space - *mem = malloc(size); - void* ret = reinterpret_cast((uintptr_t(*mem) + alignment - 1) & ~uintptr_t(alignment - 1)); + mem = malloc(size); + void* ret = reinterpret_cast((uintptr_t(mem) + alignment - 1) & ~uintptr_t(alignment - 1)); return ret; } diff --git a/src/misc.h b/src/misc.h index 45d9951a..a3780ba5 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,7 +33,7 @@ const std::string engine_info(bool to_uci = false); const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); -void* aligned_ttmem_alloc(size_t size, void** mem); +void* aligned_ttmem_alloc(size_t size, void*& mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/movegen.cpp b/src/movegen.cpp index 8f6edffb..7e8961ae 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -52,7 +52,6 @@ namespace { template ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { - // Compute some compile time parameters relative to the white side constexpr Color Them = (Us == WHITE ? BLACK : WHITE); constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); diff --git a/src/position.cpp b/src/position.cpp index de9722ff..5efd9c42 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -633,11 +633,11 @@ bool Position::gives_check(Move m) const { Square to = to_sq(m); // Is there a direct check? - if (st->checkSquares[type_of(piece_on(from))] & to) + if (check_squares(type_of(piece_on(from))) & to) return true; // Is there a discovered check? - if ( (st->blockersForKing[~sideToMove] & from) + if ( (blockers_for_king(~sideToMove) & from) && !aligned(from, to, square(~sideToMove))) return true; diff --git a/src/thread.cpp b/src/thread.cpp index 615d482c..10ec96dd 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -54,7 +54,7 @@ Thread::~Thread() { /// Thread::bestMoveCount(Move move) return best move counter for the given root move -int Thread::best_move_count(Move move) { +int Thread::best_move_count(Move move) const { auto rm = std::find(rootMoves.begin() + pvIdx, rootMoves.begin() + pvLast, move); @@ -71,14 +71,13 @@ void Thread::clear() { captureHistory.fill(0); for (bool inCheck : { false, true }) - for (StatsType c : { NoCaptures, Captures }) - for (auto& to : continuationHistory[inCheck][c]) - for (auto& h : to) - h->fill(0); - - for (bool inCheck : { false, true }) - for (StatsType c : { NoCaptures, Captures }) - continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + for (StatsType c : { NoCaptures, Captures }) + { + for (auto& to : continuationHistory[inCheck][c]) + for (auto& h : to) + h->fill(0); + continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); + } } /// Thread::start_searching() wakes up the thread that will start the search diff --git a/src/thread.h b/src/thread.h index aea86fd5..63629e33 100644 --- a/src/thread.h +++ b/src/thread.h @@ -56,7 +56,7 @@ public: void idle_loop(); void start_searching(); void wait_for_search_finished(); - int best_move_count(Move move); + int best_move_count(Move move) const; Pawns::Table pawnsTable; Material::Table materialTable; diff --git a/src/tt.cpp b/src/tt.cpp index 46860fe9..7e95a2a4 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -66,7 +66,7 @@ void TranspositionTable::resize(size_t mbSize) { free(mem); clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); - table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), &mem)); + table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); if (!mem) { std::cerr << "Failed to allocate " << mbSize From 0aee1ec4ab3f7891c6a59d9d9e0113655300ce64 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 7 Feb 2020 10:42:10 +0100 Subject: [PATCH 188/281] Fix wrong assert. can trigger an abort when compiling with debug=yes, and using 7men TB. The assert should check that less than 8 pieces are in the key for each side, matching the assumption that underlies the FEN string construction. Also take explicitly care of a 'v' character in material strings. Fixes an issue reported in the forum: https://groups.google.com/d/msg/fishcooking/yoVC7etIpz0/7mS7ntZMBAAJ closes https://github.com/official-stockfish/Stockfish/pull/2547 No functional change. --- src/position.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 5efd9c42..0ac45057 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -375,11 +375,13 @@ void Position::set_state(StateInfo* si) const { Position& Position::set(const string& code, Color c, StateInfo* si) { - assert(code.length() > 0 && code.length() < 8); assert(code[0] == 'K'); string sides[] = { code.substr(code.find('K', 1)), // Weak - code.substr(0, code.find('K', 1)) }; // Strong + code.substr(0, std::min(code.find('v'), code.find('K', 1))) }; // Strong + + assert(sides[0].length() > 0 && sides[0].length() < 8); + assert(sides[1].length() > 0 && sides[1].length() < 8); std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); From 4e8986483a83296e37433da7b07b64de53613f6f Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 7 Feb 2020 20:04:43 +0300 Subject: [PATCH 189/281] Modify singular beta for ttPv positions. This patch lowers singular beta for positions that have been in pv and are not pv nodes. The idea of using ttpv && !PvNode improved scaling with TC and could be useful for other search heuristics. passed STC http://tests.stockfishchess.org/tests/view/5e3f6d7ce70d848499f63bbc LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 154953 W: 29688 L: 29272 D: 95993 Ptnml(0-2): 2616, 17912, 36037, 18210, 2673 passed LTC http://tests.stockfishchess.org/tests/view/5e405561e70d848499f63bfa LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 70974 W: 9305 L: 8932 D: 52737 Ptnml(0-2): 466, 6658, 20920, 6826, 569 closes https://github.com/official-stockfish/Stockfish/pull/2550 Bench: 4932981 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 9562bf86..c8a35a36 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1048,7 +1048,7 @@ moves_loop: // When in check, search starts from here && tte->depth() >= depth - 3 && pos.legal(move)) { - Value singularBeta = ttValue - 2 * depth; + Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; Depth halfDepth = depth / 2; ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); From be5a2f015e45886e32867b4559ef51dd694a3cec Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 11 Feb 2020 20:42:32 +0100 Subject: [PATCH 190/281] Fix for incorrect VALUE_MATE_IN_MAX_PLY usage. Fixes #2533, fixes #2543, fixes #2423. the code that prevents false mate announcements depending on the TT state (GHI), incorrectly used VALUE_MATE_IN_MAX_PLY. The latter constant, however, also includes, counterintuitively, the TB win range. This patch fixes that, by restoring the behavior for TB win scores, while retaining the false mate correctness, and improving the mate finding ability. In particular no alse mates are announced with the poisened hash testcase ``` position fen 8/8/8/3k4/8/8/6K1/7R w - - 0 1 go depth 40 position fen 8/8/8/3k4/8/8/6K1/7R w - - 76 1 go depth 20 ucinewgame ``` mates are found with the testcases reported in #2543 ``` position fen 4k3/3pp3/8/8/8/8/2PPP3/4K3 w - - 0 1 setoption name Hash value 1024 go depth 55 ucinewgame ``` and ``` position fen 4k3/4p3/8/8/8/8/3PP3/4K3 w - - 0 1 setoption name Hash value 1024 go depth 45 ucinewgame ``` furthermore, on the mate finding benchmark (ChestUCI_23102018.epd), performance improves over master, roughly reaching performance with the false mate protection reverted ``` Analyzing 6566 mate positions for best and found mates: ----------------best ---------------found nodes master revert fixed master revert fixed 16000000 4233 4236 4235 5200 5201 5199 32000000 4583 4585 4585 5417 5424 5418 64000000 4852 4853 4855 5575 5584 5579 128000000 5071 5068 5066 5710 5720 5716 256000000 5280 5282 5279 5819 5827 5826 512000000 5471 5468 5468 5919 5935 5932 ``` On a testcase with TB enabled, progress is made consistently, contrary to master ``` setoption name SyzygyPath value ../../../syzygy/3-4-5/ setoption name Hash value 2048 position fen 1R6/3k4/8/K2p4/4n3/2P5/8/8 w - - 0 1 go depth 58 ucinewgame ``` The PR (prior to a rewrite for clarity) passed STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 65405 W: 12454 L: 12384 D: 40567 Ptnml(0-2): 920, 7256, 16285, 7286, 944 http://tests.stockfishchess.org/tests/view/5e441a3be70d848499f63d15 passed LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 27096 W: 3477 L: 3413 D: 20206 Ptnml(0-2): 128, 2215, 8776, 2292, 122 http://tests.stockfishchess.org/tests/view/5e44e277e70d848499f63d63 The incorrectly named VALUE_MATE_IN_MAX_PLY and VALUE_MATED_IN_MAX_PLY were renamed into VALUE_TB_WIN_IN_MAX_PLY and VALUE_TB_LOSS_IN_MAX_PLY, and correclty defined VALUE_MATE_IN_MAX_PLY and VALUE_MATED_IN_MAX_PLY were introduced. One further (corner case) mistake using these constants was fixed (go mate X), which could lead to a premature return if X > MAX_PLY / 2, but TB were present. Thanks to @svivanov72 for one of the reports and help fixing the issue. closes https://github.com/official-stockfish/Stockfish/pull/2552 Bench: 4932981 --- src/endgame.cpp | 4 ++-- src/search.cpp | 58 +++++++++++++++++++++++++++++++++---------------- src/types.h | 6 +++-- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 2ed6ebc2..6745ee26 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -137,7 +137,7 @@ Value Endgame::operator()(const Position& pos) const { ||(pos.count(strongSide) && pos.count(strongSide)) || ( (pos.pieces(strongSide, BISHOP) & ~DarkSquares) && (pos.pieces(strongSide, BISHOP) & DarkSquares))) - result = std::min(result + VALUE_KNOWN_WIN, VALUE_MATE_IN_MAX_PLY - 1); + result = std::min(result + VALUE_KNOWN_WIN, VALUE_TB_WIN_IN_MAX_PLY - 1); return strongSide == pos.side_to_move() ? result : -result; } @@ -162,7 +162,7 @@ Value Endgame::operator()(const Position& pos) const { + PushClose[distance(winnerKSq, loserKSq)] + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; - assert(abs(result) < VALUE_MATE_IN_MAX_PLY); + assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; } diff --git a/src/search.cpp b/src/search.cpp index c8a35a36..f1416a74 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -290,13 +290,13 @@ void MainThread::search() { votes[th->rootMoves[0].pv[0]] += (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (bestThread->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY) + if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) { // Make sure we pick the shortest mate if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } - else if ( th->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY + else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY || votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) bestThread = th; } @@ -755,9 +755,10 @@ namespace { int drawScore = TB::UseRule50 ? 1 : 0; - value = wdl < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1 - : wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1 - : VALUE_DRAW + 2 * wdl * drawScore; + // use the range VALUE_MATE_IN_MAX_PLY to VALUE_TB_WIN_IN_MAX_PLY to score + value = wdl < -drawScore ? VALUE_MATED_IN_MAX_PLY + ss->ply + 1 + : wdl > drawScore ? VALUE_MATE_IN_MAX_PLY - ss->ply - 1 + : VALUE_DRAW + 2 * wdl * drawScore; Bound b = wdl < -drawScore ? BOUND_UPPER : wdl > drawScore ? BOUND_LOWER : BOUND_EXACT; @@ -863,7 +864,7 @@ namespace { if (nullValue >= beta) { // Do not return unproven mate scores - if (nullValue >= VALUE_MATE_IN_MAX_PLY) + if (nullValue >= VALUE_TB_WIN_IN_MAX_PLY) nullValue = beta; if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 13)) @@ -890,7 +891,7 @@ namespace { // much above beta, we can (almost) safely prune the previous move. if ( !PvNode && depth >= 5 - && abs(beta) < VALUE_MATE_IN_MAX_PLY) + && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); @@ -996,7 +997,7 @@ moves_loop: // When in check, search starts from here // Step 13. Pruning at shallow depth (~200 Elo) if ( !rootNode && pos.non_pawn_material(us) - && bestValue > VALUE_MATED_IN_MAX_PLY) + && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold moveCountPruning = moveCount >= futility_move_count(improving, depth); @@ -1494,7 +1495,7 @@ moves_loop: // When in check, search starts from here // Detect non-capture evasions that are candidates to be pruned evasionPrunable = inCheck && (depth != 0 || moveCount > 2) - && bestValue > VALUE_MATED_IN_MAX_PLY + && bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !pos.capture(move); // Don't search moves with negative SEE values @@ -1560,28 +1561,47 @@ moves_loop: // When in check, search starts from here } - // value_to_tt() adjusts a mate score from "plies to mate from the root" to - // "plies to mate from the current position". Non-mate scores are unchanged. + // value_to_tt() adjusts a mate or TB score from "plies to mate from the root" to + // "plies to mate from the current position". standard scores are unchanged. // The function is called before storing a value in the transposition table. Value value_to_tt(Value v, int ply) { assert(v != VALUE_NONE); - return v >= VALUE_MATE_IN_MAX_PLY ? v + ply - : v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v; + return v >= VALUE_TB_WIN_IN_MAX_PLY ? v + ply + : v <= VALUE_TB_LOSS_IN_MAX_PLY ? v - ply : v; } - // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score + // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate or TB score // from the transposition table (which refers to the plies to mate/be mated - // from current position) to "plies to mate/be mated from the root". + // from current position) to "plies to mate/be mated (TB win/loss) from the root". + // However, for mate scores, to avoid potentially false mate scores related to the 50 moves rule, + // and the graph history interaction, return an optimal TB score instead. Value value_from_tt(Value v, int ply, int r50c) { - return v == VALUE_NONE ? VALUE_NONE - : v >= VALUE_MATE_IN_MAX_PLY ? VALUE_MATE - v > 99 - r50c ? VALUE_MATE_IN_MAX_PLY : v - ply - : v <= VALUE_MATED_IN_MAX_PLY ? VALUE_MATE + v > 99 - r50c ? VALUE_MATED_IN_MAX_PLY : v + ply : v; + if (v == VALUE_NONE) + return VALUE_NONE; + + if (v >= VALUE_TB_WIN_IN_MAX_PLY) // TB win or better + { + if (v >= VALUE_MATE_IN_MAX_PLY && VALUE_MATE - v > 99 - r50c) + return VALUE_MATE_IN_MAX_PLY - 1; // do not return a potentially false mate score + + return v - ply; + } + + if (v <= VALUE_TB_LOSS_IN_MAX_PLY) // TB loss or worse + { + if (v <= VALUE_MATED_IN_MAX_PLY && VALUE_MATE + v > 99 - r50c) + return VALUE_MATED_IN_MAX_PLY + 1; // do not return a potentially false mate score + + return v + ply; + } + + return v; } @@ -1767,7 +1787,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { Depth d = updated ? depth : depth - 1; Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; - bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; + bool tb = TB::RootInTB && abs(v) < VALUE_MATE_IN_MAX_PLY; v = tb ? rootMoves[i].tbScore : v; if (ss.rdbuf()->in_avail()) // Not at first line diff --git a/src/types.h b/src/types.h index 902c2cfc..7ab7560a 100644 --- a/src/types.h +++ b/src/types.h @@ -176,8 +176,10 @@ enum Value : int { VALUE_INFINITE = 32001, VALUE_NONE = 32002, - VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, - VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, + VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, + VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, KnightValueMg = 781, KnightValueEg = 854, From 10ead8a724671132df60ca2e23ddcad7eff7b3e5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 10 Feb 2020 15:18:16 -0700 Subject: [PATCH 191/281] Simplify Futility Move Count remove two constants STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 62050 W: 11903 L: 11802 D: 38345 Ptnml(0-2): 1002, 7346, 14283, 7320, 1065 http://tests.stockfishchess.org/tests/view/5e41d73be70d848499f63c6d LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 12850 W: 1679 L: 1572 D: 9599 Ptnml(0-2): 82, 1171, 3818, 1249, 96 http://tests.stockfishchess.org/tests/view/5e42bf07e70d848499f63cc0 Bench: 4762351 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f1416a74..c3ebf9ab 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -79,7 +79,7 @@ namespace { } constexpr int futility_move_count(bool improving, Depth depth) { - return (5 + depth * depth) * (1 + improving) / 2 - 1; + return (4 + depth * depth) / (2 - improving); } // History and stats update bonus, based on depth From ab930f8d3f4a657f493305559756e85534c88911 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 18 Feb 2020 09:10:58 -0700 Subject: [PATCH 192/281] Updated KNNKP endgame. This is a patch that significantly improves playing KNNKP endgames: ``` Score of 2553 vs master: 132 - 38 - 830 [0.547] 1000 Elo difference: 32.8 +/- 8.7, LOS: 100.0 %, DrawRatio: 83.0 % ``` At the same time it reduces the evaluation of this mostly draw engame from ~7.5 to ~1.5 This patch does not regress against master in normal games: STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 96616 W: 18459 L: 18424 D: 59733 Ptnml(0-2): 1409, 10812, 23802, 10905, 1380 http://tests.stockfishchess.org/tests/view/5e49dfe6f8d1d52b40cd31bc LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 49726 W: 6340 L: 6304 D: 37082 Ptnml(0-2): 239, 4227, 15906, 4241, 250 http://tests.stockfishchess.org/tests/view/5e4ab9ee16fb3df8c4cc01d0 Theory: KNNK is a dead draw, however the presence of the additional weakSide pawn opens up some mate opportunities. The idea is to block the pawn (preferably behind the Troitsky line) with one of the knights and press the weakSide king into a corner. If we can stalemate the king, we release the pawn with the knight (to avoid actual stalemate), and use the knight to complete the mate before the pawn promotes. This is also why there is an additional penalty for advancement of the pawn. closes https://github.com/official-stockfish/Stockfish/pull/2553 Bench: 4981770 --- src/endgame.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 6745ee26..74e16fa6 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -310,16 +310,17 @@ Value Endgame::operator()(const Position& pos) const { } -/// KNN vs KP. Simply push the opposing king to the corner +/// KNN vs KP. Very drawish, but there are some mate opportunities if we can +// press the weakSide King to a corner before the pawn advances too much. template<> Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0)); assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); - Value result = 2 * KnightValueEg - - PawnValueEg - + PushToEdges[pos.square(weakSide)]; + Value result = PawnValueEg + + 2 * PushToEdges[pos.square(weakSide)] + - 10 * relative_rank(weakSide, pos.square(weakSide)); return strongSide == pos.side_to_move() ? result : -result; } From b8c00efa2767ebf74545d2ba4bd344ef7c963319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Demetz?= Date: Fri, 21 Feb 2020 14:01:59 +0100 Subject: [PATCH 193/281] Improve move order near the root Current move histories are known to work well near the leaves, whilst at higher depths they aren't very helpful. To address this problem this patch introduces a table dedicated for what's happening at plies 0-3. It's structured like mainHistory with ply index instead of color. It get cleared with each new search and is filled during iterative deepening at higher depths when recording successful quiet moves near the root or traversing nodes which were in the principal variation (ttPv). Medium TC (20+0.2): https://tests.stockfishchess.org/tests/view/5e4d358790a0a02810d096dc LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 100910 W: 16682 L: 16376 D: 67852 Ptnml(0-2): 1177, 10983, 25883, 11181, 1231 LTC: https://tests.stockfishchess.org/tests/view/5e4e2cb790a0a02810d09714 LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 80444 W: 10495 L: 10095 D: 59854 Ptnml(0-2): 551, 7479, 23803, 7797, 592 closes https://github.com/official-stockfish/Stockfish/pull/2557 Bench: 4705960 --- src/movepick.cpp | 11 ++++++----- src/movepick.h | 12 +++++++++++- src/search.cpp | 19 ++++++++++++++----- src/thread.cpp | 2 ++ src/thread.h | 1 + 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 025f5b82..575c9022 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -56,10 +56,10 @@ namespace { /// ordering is at the current node. /// MovePicker constructor for the main search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, - const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers) - : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) { +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, + const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) + : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), + refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) , ply(pl) { assert(d > 0); @@ -115,7 +115,8 @@ void MovePicker::score() { + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; + + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + + (ply < MAX_LPH ? 4 * (*lowPlyHistory)[ply][from_to(m)] : 0); else // Type == EVASIONS { diff --git a/src/movepick.h b/src/movepick.h index cdedc9b6..33c4b086 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -88,6 +88,12 @@ enum StatsType { NoCaptures, Captures }; /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards typedef Stats ButterflyHistory; +/// LowPlyHistory at higher depths records successful quiet moves on plies 0 to 3 +/// and quiet moves which are/were in the PV (ttPv) +/// It get cleared with each new search and get filled during iterative deepening +constexpr int MAX_LPH = 4; +typedef Stats LowPlyHistory; + /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// move, see www.chessprogramming.org/Countermove_Heuristic typedef Stats CounterMoveHistory; @@ -123,10 +129,12 @@ public: const PieceToHistory**, Square); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, + const LowPlyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Move, - Move*); + Move*, + int); Move next_move(bool skipQuiets = false); private: @@ -137,6 +145,7 @@ private: const Position& pos; const ButterflyHistory* mainHistory; + const LowPlyHistory* lowPlyHistory; const CapturePieceToHistory* captureHistory; const PieceToHistory** continuationHistory; Move ttMove; @@ -145,6 +154,7 @@ private: Square recaptureSquare; Value threshold; Depth depth; + int ply; ExtMove moves[MAX_MOVES]; }; diff --git a/src/search.cpp b/src/search.cpp index c3ebf9ab..3f860ac5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -156,7 +156,7 @@ namespace { Value value_from_tt(Value v, int ply, int r50c); void update_pv(Move* pv, Move move, Move* childPv); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); @@ -695,6 +695,10 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + + if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove)) + thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); + // thisThread->ttHitAverage can be used to approximate the running average of ttHit thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow + ttHitAverageResolution * ttHit; @@ -713,7 +717,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth), depth); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -948,10 +952,12 @@ moves_loop: // When in check, search starts from here Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, + &thisThread->lowPlyHistory, &thisThread->captureHistory, contHist, countermove, - ss->killers); + ss->killers, + depth > 12 && ttPv ? ss->ply : MAX_PLY); value = bestValue; singularLMR = moveCountPruning = false; @@ -1633,7 +1639,7 @@ moves_loop: // When in check, search starts from here if (!pos.capture_or_promotion(bestMove)) { - update_quiet_stats(pos, ss, bestMove, bonus2); + update_quiet_stats(pos, ss, bestMove, bonus2, depth); // Decrease all the non-best quiet moves for (int i = 0; i < quietCount; ++i) @@ -1673,7 +1679,7 @@ moves_loop: // When in check, search starts from here // update_quiet_stats() updates move sorting heuristics - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) { + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth) { if (ss->killers[0] != move) { @@ -1694,6 +1700,9 @@ moves_loop: // When in check, search starts from here Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } + + if (depth > 12 && ss->ply < MAX_LPH) + thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7); } // When playing with strength handicap, choose best move among a set of RootMoves diff --git a/src/thread.cpp b/src/thread.cpp index 10ec96dd..b5cb87d9 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -68,6 +68,7 @@ void Thread::clear() { counterMoves.fill(MOVE_NONE); mainHistory.fill(0); + lowPlyHistory.fill(0); captureHistory.fill(0); for (bool inCheck : { false, true }) @@ -211,6 +212,7 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); + th->lowPlyHistory.fill(0); } setupStates->back() = tmp; diff --git a/src/thread.h b/src/thread.h index 63629e33..41d2b8f6 100644 --- a/src/thread.h +++ b/src/thread.h @@ -71,6 +71,7 @@ public: Depth rootDepth, completedDepth; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; + LowPlyHistory lowPlyHistory; CapturePieceToHistory captureHistory; ContinuationHistory continuationHistory[2][2]; Score contempt; From 8352977b91d9246618c7273d59400a4a05a32e2a Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Sat, 22 Feb 2020 21:27:32 -0500 Subject: [PATCH 194/281] Use single param for Outpost and ReachableOutpost. In November 2019, as a result of the simplification of rank-based outposts by 37698b0, separate bonuses were introduced for outposts that are currently occupied and outposts that are reachable on the next move. However, the values of these two bonuses are quite similar, and they have remained that way for three months of development. It appears that we can safely retire the separate ReachableOutpost parameter and use the same Outpost bonus in both cases, restoring the basic principles of Stockfish outpost evaluation to their pre-November state, while also reducing the size of the parameter space. STC: LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 47680 W: 9213 L: 9092 D: 29375 Ptnml(0-2): 776, 5573, 11071, 5594, 826 https://tests.stockfishchess.org/tests/view/5e51e33190a0a02810d09802 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 14690 W: 1960 L: 1854 D: 10876 Ptnml(0-2): 93, 1381, 4317, 1435, 119 https://tests.stockfishchess.org/tests/view/5e52197990a0a02810d0980f closes https://github.com/official-stockfish/Stockfish/pull/2559 Bench: 4697493 --- src/evaluate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ceba2588..25aba644 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -139,7 +139,6 @@ namespace { constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score ReachableOutpost = S( 32, 10); constexpr Score RookOnQueenFile = S( 7, 6); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); @@ -296,7 +295,7 @@ namespace { score += Outpost * (Pt == KNIGHT ? 2 : 1); else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) - score += ReachableOutpost; + score += Outpost; // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s) From 2e1369d0302a87d570e509af7041a1be22b836a0 Mon Sep 17 00:00:00 2001 From: AndyGrant Date: Mon, 24 Feb 2020 23:32:17 +0100 Subject: [PATCH 195/281] Fix TT write in MultiPV case. fixes an error reported earlier as https://github.com/official-stockfish/Stockfish/issues/2404 by @AndyGrant. MultiPV at root shouldn't write to the TT for later lines, as that is neither the eval nor the bestmove for that position. Fixing this error doesn't matter for playing games (http://tests.stockfishchess.org/tests/view/5dcdbd810ebc590256324a11). However, it can lead to wrong mate announcements as reported by @uriblass. In particular the following testcase gives wrong results for the second search, prior to this patch: ``` setoption name MultiPV value 2 position fen 5R2/2kB2p1/p2bR3/8/3p1B2/8/PPP5/2K5 b - - 0 49 go depth 40 position fen 2B2R2/3r2p1/p1kbR3/8/3p1B2/8/PPP5/2K5 b - - 8 48 go depth 40 ``` fixes https://github.com/official-stockfish/Stockfish/issues/2561 closes https://github.com/official-stockfish/Stockfish/pull/2562 Only affects MultiPV search. Bench: 4697493 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3f860ac5..a32ff4b6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1339,7 +1339,7 @@ moves_loop: // When in check, search starts from here if (PvNode) bestValue = std::min(bestValue, maxValue); - if (!excludedMove) + if (!excludedMove && !(rootNode && thisThread->pvIdx)) tte->save(posKey, value_to_tt(bestValue, ss->ply), ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, From 09f53dbfa5b55e761ca8070960345ab140baad04 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sat, 22 Feb 2020 14:57:01 +0100 Subject: [PATCH 196/281] Weak queen protection Extra penalty if weak piece is only protected by a queen. STC: http://tests.stockfishchess.org/tests/view/5e53c6ab84a82b4acd4148fa LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 44630 W: 8615 L: 8359 D: 27656 Ptnml(0-2): 746, 5156, 10323, 5276, 814 LTC: http://tests.stockfishchess.org/tests/view/5e54e05d84a82b4acd414947 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 175480 W: 23085 L: 22409 D: 129986 Ptnml(0-2): 1264, 16494, 51678, 16910, 1394 closes https://github.com/official-stockfish/Stockfish/pull/2564 Bench: 4923286 --- src/evaluate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 25aba644..06366e09 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -114,11 +114,11 @@ namespace { // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(6, 32), S(59, 41), S(79, 56), S(90, 119), S(79, 161) + S(0, 0), S(5, 32), S(57, 41), S(77, 56), S(88, 119), S(79, 161) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(3, 44), S(38, 71), S(38, 61), S(0, 38), S(51, 38) + S(0, 0), S(2, 44), S(36, 71), S(36, 61), S(0, 38), S(51, 38) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -516,6 +516,9 @@ namespace { b = ~attackedBy[Them][ALL_PIECES] | (nonPawnEnemies & attackedBy2[Us]); score += Hanging * popcount(weak & b); + + // Additional bonus if weak piece is only protected by a queen + score += make_score(14, 0) * popcount(weak & attackedBy[Them][QUEEN]); } // Bonus for restricting their piece moves From f27339d35b6c8ccd1f83914b334c89111e62f320 Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Thu, 27 Feb 2020 15:58:22 +0100 Subject: [PATCH 197/281] Simplify lowply-history logic Don't restrict usage to ttPv nodes exclusively STC: http://tests.stockfishchess.org/tests/view/5e5634f284a82b4acd41499a LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 152796 W: 29146 L: 29178 D: 94472 Ptnml(0-2): 2590, 17792, 35628, 17836, 2552 LTC: http://tests.stockfishchess.org/tests/view/5e575d4984a82b4acd4149e8 LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 20078 W: 2688 L: 2587 D: 14803 Ptnml(0-2): 139, 1914, 5853, 1973, 160 closes https://github.com/official-stockfish/Stockfish/pull/2565 bench: 4923286 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index a32ff4b6..544c3ee5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -957,7 +957,7 @@ moves_loop: // When in check, search starts from here contHist, countermove, ss->killers, - depth > 12 && ttPv ? ss->ply : MAX_PLY); + depth > 12 ? ss->ply : MAX_PLY); value = bestValue; singularLMR = moveCountPruning = false; From c6839a26155c18dbb7700175971fe01c5a67b01c Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 1 Mar 2020 09:31:17 +0100 Subject: [PATCH 198/281] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2546 No functional change. --- src/Makefile | 2 +- src/bitboard.h | 2 +- src/endgame.cpp | 2 +- src/evaluate.cpp | 44 ++++++++++++++++++++++---------------------- src/evaluate.h | 2 -- src/psqt.cpp | 8 -------- src/search.cpp | 10 +++++----- src/types.h | 8 +++++++- 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/Makefile b/src/Makefile index 679eb8d9..15ad6353 100644 --- a/src/Makefile +++ b/src/Makefile @@ -409,7 +409,7 @@ help: @echo "" -.PHONY: help build profile-build strip install clean objclean profileclean help \ +.PHONY: help build profile-build strip install clean objclean profileclean \ config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \ clang-profile-use clang-profile-make diff --git a/src/bitboard.h b/src/bitboard.h index d11b7e73..ca161481 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -154,7 +154,7 @@ inline Bitboard file_bb(Square s) { } -/// shift() moves a bitboard one step along direction D +/// shift() moves a bitboard one or two steps as specified by the direction D template constexpr Bitboard shift(Bitboard b) { diff --git a/src/endgame.cpp b/src/endgame.cpp index 74e16fa6..5fdd307e 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -281,7 +281,7 @@ Value Endgame::operator()(const Position& pos) const { if ( relative_rank(weakSide, pawnSq) != RANK_7 || distance(loserKSq, pawnSq) != 1 - || !((FileABB | FileCBB | FileFBB | FileHBB) & pawnSq)) + || ((FileBBB | FileDBB | FileEBB | FileGBB) & pawnSq)) result += QueenValueEg - PawnValueEg; return strongSide == pos.side_to_move() ? result : -result; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 06366e09..31272f2c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -127,25 +127,26 @@ namespace { }; // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); - constexpr Score CorneredBishop = S( 50, 50); - constexpr Score FlankAttacks = S( 8, 0); - constexpr Score Hanging = S( 69, 36); - constexpr Score KingProtector = S( 7, 8); - constexpr Score KnightOnQueen = S( 16, 12); - constexpr Score LongDiagonalBishop = S( 45, 0); - constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 30, 21); - constexpr Score PassedFile = S( 11, 8); - constexpr Score PawnlessFlank = S( 17, 95); - constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnQueenFile = S( 7, 6); - constexpr Score SliderOnQueen = S( 59, 18); - constexpr Score ThreatByKing = S( 24, 89); - constexpr Score ThreatByPawnPush = S( 48, 39); - constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); - constexpr Score WeakQueen = S( 49, 15); + constexpr Score BishopPawns = S( 3, 7); + constexpr Score CorneredBishop = S( 50, 50); + constexpr Score FlankAttacks = S( 8, 0); + constexpr Score Hanging = S( 69, 36); + constexpr Score KingProtector = S( 7, 8); + constexpr Score KnightOnQueen = S( 16, 12); + constexpr Score LongDiagonalBishop = S( 45, 0); + constexpr Score MinorBehindPawn = S( 18, 3); + constexpr Score Outpost = S( 30, 21); + constexpr Score PassedFile = S( 11, 8); + constexpr Score PawnlessFlank = S( 17, 95); + constexpr Score RestrictedPiece = S( 7, 7); + constexpr Score RookOnQueenFile = S( 7, 6); + constexpr Score SliderOnQueen = S( 59, 18); + constexpr Score ThreatByKing = S( 24, 89); + constexpr Score ThreatByPawnPush = S( 48, 39); + constexpr Score ThreatBySafePawn = S(173, 94); + constexpr Score TrappedRook = S( 52, 10); + constexpr Score WeakQueen = S( 49, 15); + constexpr Score WeakQueenProtection = S( 14, 0); #undef S @@ -518,7 +519,7 @@ namespace { score += Hanging * popcount(weak & b); // Additional bonus if weak piece is only protected by a queen - score += make_score(14, 0) * popcount(weak & attackedBy[Them][QUEEN]); + score += WeakQueenProtection * popcount(weak & attackedBy[Them][QUEEN]); } // Bonus for restricting their piece moves @@ -830,8 +831,7 @@ namespace { Trace::add(TOTAL, score); } - return (pos.side_to_move() == WHITE ? v : -v) // Side to move point of view - + Eval::Tempo; + return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view } } // namespace diff --git a/src/evaluate.h b/src/evaluate.h index 077de70c..7c8a2a6f 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,8 +29,6 @@ class Position; namespace Eval { -constexpr Value Tempo = Value(28); // Must be visible to search - std::string trace(const Position& pos); Value evaluate(const Position& pos); diff --git a/src/psqt.cpp b/src/psqt.cpp index 647bd864..8bad7ed4 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -22,11 +22,6 @@ #include "types.h" -Value PieceValue[PHASE_NB][PIECE_NB] = { - { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg }, - { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } -}; - namespace PSQT { #define S(mg, eg) make_score(mg, eg) @@ -112,9 +107,6 @@ void init() { for (Piece pc = W_PAWN; pc <= W_KING; ++pc) { - PieceValue[MG][~pc] = PieceValue[MG][pc]; - PieceValue[EG][~pc] = PieceValue[EG][pc]; - Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); for (Square s = SQ_A1; s <= SQ_H8; ++s) diff --git a/src/search.cpp b/src/search.cpp index 544c3ee5..7f6abf15 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -819,14 +819,14 @@ namespace { ss->staticEval = eval = evaluate(pos) + bonus; } else - ss->staticEval = eval = -(ss-1)->staticEval + 2 * Eval::Tempo; + ss->staticEval = eval = -(ss-1)->staticEval + 2 * Tempo; tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } // Step 7. Razoring (~1 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch - && depth < 2 + && depth == 1 && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); @@ -1434,13 +1434,13 @@ moves_loop: // When in check, search starts from here else ss->staticEval = bestValue = (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) - : -(ss-1)->staticEval + 2 * Eval::Tempo; + : -(ss-1)->staticEval + 2 * Tempo; // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { if (!ttHit) - tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, BOUND_LOWER, + tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->staticEval); return bestValue; @@ -1667,7 +1667,7 @@ moves_loop: // When in check, search starts from here // update_continuation_histories() updates histories of the move pairs formed - // by moves at ply -1, -2, and -4 with current move. + // by moves at ply -1, -2, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { diff --git a/src/types.h b/src/types.h index 7ab7560a..58d05d2c 100644 --- a/src/types.h +++ b/src/types.h @@ -186,6 +186,7 @@ enum Value : int { BishopValueMg = 825, BishopValueEg = 915, RookValueMg = 1276, RookValueEg = 1380, QueenValueMg = 2538, QueenValueEg = 2682, + Tempo = 28, MidgameLimit = 15258, EndgameLimit = 3915 }; @@ -203,7 +204,12 @@ enum Piece { PIECE_NB = 16 }; -extern Value PieceValue[PHASE_NB][PIECE_NB]; +constexpr Value PieceValue[PHASE_NB][PIECE_NB] = { + { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO, + VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg, VALUE_ZERO, VALUE_ZERO }, + { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO, + VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg, VALUE_ZERO, VALUE_ZERO } +}; typedef int Depth; From 960d59d54143d84aab26deae65279a611fc989f4 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 1 Mar 2020 02:03:36 -0700 Subject: [PATCH 199/281] Consolidate Square Flipping Add a flip_rank() and flip_file() so that all of the square flipping can be consolidated. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 57234 W: 11064 L: 10969 D: 35201 Ptnml(0-2): 822, 6562, 13801, 6563, 869 http://tests.stockfishchess.org/tests/view/5e5d2f2aafe6254521f2ffaa closes https://github.com/official-stockfish/Stockfish/pull/2568 No functional change. --- src/endgame.cpp | 4 ++-- src/psqt.cpp | 2 +- src/syzygy/tbprobe.cpp | 7 +++---- src/types.h | 8 ++++++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 5fdd307e..16c072be 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -74,9 +74,9 @@ namespace { assert(pos.count(strongSide) == 1); if (file_of(pos.square(strongSide)) >= FILE_E) - sq = Square(int(sq) ^ 7); // Mirror SQ_H1 -> SQ_A1 + sq = flip_file(sq); - return strongSide == WHITE ? sq : ~sq; + return strongSide == WHITE ? sq : flip_rank(sq); } } // namespace diff --git a/src/psqt.cpp b/src/psqt.cpp index 8bad7ed4..f6f5933c 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -114,7 +114,7 @@ void init() { File f = map_to_queenside(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); - psq[~pc][~s] = -psq[pc][s]; + psq[~pc][flip_rank(s)] = -psq[pc][s]; } } } diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 721a0ef5..6f369455 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -66,7 +66,6 @@ enum TBType { KEY, WDL, DTZ }; // Used as template parameter enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 }; inline WDLScore operator-(WDLScore d) { return WDLScore(-int(d)); } -inline Square operator^=(Square& s, int i) { return s = Square(int(s) ^ i); } inline Square operator^(Square s, int i) { return Square(int(s) ^ i); } const std::string PieceToChar = " PNBRQK pnbrqk"; @@ -743,7 +742,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // the triangle A1-D1-D4. if (file_of(squares[0]) > FILE_D) for (int i = 0; i < size; ++i) - squares[i] ^= 7; // Horizontal flip: SQ_H1 -> SQ_A1 + squares[i] = flip_file(squares[i]); // Encode leading pawns starting with the one with minimum MapPawns[] and // proceeding in ascending order. @@ -762,7 +761,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // piece is below RANK_5. if (rank_of(squares[0]) > RANK_4) for (int i = 0; i < size; ++i) - squares[i] ^= SQ_A8; // Vertical flip: SQ_A8 -> SQ_A1 + squares[i] = flip_rank(squares[i]); // Look for the first piece of the leading group not on the A1-D4 diagonal // and ensure it is mapped below the diagonal. @@ -1344,7 +1343,7 @@ void Tablebases::init(const std::string& paths) { if (leadPawnsCnt == 1) { MapPawns[sq] = availableSquares--; - MapPawns[sq ^ 7] = availableSquares--; // Horizontal flip + MapPawns[flip_file(sq)] = availableSquares--; } LeadPawnIdx[leadPawnsCnt][sq] = idx; idx += Binomial[leadPawnsCnt - 1][MapPawns[sq]]; diff --git a/src/types.h b/src/types.h index 58d05d2c..d4937fd6 100644 --- a/src/types.h +++ b/src/types.h @@ -358,8 +358,12 @@ constexpr Color operator~(Color c) { return Color(c ^ BLACK); // Toggle color } -constexpr Square operator~(Square s) { - return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 +constexpr Square flip_rank(Square s) { + return Square(s ^ SQ_A8); +} + +constexpr Square flip_file(Square s) { + return Square(s ^ SQ_H1); } constexpr Piece operator~(Piece pc) { From 5a7b45eac9dedbf7ebc61d9deb4dd934058d1ca1 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 2 Mar 2020 17:32:02 -0700 Subject: [PATCH 200/281] Use equations for PushAway and PushClose A functional simplification replacing the corresponding arrays. Tested in two variants, also the simpler one performs well, even though differences to master should be minimal. STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 57864 W: 11092 L: 11001 D: 35771 Ptnml(0-2): 826, 6458, 14320, 6455, 873 http://tests.stockfishchess.org/tests/view/5e5da5b6e42a5c3b3ca2e05c LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 7198 W: 982 L: 883 D: 5333 Ptnml(0-2): 33, 575, 2296, 650, 45 http://tests.stockfishchess.org/tests/view/5e5df13ae42a5c3b3ca2e077 LTC (This exact version. . . more simplified) LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 5392 W: 729 L: 631 D: 4032 Ptnml(0-2): 23, 405, 1751, 485, 32 http://tests.stockfishchess.org/tests/view/5e5ead99e42a5c3b3ca2e0e4 closes https://github.com/official-stockfish/Stockfish/pull/2570 Bench 5123316 --- src/endgame.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 16c072be..73a44633 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -54,9 +54,9 @@ namespace { 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 }; - // Tables used to drive a piece towards or away from another piece - constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; - constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; + // Drive a piece close to or away from another piece + inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } + inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); } // Pawn Rank based scaling factors used in KRPPKRP endgame constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; @@ -130,7 +130,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg + PushToEdges[loserKSq] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) || pos.count(strongSide) @@ -159,7 +159,7 @@ Value Endgame::operator()(const Position& pos) const { // to drive to opposite corners (A8/H1). Value result = VALUE_KNOWN_WIN - + PushClose[distance(winnerKSq, loserKSq)] + + push_close(winnerKSq, loserKSq) + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); @@ -258,7 +258,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[bksq] + PushAway[distance(bksq, bnsq)]); + Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -277,7 +277,7 @@ Value Endgame::operator()(const Position& pos) const { Square loserKSq = pos.square(weakSide); Square pawnSq = pos.square(weakSide); - Value result = Value(PushClose[distance(winnerKSq, loserKSq)]); + Value result = Value(push_close(winnerKSq, loserKSq)); if ( relative_rank(weakSide, pawnSq) != RANK_7 || distance(loserKSq, pawnSq) != 1 @@ -304,7 +304,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg + PushToEdges[loserKSq] - + PushClose[distance(winnerKSq, loserKSq)]; + + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; } From 0424273d0b20ae7ad65143b530b2db8b94de0338 Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 3 Mar 2020 16:35:45 -0700 Subject: [PATCH 201/281] Small speed-up in BetweenBB A speed-up removing some comparisons. closes https://github.com/official-stockfish/Stockfish/pull/2571 No functional change. --- src/bitboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index ca161481..b0e27233 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -199,8 +199,8 @@ inline Bitboard adjacent_files_bb(Square s) { /// If the given squares are not on a same file/rank/diagonal, return 0. inline Bitboard between_bb(Square s1, Square s2) { - return LineBB[s1][s2] & ( (AllSquares << (s1 + (s1 < s2))) - ^(AllSquares << (s2 + !(s1 < s2)))); + Bitboard b = LineBB[s1][s2] & ((AllSquares << s1) ^ (AllSquares << s2)); + return b & (b - 1); //exclude lsb } From e7c1c8c1abd85a71fd8190e0c1af49214625904b Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 5 Mar 2020 12:07:48 -0700 Subject: [PATCH 202/281] Cleanup KBPsK endgame * Clarify distinction between strong side pawns and all pawns. * Simplify and speed-up determination of pawns on the same file. * Clarify comments. * more_than_one() is probably faster than pos.count. Passed STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 40696 W: 7856 L: 7740 D: 25100 Ptnml(0-2): 584, 4519, 10054, 4579, 612 http://tests.stockfishchess.org/tests/view/5e6153b1e42a5c3b3ca2e1a9 closes https://github.com/official-stockfish/Stockfish/pull/2574 No functional change. --- src/endgame.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 73a44633..748b05ff 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -343,29 +343,27 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // No assertions about the material of weakSide, because we want draws to // be detected even when the weaker side has some pawns. - Bitboard pawns = pos.pieces(strongSide, PAWN); - File pawnsFile = file_of(lsb(pawns)); + Bitboard strongpawns = pos.pieces(strongSide, PAWN); + Bitboard allpawns = pos.pieces(PAWN); - // All pawns are on a single rook file? - if ( (pawnsFile == FILE_A || pawnsFile == FILE_H) - && !(pawns & ~file_bb(pawnsFile))) + // All strongSide pawns are on a single rook file? + if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB)) { Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(pawnsFile, RANK_8)); - Square kingSq = pos.square(weakSide); + Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8)); + Square weakkingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, kingSq) <= 1) + && distance(queeningSq, weakkingSq) <= 1) return SCALE_FACTOR_DRAW; } // If all the pawns are on the same B or G file, then it's potentially a draw - if ( (pawnsFile == FILE_B || pawnsFile == FILE_G) - && !(pos.pieces(PAWN) & ~file_bb(pawnsFile)) + if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { - // Get weakSide pawn that is closest to the home rank + // Get the least advanced weakSide pawn Square weakPawnSq = frontmost_sq(strongSide, pos.pieces(weakSide, PAWN)); Square strongKingSq = pos.square(strongSide); @@ -375,8 +373,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left if ( relative_rank(strongSide, weakPawnSq) == RANK_7 - && (pos.pieces(strongSide, PAWN) & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || pos.count(strongSide) == 1)) + && (strongpawns & (weakPawnSq + pawn_push(weakSide))) + && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns))) { int strongKingDist = distance(weakPawnSq, strongKingSq); int weakKingDist = distance(weakPawnSq, weakKingSq); From 9690cd6295fbed93ee434e7b2e16181e475755ac Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 4 Mar 2020 11:32:17 -0700 Subject: [PATCH 203/281] Remove KRPPKRPScaleFactors array Fucntional simplification that removes the KRPPKRPScaleFactors array. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 47374 W: 9159 L: 9049 D: 29166 Ptnml(0-2): 707, 5325, 11560, 5341, 754 http://tests.stockfishchess.org/tests/view/5e5ff464e42a5c3b3ca2e156 LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 31268 W: 4064 L: 3995 D: 23209 Ptnml(0-2): 173, 2734, 9764, 2777, 186 http://tests.stockfishchess.org/tests/view/5e61be6ce42a5c3b3ca2e1c1 closes https://github.com/official-stockfish/Stockfish/pull/2575 Bench 5123316 --- src/endgame.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 748b05ff..53c9ec83 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -58,9 +58,6 @@ namespace { inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } inline int push_away(Square s1, Square s2) { return 120 - push_close(s1, s2); } - // Pawn Rank based scaling factors used in KRPPKRP endgame - constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; - #ifndef NDEBUG bool verify_material(const Position& pos, Color c, Value npm, int pawnsCnt) { return pos.non_pawn_material(c) == npm && pos.count(c) == pawnsCnt; @@ -587,7 +584,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && relative_rank(strongSide, bksq) > r) { assert(r > RANK_1 && r < RANK_7); - return ScaleFactor(KRPPKRPScaleFactors[r]); + return ScaleFactor(7 * r); } return SCALE_FACTOR_NONE; } From 37e38639279bf58558b92932739da57e7c2e3bdc Mon Sep 17 00:00:00 2001 From: Gary Heckman Date: Thu, 5 Mar 2020 12:37:08 -0500 Subject: [PATCH 204/281] Fix ambiguity between clamp implementations There is an ambiguity between global and std clamp implementations when compiling in c++17, and on certain toolchains that are not strictly conforming to c++11. This is solved by putting our clamp implementation in a namespace. closes https://github.com/official-stockfish/Stockfish/pull/2572 No functional change. --- AUTHORS | 1 + src/bitboard.h | 3 --- src/evaluate.cpp | 4 ++-- src/material.cpp | 2 +- src/misc.h | 8 ++++++++ src/pawns.cpp | 2 +- src/search.cpp | 6 +++--- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index a9f141f9..7657acee 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,7 @@ fanon Fauzi Akram Dabat (FauziAkram) Felix Wittmann gamander +Gary Heckman (gheckman) gguliash Gian-Carlo Pascutto (gcp) Gontran Lemaire (gonlem) diff --git a/src/bitboard.h b/src/bitboard.h index b0e27233..3ea18dd8 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -255,9 +255,6 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } -template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { - return v < lo ? lo : v > hi ? hi : v; -} /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 31272f2c..5d073b15 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -236,8 +236,8 @@ namespace { attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); // Init our king safety tables - Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G), - clamp(rank_of(ksq), RANK_2, RANK_7)); + Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G), + Utility::clamp(rank_of(ksq), RANK_2, RANK_7)); kingRing[Us] = PseudoAttacks[KING][s] | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); diff --git a/src/material.cpp b/src/material.cpp index 0e130878..7e212461 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -129,7 +129,7 @@ Entry* probe(const Position& pos) { Value npm_w = pos.non_pawn_material(WHITE); Value npm_b = pos.non_pawn_material(BLACK); - Value npm = clamp(npm_w + npm_b, EndgameLimit, MidgameLimit); + Value npm = Utility::clamp(npm_w + npm_b, EndgameLimit, MidgameLimit); // Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME] e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit)); diff --git a/src/misc.h b/src/misc.h index a3780ba5..e0e0e98b 100644 --- a/src/misc.h +++ b/src/misc.h @@ -64,6 +64,14 @@ std::ostream& operator<<(std::ostream&, SyncCout); #define sync_cout std::cout << IO_LOCK #define sync_endl std::endl << IO_UNLOCK +namespace Utility { + +/// Clamp a value between lo and hi. Available in c++17. +template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { + return v < lo ? lo : v > hi ? hi : v; +} + +} /// xorshift64star Pseudo-Random Number Generator /// This class is based on original code written and dedicated diff --git a/src/pawns.cpp b/src/pawns.cpp index c3f7872f..9981ac01 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -193,7 +193,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { Score bonus = make_score(5, 5); - File center = clamp(file_of(ksq), FILE_B, FILE_G); + File center = Utility::clamp(file_of(ksq), FILE_B, FILE_G); for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); diff --git a/src/search.cpp b/src/search.cpp index 7f6abf15..3d130efc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -365,7 +365,7 @@ void Thread::search() { // for match (TC 60+0.6) results spanning a wide range of k values. PRNG rng(now()); double floatLevel = Options["UCI_LimitStrength"] ? - clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : + Utility::clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : double(Options["Skill Level"]); int intLevel = int(floatLevel) + ((floatLevel - int(floatLevel)) * 1024 > rng.rand() % 1024 ? 1 : 0); @@ -538,7 +538,7 @@ void Thread::search() { { double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue) + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; - fallingEval = clamp(fallingEval, 0.5, 1.5); + fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.94 : 0.91; @@ -1197,7 +1197,7 @@ moves_loop: // When in check, search starts from here else if (depth < 8 && moveCount > 2) r++; - Depth d = clamp(newDepth - r, 1, newDepth); + Depth d = Utility::clamp(newDepth - r, 1, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); From 47be966d3028ca9b5c4d095f266663eb205c0c07 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 9 Mar 2020 22:11:08 +0100 Subject: [PATCH 205/281] Equations for edges and corners. This is a functional simplification that removes the large arrays in endgames.cpp. It also fixes a recently introduced bug (960d59d54143d84aab26deae65279a611fc989f4) in KNBvK, now using flip_file() instead of ~. One fen added to bench to increase endgame coverage. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 174724 W: 33325 L: 33404 D: 107995 Ptnml(0-2): 2503, 19607, 43181, 19608, 2463 http://tests.stockfishchess.org/tests/view/5e6448ffe42a5c3b3ca2e287 LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 35640 W: 4679 L: 4621 D: 26340 Ptnml(0-2): 189, 2991, 11424, 3005, 211 http://tests.stockfishchess.org/tests/view/5e650b24e42a5c3b3ca2e2d8 closes https://github.com/official-stockfish/Stockfish/pull/2577 Bench: 5527957 --- src/benchmark.cpp | 1 + src/bitboard.h | 2 ++ src/endgame.cpp | 46 +++++++++++++++--------------------------- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- src/psqt.cpp | 3 ++- src/syzygy/tbprobe.cpp | 2 +- src/types.h | 4 ---- 8 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index f906e731..f338cdda 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -65,6 +65,7 @@ const vector Defaults = { "4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21", "r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16", "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40", + "4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1", // 5-man positions "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate diff --git a/src/bitboard.h b/src/bitboard.h index 3ea18dd8..f1d14603 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -255,6 +255,8 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } +inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); } +inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/endgame.cpp b/src/endgame.cpp index 53c9ec83..0a2b02ad 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -28,31 +28,17 @@ using std::string; namespace { - // Table used to drive the king towards the edge of the board + // Used to drive the king towards the edge of the board // in KX vs K and KQ vs KR endgames. - constexpr int PushToEdges[SQUARE_NB] = { - 100, 90, 80, 70, 70, 80, 90, 100, - 90, 70, 60, 50, 50, 60, 70, 90, - 80, 60, 40, 30, 30, 40, 60, 80, - 70, 50, 30, 20, 20, 30, 50, 70, - 70, 50, 30, 20, 20, 30, 50, 70, - 80, 60, 40, 30, 30, 40, 60, 80, - 90, 70, 60, 50, 50, 60, 70, 90, - 100, 90, 80, 70, 70, 80, 90, 100 - }; + inline int push_to_edge(Square s) { + int rd = edge_distance(rank_of(s)), fd = edge_distance(file_of(s)); + return 90 - (7 * fd * fd / 2 + 7 * rd * rd / 2); + } - // Table used to drive the king towards a corner square of the - // right color in KBN vs K endgames. - constexpr int PushToCorners[SQUARE_NB] = { - 6400, 6080, 5760, 5440, 5120, 4800, 4480, 4160, - 6080, 5760, 5440, 5120, 4800, 4480, 4160, 4480, - 5760, 5440, 4960, 4480, 4480, 4000, 4480, 4800, - 5440, 5120, 4480, 3840, 3520, 4480, 4800, 5120, - 5120, 4800, 4480, 3520, 3840, 4480, 5120, 5440, - 4800, 4480, 4000, 4480, 4480, 4960, 5440, 5760, - 4480, 4160, 4480, 4800, 5120, 5440, 5760, 6080, - 4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400 - }; + // Used to drive the king towards A1H8 corners in KBN vs K endgames. + inline int push_to_corner(Square s) { + return abs(7 - rank_of(s) - file_of(s)); + } // Drive a piece close to or away from another piece inline int push_close(Square s1, Square s2) { return 140 - 20 * distance(s1, s2); } @@ -126,7 +112,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = pos.non_pawn_material(strongSide) + pos.count(strongSide) * PawnValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); if ( pos.count(strongSide) @@ -155,9 +141,9 @@ Value Endgame::operator()(const Position& pos) const { // If our bishop does not attack A1/H8, we flip the enemy king square // to drive to opposite corners (A8/H1). - Value result = VALUE_KNOWN_WIN + Value result = (VALUE_KNOWN_WIN + 3520) + push_close(winnerKSq, loserKSq) - + PushToCorners[opposite_colors(bishopSq, SQ_A1) ? ~loserKSq : loserKSq]; + + 420 * push_to_corner(opposite_colors(bishopSq, SQ_A1) ? flip_file(loserKSq) : loserKSq); assert(abs(result) < VALUE_TB_WIN_IN_MAX_PLY); return strongSide == pos.side_to_move() ? result : -result; @@ -240,7 +226,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, strongSide, RookValueMg, 0)); assert(verify_material(pos, weakSide, BishopValueMg, 0)); - Value result = Value(PushToEdges[pos.square(weakSide)]); + Value result = Value(push_to_edge(pos.square(weakSide))); return strongSide == pos.side_to_move() ? result : -result; } @@ -255,7 +241,7 @@ Value Endgame::operator()(const Position& pos) const { Square bksq = pos.square(weakSide); Square bnsq = pos.square(weakSide); - Value result = Value(PushToEdges[bksq] + push_away(bksq, bnsq)); + Value result = Value(push_to_edge(bksq) + push_away(bksq, bnsq)); return strongSide == pos.side_to_move() ? result : -result; } @@ -300,7 +286,7 @@ Value Endgame::operator()(const Position& pos) const { Value result = QueenValueEg - RookValueEg - + PushToEdges[loserKSq] + + push_to_edge(loserKSq) + push_close(winnerKSq, loserKSq); return strongSide == pos.side_to_move() ? result : -result; @@ -316,7 +302,7 @@ Value Endgame::operator()(const Position& pos) const { assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); Value result = PawnValueEg - + 2 * PushToEdges[pos.square(weakSide)] + + 2 * push_to_edge(pos.square(weakSide)) - 10 * relative_rank(weakSide, pos.square(weakSide)); return strongSide == pos.side_to_move() ? result : -result; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 5d073b15..40630d22 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -643,7 +643,7 @@ namespace { || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * map_to_queenside(file_of(s)); + score += bonus - PassedFile * edge_distance(file_of(s)); } if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index 9981ac01..560fd76b 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -202,7 +202,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = map_to_queenside(f); + File d = edge_distance(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index f6f5933c..d86e98e4 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -21,6 +21,7 @@ #include #include "types.h" +#include "bitboard.h" namespace PSQT { @@ -111,7 +112,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = map_to_queenside(file_of(s)); + File f = edge_distance(file_of(s)); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][flip_rank(s)] = -psq[pc][s]; diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 6f369455..2532bbd3 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -705,7 +705,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp)); - tbFile = map_to_queenside(file_of(squares[0])); + tbFile = edge_distance(file_of(squares[0])); } // DTZ tables are one-sided, i.e. they store positions only for white to diff --git a/src/types.h b/src/types.h index d4937fd6..71893c0f 100644 --- a/src/types.h +++ b/src/types.h @@ -370,10 +370,6 @@ constexpr Piece operator~(Piece pc) { return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT } -inline File map_to_queenside(File f) { - return std::min(f, File(FILE_H - f)); // Map files ABCDEFGH to files ABCDDCBA -} - constexpr CastlingRights operator&(Color c, CastlingRights cr) { return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } From c077bfb413fbed8d6fa94459135ca81f9977c2f2 Mon Sep 17 00:00:00 2001 From: silversolver1 <61594747+silversolver1@users.noreply.github.com> Date: Sun, 8 Mar 2020 14:52:05 -0500 Subject: [PATCH 206/281] Remove set statScore to zero Simplification. Removes setting statScore to zero if negative. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 84820 W: 16100 L: 16033 D: 52687 Ptnml(0-2): 1442, 9865, 19723, 9944, 1436 https://tests.stockfishchess.org/tests/view/5e654fdae42a5c3b3ca2e2f8 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 57658 W: 7435 L: 7391 D: 42832 Ptnml(0-2): 441, 5397, 17104, 5451, 436 https://tests.stockfishchess.org/tests/view/5e657ce9e42a5c3b3ca2e307 closes https://github.com/official-stockfish/Stockfish/pull/2578 Bench: 5168890 --- AUTHORS | 5 +---- src/search.cpp | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7657acee..4826d1c4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -123,6 +123,7 @@ Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) pellanda Peter Zsifkovits (CoffeeOne) +Rahul Dsilva (silversolver1) Ralph Stößer (Ralph Stoesser) Raminder Singh renouve @@ -158,7 +159,3 @@ Vince Negri (cuddlestmonkey) # an amazing and essential framework for the development of Stockfish! # # https://github.com/glinscott/fishtest/blob/master/AUTHORS - - - - diff --git a/src/search.cpp b/src/search.cpp index 3d130efc..f9910fb7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1175,13 +1175,6 @@ moves_loop: // When in check, search starts from here + (*contHist[3])[movedPiece][to_sq(move)] - 4926; - // Reset statScore to zero if negative and most stats shows >= 0 - if ( ss->statScore < 0 - && (*contHist[0])[movedPiece][to_sq(move)] >= 0 - && (*contHist[1])[movedPiece][to_sq(move)] >= 0 - && thisThread->mainHistory[us][from_to(move)] >= 0) - ss->statScore = 0; - // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) if (ss->statScore >= -102 && (ss-1)->statScore < -114) r--; From 442e1e0f9348226986e568bd52e1b909ec347218 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 11 Mar 2020 16:27:51 -0600 Subject: [PATCH 207/281] simplify castling part of generate_all. somewhat more compact, generates same code. close https://github.com/official-stockfish/Stockfish/pull/2580 No functional change. --- src/movegen.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 7e8961ae..9964ad34 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -214,9 +214,6 @@ namespace { template ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { - - constexpr CastlingRights OO = Us & KING_SIDE; - constexpr CastlingRights OOO = Us & QUEEN_SIDE; constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); @@ -232,14 +229,10 @@ namespace { while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); - if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) - { - if (!pos.castling_impeded(OO) && pos.can_castle(OO)) - *moveList++ = make(ksq, pos.castling_rook_square(OO)); - - if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) - *moveList++ = make(ksq, pos.castling_rook_square(OOO)); - } + if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) + for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) + if (!pos.castling_impeded(cr) && pos.can_castle(cr)) + *moveList++ = make(ksq, pos.castling_rook_square(cr)); } return moveList; From ec2002c594cce22dfbbdc7b6b8df2828a00d18cf Mon Sep 17 00:00:00 2001 From: pb00067 Date: Fri, 13 Mar 2020 19:29:36 +0100 Subject: [PATCH 208/281] Simplify futility pruning parent node only continuation histories seem needed for this purpose. STC: http://tests.stockfishchess.org/tests/view/5e6b88dfe42a5c3b3ca2e4ab LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 113356 W: 21725 L: 21696 D: 69935 Ptnml(0-2): 1999, 13255, 26163, 13240, 2021 LTC: http://tests.stockfishchess.org/tests/view/5e6babbfe42a5c3b3ca2e4c2 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 22164 W: 2917 L: 2821 D: 16426 Ptnml(0-2): 173, 2040, 6548, 2160, 161 closes https://github.com/official-stockfish/Stockfish/pull/2583 bench: 4839496 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f9910fb7..70520ac9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1024,10 +1024,9 @@ moves_loop: // When in check, search starts from here if ( lmrDepth < 6 && !inCheck && ss->staticEval + 235 + 172 * lmrDepth <= alpha - && thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] + && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < 25000) + + (*contHist[3])[movedPiece][to_sq(move)] < 27400) continue; // Prune moves with negative SEE (~20 Elo) From ddcbacd04d1c860e808202ce8c1206c8acdca627 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 14 Mar 2020 17:04:50 +0100 Subject: [PATCH 209/281] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2567 No functional change. --- src/bitboard.h | 5 ++++- src/endgame.cpp | 31 +++++++++++++------------------ src/position.cpp | 5 +---- src/search.cpp | 10 ++++++++-- src/syzygy/tbprobe.cpp | 2 +- src/tt.h | 2 +- src/types.h | 2 +- src/uci.cpp | 2 +- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index f1d14603..529e3dfe 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -375,14 +375,17 @@ inline Square msb(Bitboard b) { /// pop_lsb() finds and clears the least significant bit in a non-zero bitboard inline Square pop_lsb(Bitboard* b) { + assert(*b); const Square s = lsb(*b); *b &= *b - 1; return s; } -/// frontmost_sq() returns the most advanced square for the given color +/// frontmost_sq() returns the most advanced square for the given color, +/// requires a non-zero bitboard. inline Square frontmost_sq(Color c, Bitboard b) { + assert(b); return c == WHITE ? msb(b) : lsb(b); } diff --git a/src/endgame.cpp b/src/endgame.cpp index 0a2b02ad..56583c58 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -24,8 +24,6 @@ #include "endgame.h" #include "movegen.h" -using std::string; - namespace { // Used to drive the king towards the edge of the board @@ -326,23 +324,23 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // No assertions about the material of weakSide, because we want draws to // be detected even when the weaker side has some pawns. - Bitboard strongpawns = pos.pieces(strongSide, PAWN); - Bitboard allpawns = pos.pieces(PAWN); + Bitboard strongPawns = pos.pieces(strongSide, PAWN); + Bitboard allPawns = pos.pieces(PAWN); // All strongSide pawns are on a single rook file? - if (!(strongpawns & ~FileABB) || !(strongpawns & ~FileHBB)) + if (!(strongPawns & ~FileABB) || !(strongPawns & ~FileHBB)) { Square bishopSq = pos.square(strongSide); - Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongpawns)), RANK_8)); - Square weakkingSq = pos.square(weakSide); + Square queeningSq = relative_square(strongSide, make_square(file_of(lsb(strongPawns)), RANK_8)); + Square weakKingSq = pos.square(weakSide); if ( opposite_colors(queeningSq, bishopSq) - && distance(queeningSq, weakkingSq) <= 1) + && distance(queeningSq, weakKingSq) <= 1) return SCALE_FACTOR_DRAW; } // If all the pawns are on the same B or G file, then it's potentially a draw - if ((!(allpawns & ~FileBBB) || !(allpawns & ~FileGBB)) + if ((!(allPawns & ~FileBBB) || !(allPawns & ~FileGBB)) && pos.non_pawn_material(weakSide) == 0 && pos.count(weakSide) >= 1) { @@ -356,8 +354,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // There's potential for a draw if our pawn is blocked on the 7th rank, // the bishop cannot attack it or they only have one pawn left if ( relative_rank(strongSide, weakPawnSq) == RANK_7 - && (strongpawns & (weakPawnSq + pawn_push(weakSide))) - && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongpawns))) + && (strongPawns & (weakPawnSq + pawn_push(weakSide))) + && (opposite_colors(bishopSq, weakPawnSq) || !more_than_one(strongPawns))) { int strongKingDist = distance(weakPawnSq, strongKingSq); int weakKingDist = distance(weakPawnSq, weakKingSq); @@ -588,11 +586,9 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square ksq = pos.square(weakSide); Bitboard pawns = pos.pieces(strongSide, PAWN); - // If all pawns are ahead of the king, on a single rook file and - // the king is within one file of the pawns, it's a draw. - if ( !(pawns & ~forward_ranks_bb(weakSide, ksq)) - && !((pawns & ~FileABB) && (pawns & ~FileHBB)) - && distance(ksq, lsb(pawns)) <= 1) + // If all pawns are ahead of the king on a single rook file, it's a draw. + if (!((pawns & ~FileABB) || (pawns & ~FileHBB)) && + !(pawns & ~passed_pawn_span(weakSide, ksq))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -615,8 +611,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square weakKingSq = pos.square(weakSide); // Case 1: Defending king blocks the pawn, and cannot be driven away - if ( file_of(weakKingSq) == file_of(pawnSq) - && relative_rank(strongSide, pawnSq) < relative_rank(strongSide, weakKingSq) + if ( (forward_file_bb(strongSide, pawnSq) & weakKingSq) && ( opposite_colors(weakKingSq, strongBishopSq) || relative_rank(strongSide, weakKingSq) <= RANK_6)) return SCALE_FACTOR_DRAW; diff --git a/src/position.cpp b/src/position.cpp index 0ac45057..fefce56e 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1121,10 +1121,7 @@ bool Position::is_draw(int ply) const { // Return a draw score if a position repeats once earlier but strictly // after the root, or repeats twice before or at the root. - if (st->repetition && st->repetition < ply) - return true; - - return false; + return st->repetition && st->repetition < ply; } diff --git a/src/search.cpp b/src/search.cpp index 70520ac9..a54e181a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1193,10 +1193,16 @@ moves_loop: // When in check, search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && d != newDepth), didLMR = true; + doFullDepthSearch = value > alpha && d != newDepth; + + didLMR = true; } else - doFullDepthSearch = !PvNode || moveCount > 1, didLMR = false; + { + doFullDepthSearch = !PvNode || moveCount > 1; + + didLMR = false; + } // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 2532bbd3..34e4331d 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -769,7 +769,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu if (!off_A1H8(squares[i])) continue; - if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C3 + if (off_A1H8(squares[i]) > 0) // A1-H8 diagonal flip: SQ_A3 -> SQ_C1 for (int j = i; j < size; ++j) squares[j] = Square(((squares[j] >> 3) | (squares[j] << 3)) & 63); break; diff --git a/src/tt.h b/src/tt.h index 142afd90..8b70f797 100644 --- a/src/tt.h +++ b/src/tt.h @@ -41,7 +41,7 @@ struct TTEntry { Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } Depth depth() const { return (Depth)depth8 + DEPTH_OFFSET; } - bool is_pv() const { return (bool)(genBound8 & 0x4); } + bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --git a/src/types.h b/src/types.h index 71893c0f..bfcd3f23 100644 --- a/src/types.h +++ b/src/types.h @@ -220,7 +220,7 @@ enum : int { DEPTH_QS_RECAPTURES = -5, DEPTH_NONE = -6, - DEPTH_OFFSET = DEPTH_NONE, + DEPTH_OFFSET = DEPTH_NONE }; enum Square : int { diff --git a/src/uci.cpp b/src/uci.cpp index 8b35e6fd..33577a4e 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -260,7 +260,7 @@ string UCI::value(Value v) { stringstream ss; - if (abs(v) < VALUE_MATE - MAX_PLY) + if (abs(v) < VALUE_MATE_IN_MAX_PLY) ss << "cp " << v * 100 / PawnValueEg; else ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; From 07caca2587d3090921b99f37fa8c9bf6a29a89af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Tue, 17 Mar 2020 08:26:27 +0100 Subject: [PATCH 210/281] Anchored bishops Reduce the "bad bishop" penalty when the bishop is protected by one of our pawns, as it may indicate that the bishop has found a safe spot outside the pawn chain. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 176942 W: 34142 L: 33696 D: 109104 Ptnml(0-2): 3129, 20422, 40919, 20876, 3125 http://tests.stockfishchess.org/tests/view/5e6f61aae42a5c3b3ca2e62d LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 42252 W: 5615 L: 5322 D: 31315 Ptnml(0-2): 308, 3881, 12500, 4084, 353 http://tests.stockfishchess.org/tests/view/5e701382e42a5c3b3ca2e661 closes https://github.com/official-stockfish/Stockfish/pull/2587 Bench: 4963440 --- src/evaluate.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 40630d22..fad2a785 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -308,11 +308,12 @@ namespace { if (Pt == BISHOP) { // Penalty according to number of pawns on the same color square as the - // bishop, bigger when the center files are blocked with pawns. + // bishop, bigger when the center files are blocked with pawns and smaller + // when the bishop is outside the pawn chain. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) - * (1 + popcount(blocked & CenterFiles)); + * (!bool(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) From ff271093139de92ebf4f4f8b8c67474e07d6a8bf Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 17 Mar 2020 19:38:21 +0300 Subject: [PATCH 211/281] Adjust singular LMR for positions seen in PV This patch continues work on altering search for ttPv nodes, using recent idea to alter it more in not PvNodes. Previous tweak based on this idea adjusted singularBeta - this one adjusts value of singularLMR, so they are both related to singular extension search. passed STC http://tests.stockfishchess.org/tests/view/5e700737e42a5c3b3ca2e659 LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 140608 W: 27053 L: 26659 D: 86896 Ptnml(0-2): 2425, 16337, 32439, 16625, 2478 passed LTC http://tests.stockfishchess.org/tests/view/5e7068eae42a5c3b3ca2e687 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 79318 W: 10463 L: 10064 D: 58791 Ptnml(0-2): 567, 7416, 23359, 7685, 632 closes https://github.com/official-stockfish/Stockfish/pull/2588 Bench: 4952322 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index a54e181a..fe57806c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1149,7 +1149,7 @@ moves_loop: // When in check, search starts from here // Decrease reduction if ttMove has been singularly extended (~3 Elo) if (singularLMR) - r -= 2; + r -= 1 + (ttPv && !PvNode); if (!captureOrPromotion) { From 6ecab03dee15fe30bc0237919180a2e51e0ce4b1 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 20 Mar 2020 12:12:56 +0300 Subject: [PATCH 212/281] Adjust singular extension search depth This patch applies a different singular extension search logic in case the position is ttPv && !PvNode. It changes the depth of this search, higher for this types of nodes, and lower for other nodes. passed STC http://tests.stockfishchess.org/tests/view/5e72bbaae42a5c3b3ca2e75e LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 12692 W: 2608 L: 2389 D: 7695 Ptnml(0-2): 238, 1414, 2839, 1601, 254 passed LTC http://tests.stockfishchess.org/tests/view/5e731c07e42a5c3b3ca2e770 LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 145716 W: 19218 L: 18626 D: 107872 Ptnml(0-2): 1100, 13605, 42899, 14111, 1143 closes https://github.com/official-stockfish/Stockfish/pull/2590 Bench: 5398277 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index fe57806c..abc6874e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1055,9 +1055,9 @@ moves_loop: // When in check, search starts from here && pos.legal(move)) { Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; - Depth halfDepth = depth / 2; + Depth singularDepth = (depth - 1 + 3 * (ttPv && !PvNode)) / 2; ss->excludedMove = move; - value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); + value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); ss->excludedMove = MOVE_NONE; if (value < singularBeta) From 8b229381daa9c2537dc9a8cf5080a3a282265d0a Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 22 Mar 2020 22:21:49 -0600 Subject: [PATCH 213/281] Remove KNPKB endgame. This is a functional simplification that removes the KNPKB endgame. Testing on only KNPKB positions suggests that this removal actually gains Elo: Score of patch vs master: 3380 - 3035 - 33585 [0.504] 40000 Elo difference: 3.0 +/- 1.4, LOS: 100.0 %, DrawRatio: 84.0 % Score of patch vs master: 290 - 36 - 39674 [0.503] 40000 Elo difference: 2.2 +/- 0.3, LOS: 100.0 %, DrawRatio: 99.2 % removal also doesn't cause a regression with the standard book: STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 71376 W: 13794 L: 13719 D: 43863 Ptnml(0-2): 1066, 8092, 17290, 8181, 1059 https://tests.stockfishchess.org/tests/view/5e76c3d5e42a5c3b3ca2e8be LTC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 28394 W: 3731 L: 3662 D: 21001 Ptnml(0-2): 167, 2339, 9116, 2408, 167 https://tests.stockfishchess.org/tests/view/5e76e5eae42a5c3b3ca2e8d3 closes https://github.com/official-stockfish/Stockfish/pull/2594 Bench 5480811 --- src/endgame.cpp | 22 ---------------------- src/endgame.h | 1 - 2 files changed, 23 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 56583c58..1a5959e5 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -80,7 +80,6 @@ namespace Endgames { add("KNNKP"); add("KNPK"); - add("KNPKB"); add("KRPKR"); add("KRPKB"); add("KBPKB"); @@ -733,27 +732,6 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// KNP vs KB. If knight can block bishop from taking pawn, it's a win. -/// Otherwise the position is drawn. -template<> -ScaleFactor Endgame::operator()(const Position& pos) const { - - assert(verify_material(pos, strongSide, KnightValueMg, 1)); - assert(verify_material(pos, weakSide, BishopValueMg, 0)); - - Square pawnSq = pos.square(strongSide); - Square bishopSq = pos.square(weakSide); - Square weakKingSq = pos.square(weakSide); - - // King needs to get close to promoting pawn to prevent knight from blocking. - // Rules for this are very tricky, so just approximate. - if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from(bishopSq)) - return ScaleFactor(distance(weakKingSq, pawnSq)); - - return SCALE_FACTOR_NONE; -} - - /// KP vs KP. This is done by removing the weakest side's pawn and probing the /// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably /// has at least a draw with the pawn as well. The exception is when the stronger diff --git a/src/endgame.h b/src/endgame.h index f6135354..49ebb603 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -58,7 +58,6 @@ enum EndgameCode { KBPPKB, // KBPP vs KB KBPKN, // KBP vs KN KNPK, // KNP vs K - KNPKB, // KNP vs KB KPKP // KP vs KP }; From c8e8e48b144bcc50c5423b771eb668eafb13af99 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 25 Mar 2020 16:06:25 +0000 Subject: [PATCH 214/281] Remove passed_count from almostUnwinnable. This simplification allows the almostUnwinnable flag to match endgames where the pawns are all on the same flank but are not symmetrical. STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 23356 W: 4543 L: 4395 D: 14418 Ptnml(0-2): 346, 2651, 5582, 2707, 392 https://tests.stockfishchess.org/tests/view/5e7b8f57e42a5c3b3ca2eb09 LTC: LLR: 2.96 (-2.94,2.94) {-1.50,0.50} Total: 31778 W: 4097 L: 4023 D: 23658 Ptnml(0-2): 199, 2853, 9729, 2891, 217 https://tests.stockfishchess.org/tests/view/5e7ba5ade42a5c3b3ca2eb16 closes https://github.com/official-stockfish/Stockfish/pull/2596 Bench 4777139 --- src/evaluate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fad2a785..d51325f0 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -707,8 +707,7 @@ namespace { bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); - bool almostUnwinnable = !pe->passed_count() - && outflanking < 0 + bool almostUnwinnable = outflanking < 0 && !pawnsOnBothFlanks; bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 From 58746d9fb8bab4e9617cd7c809c6a0afd809c35e Mon Sep 17 00:00:00 2001 From: Lyudmil Antonov Date: Mon, 17 Feb 2020 11:13:03 +0200 Subject: [PATCH 215/281] Tuned history reduction Value after a long Bayesian tuning, using a home-made classification approach. STC https://tests.stockfishchess.org/tests/view/5e7c7b16e42a5c3b3ca2eb66 LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 45472 W: 8992 L: 8732 D: 27748 Ptnml(0-2): 795, 5276, 10352, 5500, 813 LTC https://tests.stockfishchess.org/tests/view/5e7c8be7e42a5c3b3ca2eb75 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 22744 W: 3085 L: 2849 D: 16810 Ptnml(0-2): 156, 2090, 6658, 2298, 170 closes https://github.com/official-stockfish/Stockfish/pull/2597 Bench 5030855 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index abc6874e..c5a7582c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1182,7 +1182,7 @@ moves_loop: // When in check, search starts from here r++; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 16384; + r -= ss->statScore / 16434; } // Increase reduction for captures/promotions if late move and at low depth From 8c73339a3639f1753b2270b569532daffa7d93f5 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 26 Mar 2020 19:47:48 +0000 Subject: [PATCH 216/281] Remove previousScore adjustment of delta. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 14580 W: 2904 L: 2731 D: 8945 Ptnml(0-2): 243, 1665, 3339, 1762, 281 https://tests.stockfishchess.org/tests/view/5e7d080ae42a5c3b3ca2ebc6 LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 60338 W: 7870 L: 7831 D: 44637 Ptnml(0-2): 451, 5596, 18018, 5671, 433 https://tests.stockfishchess.org/tests/view/5e7d11b3e42a5c3b3ca2ebd3 closes https://github.com/official-stockfish/Stockfish/pull/2598 Bench 5247262 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index c5a7582c..f866afe5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -433,7 +433,7 @@ void Thread::search() { if (rootDepth >= 4) { Value previousScore = rootMoves[pvIdx].previousScore; - delta = Value(21 + abs(previousScore) / 256); + delta = Value(21); alpha = std::max(previousScore - delta,-VALUE_INFINITE); beta = std::min(previousScore + delta, VALUE_INFINITE); From f2430bf034cc31258c870797501bce0605bce3d0 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sun, 29 Mar 2020 20:04:20 +0300 Subject: [PATCH 217/281] Count only the most advanced passed pawn for each file. This patch adjusts definition of passed pawns - if there is a pawn of our color in the same file in front of a current pawn it's no longer counts as passed. passed STC https://tests.stockfishchess.org/tests/view/5e802037e42a5c3b3ca2ed07 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 215296 W: 41843 L: 41341 D: 132112 Ptnml(0-2): 3688, 25313, 49304, 25495, 3848 passed LTC https://tests.stockfishchess.org/tests/view/5e806441e42a5c3b3ca2ed2b LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 74050 W: 9761 L: 9379 D: 54910 Ptnml(0-2): 510, 6838, 22025, 7064, 588 closes https://github.com/official-stockfish/Stockfish/pull/2602 bench: 4902237 --- src/pawns.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pawns.cpp b/src/pawns.cpp index 560fd76b..3023021d 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -124,6 +124,8 @@ namespace { || ( stoppers == blocked && r >= RANK_5 && (shift(support) & ~(theirPawns | doubleAttackThem))); + passed &= !(forward_file_bb(Us, s) & ourPawns); + // Passed pawns will be properly scored later in evaluation when we have // full attack info. if (passed) From b7ecdaada7e2690dd286c41d3a73463f06fb088f Mon Sep 17 00:00:00 2001 From: Praveen tummala Date: Mon, 30 Mar 2020 10:22:42 +0530 Subject: [PATCH 218/281] Movecount pruning reduction logic This patch refines search reduction logic in case the position is not a former PV node and is pruned based on move count. passed STC https://tests.stockfishchess.org/tests/view/5e8092bde42a5c3b3ca2ed35 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 78848 W: 15480 L: 15170 D: 48198 Ptnml(0-2): 1406, 9310, 17773, 9438, 1497 passed LTC https://tests.stockfishchess.org/tests/view/5e80bb13e42a5c3b3ca2ed4b LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 86596 W: 11451 L: 11033 D: 64112 Ptnml(0-2): 624, 7993, 25687, 8329, 665 closes https://github.com/official-stockfish/Stockfish/pull/2605 Bench: 5138771 --- AUTHORS | 3 ++- src/search.cpp | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4826d1c4..79eb98a0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ -# List of authors for Stockfish, as of January 7, 2020 +# List of authors for Stockfish, as of March 30, 2020 Tord Romstad (romstad) Marco Costalba (mcostalba) @@ -123,6 +123,7 @@ Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) pellanda Peter Zsifkovits (CoffeeOne) +Praveen Kumar Tummala (praveentml) Rahul Dsilva (silversolver1) Ralph Stößer (Ralph Stoesser) Raminder Singh diff --git a/src/search.cpp b/src/search.cpp index f866afe5..993fa853 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -962,6 +962,7 @@ moves_loop: // When in check, search starts from here value = bestValue; singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); + bool formerPv = ttPv && !PvNode; // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); @@ -1054,8 +1055,8 @@ moves_loop: // When in check, search starts from here && tte->depth() >= depth - 3 && pos.legal(move)) { - Value singularBeta = ttValue - (((ttPv && !PvNode) + 4) * depth) / 2; - Depth singularDepth = (depth - 1 + 3 * (ttPv && !PvNode)) / 2; + Value singularBeta = ttValue - ((formerPv + 4) * depth) / 2; + Depth singularDepth = (depth - 1 + 3 * formerPv) / 2; ss->excludedMove = move; value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); ss->excludedMove = MOVE_NONE; @@ -1143,13 +1144,16 @@ moves_loop: // When in check, search starts from here if (ttPv) r -= 2; + if (moveCountPruning && !formerPv) + r++; + // Decrease reduction if opponent's move count is high (~5 Elo) if ((ss-1)->moveCount > 14) r--; // Decrease reduction if ttMove has been singularly extended (~3 Elo) if (singularLMR) - r -= 1 + (ttPv && !PvNode); + r -= 1 + formerPv; if (!captureOrPromotion) { From 209e94203f8c4d0a48405192d1e71c80f28f3159 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 30 Mar 2020 22:45:35 +0200 Subject: [PATCH 219/281] Small cleanups https://github.com/official-stockfish/Stockfish/pull/2584 No functional change. --- src/bitboard.cpp | 34 ++++++++++++++-------------------- src/evaluate.cpp | 26 +++++++++++++------------- src/material.cpp | 2 +- src/movegen.cpp | 4 ++-- src/movepick.cpp | 2 +- src/pawns.cpp | 4 ++-- src/position.cpp | 2 +- src/search.cpp | 4 ++-- src/uci.cpp | 2 +- 9 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 70114f20..bb03dfeb 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -78,11 +78,11 @@ void Bitboards::init() { for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - PawnAttacks[WHITE][s] = pawn_attacks_bb(square_bb(s)); - PawnAttacks[BLACK][s] = pawn_attacks_bb(square_bb(s)); - } + Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; + Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; + + init_magics(RookTable, RookMagics, RookDirections); + init_magics(BishopTable, BishopMagics, BishopDirections); // Helper returning the target bitboard of a step from a square auto landing_square_bb = [&](Square s, int step) @@ -91,23 +91,17 @@ void Bitboards::init() { return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); }; - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) - PseudoAttacks[KING][s] |= landing_square_bb(s, step); - - for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) - PseudoAttacks[KNIGHT][s] |= landing_square_bb(s, step); - } - - Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; - Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; - - init_magics(RookTable, RookMagics, RookDirections); - init_magics(BishopTable, BishopMagics, BishopDirections); - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) { + PawnAttacks[WHITE][s1] = pawn_attacks_bb(square_bb(s1)); + PawnAttacks[BLACK][s1] = pawn_attacks_bb(square_bb(s1)); + + for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) + PseudoAttacks[KING][s1] |= landing_square_bb(s1, step); + + for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) + PseudoAttacks[KNIGHT][s1] |= landing_square_bb(s1, step); + PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d51325f0..63541c2a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -91,15 +91,15 @@ namespace { // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. constexpr Score MobilityBonus[][32] = { - { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knights + { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knight S( 22, 23), S( 28, 27), S( 33, 33) }, - { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops + { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, - { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rooks + { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rook S( 9,112), S( 16,118), S( 30,132), S( 29,142), S( 32,155), S( 38,165), S( 46,166), S( 48,169), S( 58,171) }, - { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queens + { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queen S( 28, 61), S( 41, 73), S( 43, 79), S( 48, 92), S( 56, 94), S( 60,104), S( 60,113), S( 66,120), S( 67,123), S( 70,126), S( 71,133), S( 73,136), S( 79,140), S( 88,143), S( 88,148), S( 99,166), S(102,170), S(102,175), @@ -213,7 +213,7 @@ namespace { template template void Evaluation::initialize() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); constexpr Direction Down = -Up; constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); @@ -252,7 +252,7 @@ namespace { template template Score Evaluation::pieces() { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); @@ -298,12 +298,12 @@ namespace { else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) score += Outpost; - // Knight and Bishop bonus for being right behind a pawn + // Bonus for a knight or bishop shielded by pawn if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; // Penalty if the piece is far from the king - score -= KingProtector * distance(s, pos.square(Us)); + score -= KingProtector * distance(pos.square(Us), s); if (Pt == BISHOP) { @@ -313,7 +313,7 @@ namespace { Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) - * (!bool(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); + * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) @@ -372,7 +372,7 @@ namespace { template template Score Evaluation::king() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); @@ -480,7 +480,7 @@ namespace { template template Score Evaluation::threats() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); @@ -576,7 +576,7 @@ namespace { template template Score Evaluation::passed() const { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); auto king_proximity = [&](Color c, Square s) { @@ -667,7 +667,7 @@ namespace { if (pos.non_pawn_material() < SpaceThreshold) return SCORE_ZERO; - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Down = -pawn_push(Us); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) diff --git a/src/material.cpp b/src/material.cpp index 7e212461..93699f5f 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -84,7 +84,7 @@ namespace { template int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; int bonus = 0; diff --git a/src/movegen.cpp b/src/movegen.cpp index 9964ad34..804ef87b 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -52,7 +52,7 @@ namespace { template ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); constexpr Direction Up = pawn_push(Us); @@ -319,7 +319,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { while (sliders) { Square checksq = pop_lsb(&sliders); - sliderAttacks |= LineBB[checksq][ksq] ^ checksq; + sliderAttacks |= LineBB[ksq][checksq] ^ checksq; } // Generate evasions for king, capture and non capture moves diff --git a/src/movepick.cpp b/src/movepick.cpp index 575c9022..580c6d75 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -59,7 +59,7 @@ namespace { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) , ply(pl) { + refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); diff --git a/src/pawns.cpp b/src/pawns.cpp index 3023021d..8759631a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -68,7 +68,7 @@ namespace { template Score evaluate(const Position& pos, Pawns::Entry* e) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); Bitboard neighbours, stoppers, support, phalanx, opposed; @@ -187,7 +187,7 @@ Entry* probe(const Position& pos) { template Score Entry::evaluate_shelter(const Position& pos, Square ksq) { - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = ~Us; Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us); diff --git a/src/position.cpp b/src/position.cpp index fefce56e..6bbb7914 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -666,7 +666,7 @@ bool Position::gives_check(Move m) const { case CASTLING: { Square kfrom = from; - Square rfrom = to; // Castling is encoded as 'King captures the rook' + Square rfrom = to; // Castling is encoded as 'king captures the rook' Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); diff --git a/src/search.cpp b/src/search.cpp index 993fa853..38d3204c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -292,7 +292,7 @@ void MainThread::search() { if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) { - // Make sure we pick the shortest mate + // Make sure we pick the shortest mate / TB conversion if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } @@ -867,7 +867,7 @@ namespace { if (nullValue >= beta) { - // Do not return unproven mate scores + // Do not return unproven mate or TB scores if (nullValue >= VALUE_TB_WIN_IN_MAX_PLY) nullValue = beta; diff --git a/src/uci.cpp b/src/uci.cpp index 33577a4e..11d5adc6 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -115,7 +115,7 @@ namespace { limits.startTime = now(); // As early as possible! while (is >> token) - if (token == "searchmoves") + if (token == "searchmoves") // Needs to be the last command on the line while (is >> token) limits.searchmoves.push_back(UCI::to_move(pos, token)); From 0b8ce4b3037c0efcb2c8bf10598ec3f4fd919e1a Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 25 Mar 2020 19:57:36 -0600 Subject: [PATCH 220/281] Limit array access in Position This is a non-functional code style change that routes all position array accesses to single methods, and adds an assert to check correctness. Passed STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 37312 W: 7378 L: 7246 D: 22688 Ptnml(0-2): 606, 4280, 8762, 4392, 616 https://tests.stockfishchess.org/tests/view/5e7c0c69e42a5c3b3ca2eb3d closes https://github.com/official-stockfish/Stockfish/pull/2595 No functional change. --- src/position.h | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/position.h b/src/position.h index e5071d53..f79c5463 100644 --- a/src/position.h +++ b/src/position.h @@ -83,7 +83,6 @@ public: const std::string fen() const; // Position representation - Bitboard pieces() const; Bitboard pieces(PieceType pt) const; Bitboard pieces(PieceType pt1, PieceType pt2) const; Bitboard pieces(Color c) const; @@ -207,28 +206,25 @@ inline Color Position::side_to_move() const { return sideToMove; } -inline bool Position::empty(Square s) const { - return board[s] == NO_PIECE; -} - inline Piece Position::piece_on(Square s) const { + assert(is_ok(s)); return board[s]; } +inline bool Position::empty(Square s) const { + return piece_on(s) == NO_PIECE; +} + inline Piece Position::moved_piece(Move m) const { - return board[from_sq(m)]; + return piece_on(from_sq(m)); } -inline Bitboard Position::pieces() const { - return byTypeBB[ALL_PIECES]; -} - -inline Bitboard Position::pieces(PieceType pt) const { +inline Bitboard Position::pieces(PieceType pt = ALL_PIECES) const { return byTypeBB[pt]; } inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const { - return byTypeBB[pt1] | byTypeBB[pt2]; + return pieces(pt1) | pieces(pt2); } inline Bitboard Position::pieces(Color c) const { @@ -236,11 +232,11 @@ inline Bitboard Position::pieces(Color c) const { } inline Bitboard Position::pieces(Color c, PieceType pt) const { - return byColorBB[c] & byTypeBB[pt]; + return pieces(c) & pieces(pt); } inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const { - return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]); + return pieces(c) & (pieces(pt1) | pieces(pt2)); } template inline int Position::count(Color c) const { @@ -248,7 +244,7 @@ template inline int Position::count(Color c) const { } template inline int Position::count() const { - return pieceCount[make_piece(WHITE, Pt)] + pieceCount[make_piece(BLACK, Pt)]; + return count(WHITE) + count(BLACK); } template inline const Square* Position::squares(Color c) const { @@ -257,7 +253,7 @@ template inline const Square* Position::squares(Color c) const { template inline Square Position::square(Color c) const { assert(pieceCount[make_piece(c, Pt)] == 1); - return pieceList[make_piece(c, Pt)][0]; + return squares(c)[0]; } inline Square Position::ep_square() const { @@ -279,7 +275,7 @@ inline int Position::castling_rights(Color c) const { inline bool Position::castling_impeded(CastlingRights cr) const { assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); - return byTypeBB[ALL_PIECES] & castlingPath[cr]; + return pieces() & castlingPath[cr]; } inline Square Position::castling_rook_square(CastlingRights cr) const { @@ -292,7 +288,7 @@ template inline Bitboard Position::attacks_from(Square s) const { static_assert(Pt != PAWN, "Pawn attacks need color"); - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, byTypeBB[ALL_PIECES]) + return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, pieces()) : Pt == QUEEN ? attacks_from(s) | attacks_from(s) : PseudoAttacks[Pt][s]; } @@ -303,11 +299,11 @@ inline Bitboard Position::attacks_from(Square s, Color c) const { } inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, byTypeBB[ALL_PIECES]); + return attacks_bb(pt, s, pieces()); } inline Bitboard Position::attackers_to(Square s) const { - return attackers_to(s, byTypeBB[ALL_PIECES]); + return attackers_to(s, pieces()); } inline Bitboard Position::checkers() const { @@ -360,7 +356,7 @@ inline Value Position::non_pawn_material(Color c) const { } inline Value Position::non_pawn_material() const { - return st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK]; + return non_pawn_material(WHITE) + non_pawn_material(BLACK); } inline int Position::game_ply() const { @@ -372,8 +368,8 @@ inline int Position::rule50_count() const { } inline bool Position::opposite_bishops() const { - return pieceCount[W_BISHOP] == 1 - && pieceCount[B_BISHOP] == 1 + return count(WHITE) == 1 + && count(BLACK) == 1 && opposite_colors(square(WHITE), square(BLACK)); } From 84f3bf594d323ac4fcaac0b6681edcdf2f9da70f Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 29 Mar 2020 14:09:19 -0700 Subject: [PATCH 221/281] No voting for TB loss / mate. Just as we pick the shortest mate also make sure we stave off mate as long as possible. https://github.com/official-stockfish/Stockfish/pull/2603 bench: 5138771 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 38d3204c..ad5b364d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -280,7 +280,7 @@ void MainThread::search() { std::map votes; Value minScore = this->rootMoves[0].score; - // Find out minimum score + // Find minimum score for (Thread* th: Threads) minScore = std::min(minScore, th->rootMoves[0].score); @@ -290,14 +290,15 @@ void MainThread::search() { votes[th->rootMoves[0].pv[0]] += (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (bestThread->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY) + if (abs(bestThread->rootMoves[0].score) >= VALUE_TB_WIN_IN_MAX_PLY) { - // Make sure we pick the shortest mate / TB conversion + // Make sure we pick the shortest mate / TB conversion or stave off mate the longest if (th->rootMoves[0].score > bestThread->rootMoves[0].score) bestThread = th; } else if ( th->rootMoves[0].score >= VALUE_TB_WIN_IN_MAX_PLY - || votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) + || ( th->rootMoves[0].score > VALUE_TB_LOSS_IN_MAX_PLY + && votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]])) bestThread = th; } } From 375e4eeaf5e739c176c38ff05ae954bb60a98987 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Mon, 30 Mar 2020 21:53:02 -0400 Subject: [PATCH 222/281] Simplify a candidate passer condition. STC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 31528 W: 6208 L: 6061 D: 19259 Ptnml(0-2): 541, 3673, 7205, 3788, 557 https://tests.stockfishchess.org/tests/view/5e825db0e42a5c3b3ca2ee21 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 38546 W: 5083 L: 5009 D: 28454 Ptnml(0-2): 299, 3628, 11362, 3668, 316 https://tests.stockfishchess.org/tests/view/5e826ec7e42a5c3b3ca2ee2a closes https://github.com/official-stockfish/Stockfish/pull/2607 Bench: 5139561 --- src/evaluate.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 63541c2a..57491f34 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -639,9 +639,8 @@ namespace { } // r > RANK_3 // Scale down bonus for candidate passers which need more than one - // pawn push to become passed, or have a pawn in front of them. - if ( !pos.pawn_passed(Us, s + Up) - || (pos.pieces(PAWN) & (s + Up))) + // pawn push to become passed. + if (!pos.pawn_passed(Us, s + Up)) bonus = bonus / 2; score += bonus - PassedFile * edge_distance(file_of(s)); From c14f4877cf8067e0913a6db4ab05fef9a853c1d0 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Thu, 2 Apr 2020 06:33:53 +0300 Subject: [PATCH 223/281] Increase reduction for captures. The idea behind this patch is that if static eval is really bad so capturing of current piece on spot will still produce a position with an eval much lower than alpha then our best chance is to create some kind of king attack. So captures without check are mostly worse than captures with check and can be reduced more. passed STC https://tests.stockfishchess.org/tests/view/5e8514b44411759d9d098543 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 46196 W: 9039 L: 8781 D: 28376 Ptnml(0-2): 750, 5412, 10628, 5446, 862 passed LTC https://tests.stockfishchess.org/tests/view/5e8530134411759d9d09854c LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 23462 W: 3228 L: 2988 D: 17246 Ptnml(0-2): 186, 2125, 6849, 2405, 166 close https://github.com/official-stockfish/Stockfish/pull/2612 bench 4742598 --- src/search.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ad5b364d..eb30d9fa 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1189,10 +1189,17 @@ moves_loop: // When in check, search starts from here // Decrease/increase reduction for moves with a good/bad history (~30 Elo) r -= ss->statScore / 16434; } + else + { + // Increase reduction for captures/promotions if late move and at low depth + if (depth < 8 && moveCount > 2) + r++; - // Increase reduction for captures/promotions if late move and at low depth - else if (depth < 8 && moveCount > 2) - r++; + // Unless giving check, this capture is likely bad + if ( !givesCheck + && ss->staticEval + PieceValue[EG][pos.captured_piece()] + 200 * depth <= alpha) + r++; + } Depth d = Utility::clamp(newDepth - r, 1, newDepth); From 3cb1c6c3c6206c3c2a0d78ce1cb9820256efc96e Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 31 Mar 2020 15:08:55 -0600 Subject: [PATCH 224/281] remove KNPK endgame code In more than 100k local KNPK games, there is no discernible difference between master and master with this endgame removed: master:42971, patch:42973, draws: 3969. Removal does not seem to regress in normal games. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 46390 W: 8998 L: 8884 D: 28508 Ptnml(0-2): 707, 5274, 11163, 5300, 751 https://tests.stockfishchess.org/tests/view/5e83b18ee42a5c3b3ca2ef02 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 44768 W: 5863 L: 5814 D: 33091 Ptnml(0-2): 251, 3918, 14028, 3905, 282 https://tests.stockfishchess.org/tests/view/5e84a82a4411759d9d0984f4 In tests with a book of endgames that can convert into KNPK, no significant difference can be seen either ``` TC 1.0+0.01 Score of patch vs master: 6131 - 6188 - 27681 [0.499] 40000 Elo difference: -0.5 +/- 1.9, LOS: 30.4 %, DrawRatio: 69.2 % TC 2.0+0.02 Score of patch vs master: 5740 - 5741 - 28519 [0.500] 40000 Elo difference: -0.0 +/- 1.8, LOS: 49.6 %, DrawRatio: 71.3 % `` closes https://github.com/official-stockfish/Stockfish/pull/2611 Bench 4512059 --- src/endgame.cpp | 20 -------------------- src/endgame.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/endgame.cpp b/src/endgame.cpp index 1a5959e5..e232da62 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -79,7 +79,6 @@ namespace Endgames { add("KQKR"); add("KNNKP"); - add("KNPK"); add("KRPKR"); add("KRPKB"); add("KBPKB"); @@ -713,25 +712,6 @@ ScaleFactor Endgame::operator()(const Position& pos) const { } -/// KNP vs K. There is a single rule: if the pawn is a rook pawn on the 7th rank -/// and the defending king prevents the pawn from advancing, the position is drawn. -template<> -ScaleFactor Endgame::operator()(const Position& pos) const { - - assert(verify_material(pos, strongSide, KnightValueMg, 1)); - assert(verify_material(pos, weakSide, VALUE_ZERO, 0)); - - // Assume strongSide is white and the pawn is on files A-D - Square pawnSq = normalize(pos, strongSide, pos.square(strongSide)); - Square weakKingSq = normalize(pos, strongSide, pos.square(weakSide)); - - if (pawnSq == SQ_A7 && distance(SQ_A8, weakKingSq) <= 1) - return SCALE_FACTOR_DRAW; - - return SCALE_FACTOR_NONE; -} - - /// KP vs KP. This is done by removing the weakest side's pawn and probing the /// KP vs K bitbase: If the weakest side has a draw without the pawn, it probably /// has at least a draw with the pawn as well. The exception is when the stronger diff --git a/src/endgame.h b/src/endgame.h index 49ebb603..fd1aba2d 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -57,7 +57,6 @@ enum EndgameCode { KBPKB, // KBP vs KB KBPPKB, // KBPP vs KB KBPKN, // KBP vs KN - KNPK, // KNP vs K KPKP // KP vs KP }; From fbc7a328c67092799547f93e684323e2c1a6226e Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Thu, 2 Apr 2020 23:57:15 -0400 Subject: [PATCH 225/281] Retire candidate passed pawns Before this commit, some pawns were considered "candidate" passed pawns and given half bonus. After this commit, all of these pawns are scored as passed pawns, and they do not receive less bonus. STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 21806 W: 4320 L: 4158 D: 13328 Ptnml(0-2): 367, 2526, 5001, 2596, 413 https://tests.stockfishchess.org/tests/view/5e86b4724411759d9d098639 LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 12590 W: 1734 L: 1617 D: 9239 Ptnml(0-2): 96, 1187, 3645, 1238, 129 https://tests.stockfishchess.org/tests/view/5e86d2874411759d9d098640 This PR and commit are dedicated to our colleague Stefan Geschwentner (@locutus2), one of the most respected and accomplished members of the Stockfish developer community. Stockfish is a volunteer project and has always thrived because of Stefan's talent, insight, generosity, and dedication. Welcome back, Stefan! closes https://github.com/official-stockfish/Stockfish/pull/2613 Bench: 4831963 --- src/evaluate.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 57491f34..f4a5d486 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -638,11 +638,6 @@ namespace { } } // r > RANK_3 - // Scale down bonus for candidate passers which need more than one - // pawn push to become passed. - if (!pos.pawn_passed(Us, s + Up)) - bonus = bonus / 2; - score += bonus - PassedFile * edge_distance(file_of(s)); } From 85bcf4741e271d9b205ac335f7056ec65a2a6ab7 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 4 Apr 2020 18:06:13 +0300 Subject: [PATCH 226/281] Further increase reductions with increasing number of threads This patch doubles the reduction increase with thread count. passed STC https://tests.stockfishchess.org/tests/view/5e874f5a4411759d9d098696 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 9162 W: 1558 L: 1385 D: 6219 Ptnml(0-2): 90, 958, 2343, 1069, 121 passed LTC https://tests.stockfishchess.org/tests/view/5e8762804411759d9d09869f LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 79364 W: 9541 L: 9159 D: 60664 Ptnml(0-2): 462, 6880, 24661, 7172, 507 closes https://github.com/official-stockfish/Stockfish/pull/2615 bench 4831963 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index eb30d9fa..cfda94b8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -194,7 +194,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((24.8 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((24.8 + std::log(Threads.size())) * std::log(i)); } From 195a4fec6d6bd1f9e43f5b3e83a3dcf57dc73744 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Tue, 7 Apr 2020 16:53:24 +0300 Subject: [PATCH 227/281] Introduce capture history pruning This patch introduces a heuristic that is similar to countermove based pruning but for captures - capture history pruning. The idea is that we can (almost) safely prune really late captures with negative history if they don't give check so will most likely not produce some king-attacking tactic. passed STC https://tests.stockfishchess.org/tests/view/5e8c60d40ffd2be7f15e5470 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 23748 W: 4758 L: 4529 D: 14461 Ptnml(0-2): 421, 2712, 5400, 2899, 442 passed LTC https://tests.stockfishchess.org/tests/view/5e8c72bf0ffd2be7f15e547f LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 17330 W: 2415 L: 2190 D: 12725 Ptnml(0-2): 126, 1561, 5107, 1704, 167 closes https://github.com/official-stockfish/Stockfish/pull/2618 bench 4417023 --- src/search.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cfda94b8..dba8857e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -789,6 +789,8 @@ namespace { } } + CapturePieceToHistory& captureHistory = thisThread->captureHistory; + // Step 6. Static evaluation of the position if (inCheck) { @@ -899,7 +901,7 @@ namespace { && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); - MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); + MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; while ( (move = mp.next_move()) != MOVE_NONE @@ -954,7 +956,7 @@ moves_loop: // When in check, search starts from here MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->lowPlyHistory, - &thisThread->captureHistory, + &captureHistory, contHist, countermove, ss->killers, @@ -1010,12 +1012,12 @@ moves_loop: // When in check, search starts from here // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold moveCountPruning = moveCount >= futility_move_count(improving, depth); + // Reduced depth of the next LMR search + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); + if ( !captureOrPromotion && !givesCheck) { - // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); - // Countermoves based pruning (~20 Elo) if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold @@ -1035,8 +1037,16 @@ moves_loop: // When in check, search starts from here if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) - continue; + else + { + if ( !givesCheck + && lmrDepth < 1 + && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) + continue; + + if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) + continue; + } } // Step 14. Extensions (~75 Elo) From f83cb95740de019db6ff5567d6f84f218b18cd9e Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 12 Apr 2020 20:30:08 +0200 Subject: [PATCH 228/281] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2606 No functional change --- src/bitboard.cpp | 29 +++++++++-------------------- src/bitboard.h | 20 ++++++++++++++------ src/evaluate.cpp | 2 +- src/movegen.cpp | 10 ++-------- src/pawns.cpp | 2 +- src/psqt.cpp | 2 +- src/search.cpp | 25 ++++++++++++++----------- src/syzygy/tbprobe.cpp | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- src/types.h | 6 +++--- 11 files changed, 48 insertions(+), 54 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index bb03dfeb..69bbc77b 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -84,23 +84,16 @@ void Bitboards::init() { init_magics(RookTable, RookMagics, RookDirections); init_magics(BishopTable, BishopMagics, BishopDirections); - // Helper returning the target bitboard of a step from a square - auto landing_square_bb = [&](Square s, int step) - { - Square to = Square(s + step); - return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); - }; - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) { PawnAttacks[WHITE][s1] = pawn_attacks_bb(square_bb(s1)); PawnAttacks[BLACK][s1] = pawn_attacks_bb(square_bb(s1)); for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} ) - PseudoAttacks[KING][s1] |= landing_square_bb(s1, step); + PseudoAttacks[KING][s1] |= safe_destination(s1, step); for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} ) - PseudoAttacks[KNIGHT][s1] |= landing_square_bb(s1, step); + PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step); PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); @@ -117,20 +110,16 @@ namespace { Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied) { - Bitboard attack = 0; + Bitboard attacks = 0; for (int i = 0; i < 4; ++i) - for (Square s = sq + directions[i]; - is_ok(s) && distance(s, s - directions[i]) == 1; - s += directions[i]) - { - attack |= s; + { + Square s = sq; + while(safe_destination(s, directions[i]) && !(occupied & s)) + attacks |= (s += directions[i]); + } - if (occupied & s) - break; - } - - return attack; + return attacks; } diff --git a/src/bitboard.h b/src/bitboard.h index 529e3dfe..9252c3dc 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -106,7 +106,7 @@ extern Magic RookMagics[SQUARE_NB]; extern Magic BishopMagics[SQUARE_NB]; inline Bitboard square_bb(Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(is_ok(s)); return SquareBB[s]; } @@ -123,7 +123,7 @@ inline Bitboard operator&(Square s, Bitboard b) { return b & s; } inline Bitboard operator|(Square s, Bitboard b) { return b | s; } inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; } -inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | square_bb(s2); } +inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | s2; } constexpr bool more_than_one(Bitboard b) { return b & (b - 1); @@ -209,8 +209,8 @@ inline Bitboard between_bb(Square s1, Square s2) { /// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2. inline Bitboard forward_ranks_bb(Color c, Square s) { - return c == WHITE ? ~Rank1BB << 8 * (rank_of(s) - RANK_1) - : ~Rank8BB >> 8 * (RANK_8 - rank_of(s)); + return c == WHITE ? ~Rank1BB << 8 * relative_rank(WHITE, s) + : ~Rank8BB >> 8 * relative_rank(BLACK, s); } @@ -255,8 +255,16 @@ template<> inline int distance(Square x, Square y) { return std::abs(file_ template<> inline int distance(Square x, Square y) { return std::abs(rank_of(x) - rank_of(y)); } template<> inline int distance(Square x, Square y) { return SquareDistance[x][y]; } -inline File edge_distance(File f) { return std::min(f, File(FILE_H - f)); } -inline Rank edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } +inline int edge_distance(File f) { return std::min(f, File(FILE_H - f)); } +inline int edge_distance(Rank r) { return std::min(r, Rank(RANK_8 - r)); } + +/// Return the target square bitboard if we do not step off the board, empty otherwise + +inline Bitboard safe_destination(Square s, int step) +{ + Square to = Square(s + step); + return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); +} /// attacks_bb() returns a bitboard representing all the squares attacked by a /// piece of type Pt (bishop or rook) placed on 's'. diff --git a/src/evaluate.cpp b/src/evaluate.cpp index f4a5d486..a2e5ef7b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -746,7 +746,7 @@ namespace { { if ( pos.opposite_bishops() && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 22 ; + sf = 22; else sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); diff --git a/src/movegen.cpp b/src/movegen.cpp index 804ef87b..a3abcde8 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -277,16 +277,13 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { assert(!pos.checkers()); Color us = pos.side_to_move(); - Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us); + Bitboard dc = pos.blockers_for_king(~us) & pos.pieces(us) & ~pos.pieces(PAWN); while (dc) { Square from = pop_lsb(&dc); PieceType pt = type_of(pos.piece_on(from)); - if (pt == PAWN) - continue; // Will be generated together with direct checks - Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces(); if (pt == KING) @@ -317,10 +314,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // the king evasions in order to skip known illegal moves, which avoids any // useless legality checks later on. while (sliders) - { - Square checksq = pop_lsb(&sliders); - sliderAttacks |= LineBB[ksq][checksq] ^ checksq; - } + sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers(); // Generate evasions for king, capture and non capture moves Bitboard b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; diff --git a/src/pawns.cpp b/src/pawns.cpp index 8759631a..0017b804 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -204,7 +204,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = edge_distance(f); + File d = File(edge_distance(f)); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/psqt.cpp b/src/psqt.cpp index d86e98e4..7fa36ac8 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -112,7 +112,7 @@ void init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { - File f = edge_distance(file_of(s)); + File f = File(edge_distance(file_of(s))); psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)] : Bonus[pc][rank_of(s)][f]); psq[~pc][flip_rank(s)] = -psq[pc][s]; diff --git a/src/search.cpp b/src/search.cpp index dba8857e..4abc6069 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -303,7 +303,7 @@ void MainThread::search() { } } - previousScore = bestThread->rootMoves[0].score; + bestPreviousScore = bestThread->rootMoves[0].score; // Send again PV info if we have a new best thread if (bestThread != this) @@ -349,12 +349,12 @@ void Thread::search() { if (mainThread) { - if (mainThread->previousScore == VALUE_INFINITE) + if (mainThread->bestPreviousScore == VALUE_INFINITE) for (int i=0; i<4; ++i) mainThread->iterValue[i] = VALUE_ZERO; else for (int i=0; i<4; ++i) - mainThread->iterValue[i] = mainThread->previousScore; + mainThread->iterValue[i] = mainThread->bestPreviousScore; } size_t multiPV = Options["MultiPV"]; @@ -433,13 +433,13 @@ void Thread::search() { // Reset aspiration window starting size if (rootDepth >= 4) { - Value previousScore = rootMoves[pvIdx].previousScore; + Value prev = rootMoves[pvIdx].previousScore; delta = Value(21); - alpha = std::max(previousScore - delta,-VALUE_INFINITE); - beta = std::min(previousScore + delta, VALUE_INFINITE); + alpha = std::max(prev - delta,-VALUE_INFINITE); + beta = std::min(prev + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + (102 - ct / 2) * previousScore / (abs(previousScore) + 157); + int dct = ct + (102 - ct / 2) * prev / (abs(prev) + 157); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -537,7 +537,7 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (332 + 6 * (mainThread->previousScore - bestValue) + double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); @@ -626,7 +626,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, formerPv, inCheck, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -696,6 +696,7 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + formerPv = ttPv && !PvNode; if (ttPv && depth > 12 && ss->ply - 1 < MAX_LPH && !pos.captured_piece() && is_ok((ss-1)->currentMove)) thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); @@ -900,7 +901,8 @@ namespace { && depth >= 5 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 189 - 45 * improving, VALUE_INFINITE); + Value raisedBeta = beta + 189 - 45 * improving; + assert(raisedBeta < VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; @@ -965,7 +967,6 @@ moves_loop: // When in check, search starts from here value = bestValue; singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - bool formerPv = ttPv && !PvNode; // Mark this node as being searched ThreadHolding th(thisThread, posKey, ss->ply); @@ -1039,11 +1040,13 @@ moves_loop: // When in check, search starts from here } else { + // Capture history based pruning when the move doesn't give check if ( !givesCheck && lmrDepth < 1 && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) continue; + // See based pruning if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) continue; } diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 34e4331d..f1fd695c 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -705,7 +705,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu std::swap(squares[0], *std::max_element(squares, squares + leadPawnsCnt, pawns_comp)); - tbFile = edge_distance(file_of(squares[0])); + tbFile = File(edge_distance(file_of(squares[0]))); } // DTZ tables are one-sided, i.e. they store positions only for white to diff --git a/src/thread.cpp b/src/thread.cpp index b5cb87d9..88331f06 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -166,7 +166,7 @@ void ThreadPool::clear() { th->clear(); main()->callsCnt = 0; - main()->previousScore = VALUE_INFINITE; + main()->bestPreviousScore = VALUE_INFINITE; main()->previousTimeReduction = 1.0; } diff --git a/src/thread.h b/src/thread.h index 41d2b8f6..79be197b 100644 --- a/src/thread.h +++ b/src/thread.h @@ -88,7 +88,7 @@ struct MainThread : public Thread { void check_time(); double previousTimeReduction; - Value previousScore; + Value bestPreviousScore; Value iterValue[4]; int callsCnt; bool stopOnPonderhit; diff --git a/src/types.h b/src/types.h index bfcd3f23..cd8d2320 100644 --- a/src/types.h +++ b/src/types.h @@ -177,9 +177,9 @@ enum Value : int { VALUE_NONE = 32002, VALUE_TB_WIN_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, - VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, + VALUE_TB_LOSS_IN_MAX_PLY = -VALUE_TB_WIN_IN_MAX_PLY, VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, - VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, + VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, KnightValueMg = 781, KnightValueEg = 854, @@ -351,7 +351,7 @@ inline Score operator*(Score s, int i) { /// Multiplication of a Score by a boolean inline Score operator*(Score s, bool b) { - return Score(int(s) * int(b)); + return b ? s : SCORE_ZERO; } constexpr Color operator~(Color c) { From 6596f0eac0c1d25a12bfd923907bfc78beedbc90 Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 3 Apr 2020 15:10:50 -0600 Subject: [PATCH 229/281] Always remember the ttMove In master, if the received ttMove meets the prescribed conditions in the various MovePicker constructors, it is returned as the first move, otherwise we set it to MOVE_NONE. If set to MOVE_NONE, we no longer track what the ttMove was, and it will might be returned later in a list of generated moves. This may be a waste. With this patch, if the ttMove fails to meet the prescribed conditions, we simply skip the TT stages, but still store the move and make sure it's never returned. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 66424 W: 12903 L: 12806 D: 40715 Ptnml(0-2): 1195, 7730, 15230, 7897, 1160 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 45682 W: 5989 L: 5926 D: 33767 Ptnml(0-2): 329, 4361, 13443, 4334, 374 closes https://github.com/official-stockfish/Stockfish/pull/2616 Bench 4928928 --- src/movepick.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 580c6d75..b1e10587 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -59,42 +59,36 @@ namespace { MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, Move* killers, int pl) : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), - refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { + ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { assert(d > 0); - stage = pos.checkers() ? EVASION_TT : MAIN_TT; - ttMove = ttm && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + + !(ttm && pos.pseudo_legal(ttm)); } /// MovePicker constructor for quiescence search MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) - : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), recaptureSquare(rs), depth(d) { + : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { assert(d <= 0); - stage = pos.checkers() ? EVASION_TT : QSEARCH_TT; - ttMove = ttm - && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) - && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + + !(ttm && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) + && pos.pseudo_legal(ttm)); } /// MovePicker constructor for ProbCut: we generate captures with SEE greater /// than or equal to the given threshold. MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) - : pos(p), captureHistory(cph), threshold(th) { + : pos(p), captureHistory(cph), ttMove(ttm), threshold(th) { assert(!pos.checkers()); - stage = PROBCUT_TT; - ttMove = ttm - && pos.capture(ttm) - && pos.pseudo_legal(ttm) - && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; - stage += (ttMove == MOVE_NONE); + stage = PROBCUT_TT + !(ttm && pos.capture(ttm) + && pos.pseudo_legal(ttm) + && pos.see_ge(ttm, threshold)); } /// MovePicker::score() assigns a numerical value to each move in a list, used From 2c5f0efa1350ea19d32c599ddd6b9350f1d216ff Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 10 Apr 2020 21:53:00 +0200 Subject: [PATCH 230/281] Extend irreversible moves if these are ttMoves and played in positions with a high value of the rule50 counter. The unusual extension of 2 is safe in this context as awarding it will reset the rule50 counter, making sure it is awarded very rarely in a search path. This patch partially addresses https://github.com/official-stockfish/Stockfish/issues/2620 as it should make it less likely to play a move that resets the counter, but that is worse than alternative moves after a slightly deeper search. passed STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 71658 W: 13840 L: 13560 D: 44258 Ptnml(0-2): 1058, 7921, 17643, 8097, 1110 https://tests.stockfishchess.org/tests/view/5e90d0f6754c3424c4cf9f41 passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 85082 W: 11069 L: 10680 D: 63333 Ptnml(0-2): 459, 6982, 27259, 7393, 448 https://tests.stockfishchess.org/tests/view/5e917470af0a0143109dc341 closes https://github.com/official-stockfish/Stockfish/pull/2623 Bench: 4432822 --- src/search.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 4abc6069..4073f21d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1110,6 +1110,12 @@ moves_loop: // When in check, search starts from here if (type_of(move) == CASTLING) extension = 1; + // Late irreversible move extension + if ( move == ttMove + && pos.rule50_count() > 80 + && (captureOrPromotion || type_of(movedPiece) == PAWN)) + extension = 2; + // Add extension to new depth newDepth += extension; From d7a2d5a44588676abf9b49e35a5a567fd57ec3b0 Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Sat, 11 Apr 2020 17:28:45 +0200 Subject: [PATCH 231/281] Remove candidate passers w/o feasible lever +-------+ | o . . | o their pawns | x . . | x our pawns | . x . | <- Can sacrifice to create passer? +-------+ yes 1 2 3 4 5 +-------+ +-------+ +-------+ +-------+ +-------+ | o . . | | o r . | | o r . | | o . b | | o . b | lowercase: theirs | x b . | | x . . | | x . R | | x . R | | x . . | uppercase: ours | . x . | | . x . | | . x . | | . x . | | . x B | +-------+ +-------+ +-------+ +-------+ +-------+ no no yes no yes The value of our top pawn depends on our ability to advance our bottom pawn, levering their blocker. Previously, this pawn configuration was always scored as passer (although a blocked one). Add requirements for the square s above our (possibly) sacrificed pawn: - s must not be occupied by them (1). - If they attack s (2), we must attack s (3). - If they attack s with a minor (4), we must attack s with a minor (5). The attack from their blocker is ignored because it is inherent in the structure; we are ok with sacrificing our bottom pawn. LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 37030 W: 4962 L: 4682 D: 27386 Ptnml(0-2): 266, 3445, 10863, 3625, 316 https://tests.stockfishchess.org/tests/view/5e92a2b4be6ede5b954bf239 STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 40874 W: 8066 L: 7813 D: 24995 Ptnml(0-2): 706, 4753, 9324, 4890, 764 https://tests.stockfishchess.org/tests/view/5e922199af0a0143109dc90e closes https://github.com/official-stockfish/Stockfish/pull/2624 Bench: 4828294 --- src/evaluate.cpp | 19 ++++++++++++++++++- src/pawns.cpp | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a2e5ef7b..2698c813 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -578,16 +578,33 @@ namespace { constexpr Color Them = ~Us; constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; auto king_proximity = [&](Color c, Square s) { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, unsafeSquares; + Bitboard b, bb, squaresToQueen, unsafeSquares, candidatePassers, leverable; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); + candidatePassers = b & shift(pos.pieces(Them, PAWN)); + if (candidatePassers) + { + // Can we lever the blocker of a candidate passer? + leverable = shift(pos.pieces(Us, PAWN)) + & ~pos.pieces(Them) + & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]) + & (~(attackedBy[Them][KNIGHT] | attackedBy[Them][BISHOP]) + | (attackedBy[Us ][KNIGHT] | attackedBy[Us ][BISHOP])); + + // Remove candidate otherwise + b &= ~candidatePassers + | shift(leverable) + | shift(leverable); + } + while (b) { Square s = pop_lsb(&b); diff --git a/src/pawns.cpp b/src/pawns.cpp index 0017b804..63bc596f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -118,6 +118,7 @@ namespace { // (a) there is no stoppers except some levers // (b) the only stoppers are the leverPush, but we outnumber them // (c) there is only one front stopper which can be levered. + // (Refined in Evaluation::passed) passed = !(stoppers ^ lever) || ( !(stoppers ^ leverPush) && popcount(phalanx) >= popcount(leverPush)) From db59696aaf91641ade911c4a6ca393a1691d78a8 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 13 Apr 2020 03:48:52 +0300 Subject: [PATCH 232/281] Scale up space weight with number of blocked pawns This idea is loosely based on stockfish losses in closed positions in different tournaments. Space weight symmetrically increases for both sides the more blocked position is. passed STC https://tests.stockfishchess.org/tests/view/5e919eefaf0a0143109dc8ce LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 16994 W: 3389 L: 3172 D: 10433 Ptnml(0-2): 277, 1931, 3918, 2040, 331 passed LTC https://tests.stockfishchess.org/tests/view/5e91d04faf0a0143109dc8ea LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 133386 W: 17316 L: 16763 D: 99307 Ptnml(0-2): 945, 12407, 39524, 12784, 1033 closes https://github.com/official-stockfish/Stockfish/pull/2626 Bench: 4966867 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 3 +++ src/pawns.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2698c813..cd535d88 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -695,7 +695,7 @@ namespace { behind |= shift(behind); int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); - int weight = pos.count(Us) - 1; + int weight = pos.count(Us) - 2 + pe->blocked_count() / 2; Score score = make_score(bonus * weight * weight / 16, 0); if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index 63bc596f..7c4eda0f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -86,6 +86,7 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); + e->blockedCount[Us] = 0; // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -105,6 +106,8 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); + e->blockedCount[Us] += bool(blocked); + // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. backward = !(neighbours & forward_ranks_bb(Them, s + Up)) diff --git a/src/pawns.h b/src/pawns.h index bd17618f..41a88c6f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -38,6 +38,7 @@ struct Entry { Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); } + int blocked_count() const { return blockedCount[WHITE] + blockedCount[BLACK]; } template Score king_safety(const Position& pos) { @@ -59,6 +60,7 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; + int blockedCount[COLOR_NB]; }; typedef HashTable Table; From de9fc53af57d1620bb913c357630e724c7ea186b Mon Sep 17 00:00:00 2001 From: silversolver1 <61594747+silversolver1@users.noreply.github.com> Date: Sun, 12 Apr 2020 22:23:04 -0500 Subject: [PATCH 233/281] Removes evasionPrunable STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 25656 W: 4979 L: 4826 D: 15851 Ptnml(0-2): 414, 2971, 5964, 3006, 473 https://tests.stockfishchess.org/tests/view/5e93dbd72cb65b3059c33819 LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 43732 W: 5656 L: 5593 D: 32483 Ptnml(0-2): 324, 4072, 13009, 4139, 322 https://tests.stockfishchess.org/tests/view/5e93e37c2cb65b3059c33825 closes https://github.com/official-stockfish/Stockfish/pull/2627 Bench: 4702195 --- src/search.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4073f21d..76011840 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1398,7 +1398,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion, evasionPrunable; + bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion; int moveCount; if (PvNode) @@ -1527,14 +1527,8 @@ moves_loop: // When in check, search starts from here } } - // Detect non-capture evasions that are candidates to be pruned - evasionPrunable = inCheck - && (depth != 0 || moveCount > 2) - && bestValue > VALUE_TB_LOSS_IN_MAX_PLY - && !pos.capture(move); - // Don't search moves with negative SEE values - if ( (!inCheck || evasionPrunable) && !pos.see_ge(move)) + if ( !inCheck && !pos.see_ge(move)) continue; // Speculative prefetch as early as possible From 5c58f6712667076babe9ebaac1689436721c42be Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Mon, 13 Apr 2020 23:01:38 +0200 Subject: [PATCH 234/281] less bonus for blocked connected pawn Use less bonus for blocked connected pawns so closed positions are less worth. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 60004 W: 11904 L: 11619 D: 36481 Ptnml(0-2): 1066, 7083, 13535, 7136, 1182 https://tests.stockfishchess.org/tests/view/5e941a8063d105aebbab23e3 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 36606 W: 4831 L: 4556 D: 27219 Ptnml(0-2): 252, 3353, 10872, 3520, 306 https://tests.stockfishchess.org/tests/view/5e9444b963d105aebbab2427 closes https://github.com/official-stockfish/Stockfish/pull/2629 Bench: 4961260 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7c4eda0f..a2063a8f 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -138,7 +138,7 @@ namespace { // Score this pawn if (support | phalanx) { - int v = Connected[r] * (2 + bool(phalanx) - bool(opposed)) + int v = Connected[r] * (4 + 2 * bool(phalanx) - 2 * bool(opposed) - bool(blocked)) / 2 + 21 * popcount(support); score += make_score(v, v * (r - 2) / 4); From ca4e399ea6d88f8f71c8fd692566223496b10f78 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 15 Apr 2020 04:13:50 +0300 Subject: [PATCH 235/281] Space bonus and number of blocked pawns This patch refines the recently introduced interaction between the space bonus and the number of blocked pawns in a position. * pawns count as blocked also if their push square is attacked by 2 enemy pawns; * overall dependence is stronger as well as offset; * bonus increase is capped at 9 blocked pawns in position; passed STC https://tests.stockfishchess.org/tests/view/5e94560663d105aebbab243d LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 29500 W: 5842 L: 5603 D: 18055 Ptnml(0-2): 504, 3443, 6677, 3562, 564 passed LTC https://tests.stockfishchess.org/tests/view/5e95b383c2aaa99f75d1a14d LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 63504 W: 8329 L: 7974 D: 47201 Ptnml(0-2): 492, 5848, 18720, 6197, 495 closes https://github.com/official-stockfish/Stockfish/pull/2631 bench 4956028 --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cd535d88..8feedfeb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -695,7 +695,7 @@ namespace { behind |= shift(behind); int bonus = popcount(safe) + popcount(behind & safe & ~attackedBy[Them][ALL_PIECES]); - int weight = pos.count(Us) - 2 + pe->blocked_count() / 2; + int weight = pos.count(Us) - 3 + std::min(pe->blocked_count(), 9); Score score = make_score(bonus * weight * weight / 16, 0); if (T) diff --git a/src/pawns.cpp b/src/pawns.cpp index a2063a8f..75e6ad7a 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -106,7 +106,7 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount[Us] += bool(blocked); + e->blockedCount[Us] += blocked || more_than_one(leverPush); // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. From 0e51ff1074d5a66495a21990bd1826a8d06447e8 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 15 Apr 2020 18:22:02 +0300 Subject: [PATCH 236/281] Don't attempt probcut if ttMove is not good enough. This idea is loosely based on xoroshiro idea about raisedBeta and ttmoves. If our ttmove have low enough ttvalue and is deep enough (deeper than our probcut depth) it makes little sense to try probcut moves, since the ttMove already more or less failed to produce one according to transposition table. passed STC https://tests.stockfishchess.org/tests/view/5e9673ddc2718dee3c822920 LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 72148 W: 14038 L: 13741 D: 44369 Ptnml(0-2): 1274, 8326, 16615, 8547, 1312 passed LTC https://tests.stockfishchess.org/tests/view/5e96b378c2718dee3c8229bf LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 89054 W: 11418 L: 10996 D: 66640 Ptnml(0-2): 623, 8113, 26643, 8515, 633 closes https://github.com/official-stockfish/Stockfish/pull/2632 bench 4952731 --- src/search.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 76011840..dae1e23c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -906,8 +906,12 @@ namespace { MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &captureHistory); int probCutCount = 0; - while ( (move = mp.next_move()) != MOVE_NONE - && probCutCount < 2 + 2 * cutNode) + while ( (move = mp.next_move()) != MOVE_NONE + && probCutCount < 2 + 2 * cutNode + && !( move == ttMove + && (tte->bound() & BOUND_LOWER) + && tte->depth() >= depth - 4 + && ttValue < raisedBeta)) if (move != excludedMove && pos.legal(move)) { assert(pos.capture_or_promotion(move)); From d87adcc0062fa9707ba2b0b6ce3369a4ab391b6d Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 16 Apr 2020 01:33:48 +0300 Subject: [PATCH 237/281] Queen and Rook Tuning Tuning for multiple parameters for Queen and Rook. passed STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 62790 W: 12033 L: 11754 D: 39003 Ptnml(0-2): 1058, 7186, 14666, 7389, 1096 https://tests.stockfishchess.org/tests/view/5e978c66c9ada107a0370d87 passed LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 89780 W: 11460 L: 11036 D: 67284 Ptnml(0-2): 624, 8151, 26951, 8505, 659 https://tests.stockfishchess.org/tests/view/5e979aaec9ada107a0370d93 closes https://github.com/official-stockfish/Stockfish/pull/2634 Bench: 5111578 --- src/evaluate.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8feedfeb..7eafacf8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -82,7 +82,7 @@ namespace { // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 1080; + constexpr int RookSafeCheck = 1078; constexpr int BishopSafeCheck = 635; constexpr int KnightSafeCheck = 790; @@ -96,19 +96,19 @@ namespace { { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, - { S(-58,-76), S(-27,-18), S(-15, 28), S(-10, 55), S( -5, 69), S( -2, 82), // Rook - S( 9,112), S( 16,118), S( 30,132), S( 29,142), S( 32,155), S( 38,165), - S( 46,166), S( 48,169), S( 58,171) }, - { S(-39,-36), S(-21,-15), S( 3, 8), S( 3, 18), S( 14, 34), S( 22, 54), // Queen - S( 28, 61), S( 41, 73), S( 43, 79), S( 48, 92), S( 56, 94), S( 60,104), - S( 60,113), S( 66,120), S( 67,123), S( 70,126), S( 71,133), S( 73,136), - S( 79,140), S( 88,143), S( 88,148), S( 99,166), S(102,170), S(102,175), - S(106,184), S(109,191), S(113,206), S(116,212) } + { S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook + S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164), + S( 57,168), S( 57,169), S( 62,172) }, + { S(-34,-36), S(-15,-21), S(-10, -1), S(-10, 22), S( 20, 41), S( 23, 56), // Queen + S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100), + S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141), + S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171), + S(110,182), S(114,182), S(114,192), S(116,219) } }; // RookOnFile[semiopen/open] contains bonuses for each rook when there is // no (friendly) pawn on the rook file. - constexpr Score RookOnFile[] = { S(21, 4), S(47, 25) }; + constexpr Score RookOnFile[] = { S(19, 7), S(48, 29) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are @@ -118,7 +118,7 @@ namespace { }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(2, 44), S(36, 71), S(36, 61), S(0, 38), S(51, 38) + S(0, 0), S(3, 46), S(37, 68), S(42, 60), S(0, 38), S(58, 41) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn @@ -132,21 +132,21 @@ namespace { constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); constexpr Score KingProtector = S( 7, 8); - constexpr Score KnightOnQueen = S( 16, 12); + constexpr Score KnightOnQueen = S( 16, 11); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); constexpr Score Outpost = S( 30, 21); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); - constexpr Score RookOnQueenFile = S( 7, 6); + constexpr Score RookOnQueenFile = S( 5, 9); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 52, 10); - constexpr Score WeakQueen = S( 49, 15); - constexpr Score WeakQueenProtection = S( 14, 0); + constexpr Score TrappedRook = S( 55, 13); + constexpr Score WeakQueen = S( 51, 14); + constexpr Score WeakQueenProtection = S( 15, 0); #undef S From 6f35af7ad31d55d0f0918742b60f4e672fc43ccf Mon Sep 17 00:00:00 2001 From: Lolligerhans Date: Thu, 16 Apr 2020 03:56:43 +0200 Subject: [PATCH 238/281] Increase safe check bonus if multiple safe checks Add 50% "safe checks" bonus when there are multiple safe checks from the same piece type. LTC LLR: 2.97 (-2.94,2.94) {0.25,1.75} Total: 128184 W: 16491 L: 15954 D: 95739 Ptnml(0-2): 884, 11793, 38267, 12198, 950 https://tests.stockfishchess.org/tests/view/5e97d1b6c9ada107a0370e03 STC LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 19022 W: 3733 L: 3514 D: 11775 Ptnml(0-2): 338, 2103, 4414, 2314, 342 https://tests.stockfishchess.org/tests/view/5e97c377c9ada107a0370ddf closes https://github.com/official-stockfish/Stockfish/pull/2636 Bench: 5057329 --- src/evaluate.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7eafacf8..0b1956f1 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -398,9 +398,9 @@ namespace { // Enemy rooks checks rookChecks = b1 & safe & attackedBy[Them][ROOK]; - if (rookChecks) - kingDanger += RookSafeCheck; + kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 3/2 + : RookSafeCheck; else unsafeChecks |= b1 & attackedBy[Them][ROOK]; @@ -411,9 +411,9 @@ namespace { & safe & ~attackedBy[Us][QUEEN] & ~rookChecks; - if (queenChecks) - kingDanger += QueenSafeCheck; + kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2 + : QueenSafeCheck; // Enemy bishops checks: we count them only if they are from squares from // which we can't give a queen check, because queen checks are more valuable. @@ -421,17 +421,17 @@ namespace { & attackedBy[Them][BISHOP] & safe & ~queenChecks; - if (bishopChecks) - kingDanger += BishopSafeCheck; + kingDanger += more_than_one(bishopChecks) ? BishopSafeCheck * 3/2 + : BishopSafeCheck; else unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; - if (knightChecks & safe) - kingDanger += KnightSafeCheck; + kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 3/2 + : KnightSafeCheck; else unsafeChecks |= knightChecks; From ecac132bca23c6dfcc697cc3cd069939bc168ed4 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 16 Apr 2020 18:10:44 +0100 Subject: [PATCH 239/281] Scale factor in opposite-color bishop endings This change varies the scale factor with the total number of pieces and pawns on the strongSide. STC : LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 150920 W: 28828 L: 28422 D: 93670 +0.65 Elo Ptnml(0-2): 2507, 17548, 35030, 17782, 2593 https://tests.stockfishchess.org/tests/view/5e983eb2c00499c5410f4951 LTC : LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 69238 W: 8810 L: 8446 D: 51982 +1.58 Elo Ptnml(0-2): 451, 6276, 20879, 6484, 529 https://tests.stockfishchess.org/tests/view/5e985b27c00499c5410f4987 closes https://github.com/official-stockfish/Stockfish/pull/2637 Bench 4821332 --- src/evaluate.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0b1956f1..cbcebd04 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -761,11 +761,16 @@ namespace { // If scale is not already specific, scale down the endgame via general heuristics if (sf == SCALE_FACTOR_NORMAL) { - if ( pos.opposite_bishops() - && pos.non_pawn_material() == 2 * BishopValueMg) - sf = 22; + if (pos.opposite_bishops()) + { + if ( pos.non_pawn_material(WHITE) == BishopValueMg + && pos.non_pawn_material(BLACK) == BishopValueMg) + sf = 22; + else + sf = 22 + 3 * pos.count(strongSide); + } else - sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::min(sf, 36 + 7 * pos.count(strongSide)); sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } From 345b2d153a8092cff93ad660c9d107cd66fda43b Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 15 Apr 2020 23:34:18 +0200 Subject: [PATCH 240/281] Remove one condition in probcut TTmove skipping the removed condition appears illogical and is not needed. passed STC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 80418 W: 15217 L: 15144 D: 50057 Ptnml(0-2): 1341, 9399, 18679, 9426, 1364 https://tests.stockfishchess.org/tests/view/5e977eb5c9ada107a0370d6b passed LTC: LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 49878 W: 6299 L: 6247 D: 37332 Ptnml(0-2): 327, 4677, 14897, 4693, 345 https://tests.stockfishchess.org/tests/view/5e97e07dc9ada107a0370e53 closes https://github.com/official-stockfish/Stockfish/pull/2638 Bench: 4958027 --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index dae1e23c..fd690dcd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -909,7 +909,6 @@ namespace { while ( (move = mp.next_move()) != MOVE_NONE && probCutCount < 2 + 2 * cutNode && !( move == ttMove - && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 4 && ttValue < raisedBeta)) if (move != excludedMove && pos.legal(move)) From bde1506ba56ae566ac4e797e642017fe386f6425 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 16 Apr 2020 23:12:43 -0600 Subject: [PATCH 241/281] Simplify minPawnDistance This is a functional simplification which fixes an awkward numerical cliff. With master king_safety, no pawns is scored higher than pawn(s) that is/are far from the king. This may motivate SF to throw away pawns to increase king safety. With this patch, there is a consistent value for minPawnDistance where losing a pawn never increases king safety. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 45548 W: 8624 L: 8525 D: 28399 Ptnml(0-2): 592, 4937, 11587, 5096, 562 https://tests.stockfishchess.org/tests/view/5e98ced630be947a14e9ddc5 LTC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 42084 W: 5292 L: 5242 D: 31550 Ptnml(0-2): 193, 3703, 13252, 3649, 245 https://tests.stockfishchess.org/tests/view/5e98e22e30be947a14e9de07 closes https://github.com/official-stockfish/Stockfish/pull/2639 bench 4600292 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 75e6ad7a..066146e2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -244,7 +244,7 @@ Score Entry::do_king_safety(const Position& pos) { // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); - int minPawnDist = pawns ? 8 : 0; + int minPawnDist = 6; if (pawns & PseudoAttacks[KING][ksq]) minPawnDist = 1; From 221893bf679f70098e6f751fded2fe843471c6be Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 18 Apr 2020 03:28:47 +0300 Subject: [PATCH 242/281] Apply multicut pruning more often This patch increases number of nodes where we produce multicut cutoffs. The idea is that if our ttMove failed to produce a singular extension but ttValue is greater than beta we can afford to do one more reduced search near beta excluding ttMove to see if it will produce a fail high - and if it does so produce muticut by analogy to existing logic. passed STC https://tests.stockfishchess.org/tests/view/5e9a162b5b664cdba0ce6e28 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 58238 W: 11192 L: 10917 D: 36129 Ptnml(0-2): 1007, 6704, 13442, 6939, 1027 passed LTC https://tests.stockfishchess.org/tests/view/5e9a1e845b664cdba0ce7411 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 137852 W: 17460 L: 16899 D: 103493 Ptnml(0-2): 916, 12610, 41383, 13031, 986 closes https://github.com/official-stockfish/Stockfish/pull/2640 bench 4881443 --- src/search.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index fd690dcd..a7e90a08 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1091,6 +1091,18 @@ moves_loop: // When in check, search starts from here // a soft bound. else if (singularBeta >= beta) return singularBeta; + + // If the eval of ttMove is greater than beta we try also if there is an other move that + // pushes it over beta, if so also produce a cutoff + else if (ttValue >= beta) + { + ss->excludedMove = move; + value = search(pos, ss, beta - 1, beta, (depth + 3) / 2, cutNode); + ss->excludedMove = MOVE_NONE; + + if (value >= beta) + return beta; + } } // Check extension (~2 Elo) From bb5589b829b79d7c60a820d4b1634dccbc4bbb3f Mon Sep 17 00:00:00 2001 From: pb00067 Date: Tue, 21 Apr 2020 20:55:41 +0200 Subject: [PATCH 243/281] continuation histories when in check If in check, don't write to continuation histories ss-4, ss-6. Adding inCheck to the stack was needed, and might be useful for future patches. Passed STC: https://tests.stockfishchess.org/tests/view/5e9ee24acaaff5d60a50b812 LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 61774 W: 11725 L: 11449 D: 38600 Ptnml(0-2): 971, 7211, 14322, 7337, 1046 Passed LTC: https://tests.stockfishchess.org/tests/view/5e9eecb7caaff5d60a50b831 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 250822 W: 32067 L: 31179 D: 187576 Ptnml(0-2): 1745, 23126, 74824, 23928, 1788 closes https://github.com/official-stockfish/Stockfish/pull/2645 bench: 4808463 --- src/search.cpp | 40 ++++++++++++++++++++++------------------ src/search.h | 1 + 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index a7e90a08..a3d4a329 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -626,14 +626,14 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, formerPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool ttHit, ttPv, formerPv, givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; int moveCount, captureCount, quietCount; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); - inCheck = pos.checkers(); + ss->inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); moveCount = captureCount = quietCount = ss->moveCount = 0; @@ -654,7 +654,7 @@ namespace { if ( Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : value_draw(pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score @@ -793,7 +793,7 @@ namespace { CapturePieceToHistory& captureHistory = thisThread->captureHistory; // Step 6. Static evaluation of the position - if (inCheck) + if (ss->inCheck) { ss->staticEval = eval = VALUE_NONE; improving = false; @@ -920,7 +920,7 @@ namespace { probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [pos.moved_piece(move)] [to_sq(move)]; @@ -1030,7 +1030,7 @@ moves_loop: // When in check, search starts from here // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 - && !inCheck + && !ss->inCheck && ss->staticEval + 235 + 172 * lmrDepth <= alpha && (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] @@ -1146,7 +1146,7 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [movedPiece] [to_sq(move)]; @@ -1365,11 +1365,11 @@ moves_loop: // When in check, search starts from here // must be a mate or a stalemate. If we are in a singular extension search then // return a fail low score. - assert(moveCount || !inCheck || excludedMove || !MoveList(pos).size()); + assert(moveCount || !ss->inCheck || excludedMove || !MoveList(pos).size()); if (!moveCount) bestValue = excludedMove ? alpha - : inCheck ? mated_in(ss->ply) : VALUE_DRAW; + : ss->inCheck ? mated_in(ss->ply) : VALUE_DRAW; else if (bestMove) update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, @@ -1413,7 +1413,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion; + bool ttHit, pvHit, givesCheck, captureOrPromotion; int moveCount; if (PvNode) @@ -1426,20 +1426,20 @@ moves_loop: // When in check, search starts from here Thread* thisThread = pos.this_thread(); (ss+1)->ply = ss->ply + 1; bestMove = MOVE_NONE; - inCheck = pos.checkers(); + ss->inCheck = pos.checkers(); moveCount = 0; // Check for an immediate draw or maximum ply reached if ( pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : VALUE_DRAW; + return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : VALUE_DRAW; assert(0 <= ss->ply && ss->ply < MAX_PLY); // Decide whether or not to include checks: this fixes also the type of // TT entry depth that we are going to use. Note that in qsearch we use // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. - ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS + ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS; // Transposition table lookup posKey = pos.key(); @@ -1457,7 +1457,7 @@ moves_loop: // When in check, search starts from here return ttValue; // Evaluate the position statically - if (inCheck) + if (ss->inCheck) { ss->staticEval = VALUE_NONE; bestValue = futilityBase = -VALUE_INFINITE; @@ -1520,7 +1520,7 @@ moves_loop: // When in check, search starts from here moveCount++; // Futility pruning - if ( !inCheck + if ( !ss->inCheck && !givesCheck && futilityBase > -VALUE_KNOWN_WIN && !pos.advanced_pawn_push(move)) @@ -1543,7 +1543,7 @@ moves_loop: // When in check, search starts from here } // Don't search moves with negative SEE values - if ( !inCheck && !pos.see_ge(move)) + if ( !ss->inCheck && !pos.see_ge(move)) continue; // Speculative prefetch as early as possible @@ -1557,7 +1557,7 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck] + ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] [captureOrPromotion] [pos.moved_piece(move)] [to_sq(move)]; @@ -1591,7 +1591,7 @@ moves_loop: // When in check, search starts from here // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. - if (inCheck && bestValue == -VALUE_INFINITE) + if (ss->inCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, @@ -1710,8 +1710,12 @@ moves_loop: // When in check, search starts from here void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { for (int i : {1, 2, 4, 6}) + { + if (ss->inCheck && i > 2) + break; if (is_ok((ss-i)->currentMove)) (*(ss-i)->continuationHistory)[pc][to] << bonus; + } } diff --git a/src/search.h b/src/search.h index a900d094..1653ce92 100644 --- a/src/search.h +++ b/src/search.h @@ -49,6 +49,7 @@ struct Stack { Value staticEval; int statScore; int moveCount; + bool inCheck; }; From 4776dc0e126ed311f10f34bfa058a6c86e9d3ef1 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Wed, 29 Apr 2020 02:40:16 +0300 Subject: [PATCH 244/281] Introduce futility pruning for captures The idea is somewhat similar to futility pruning for quiet moves - if a late enough capture doesn't give check and the static eval is much lower than alpha we can almost safely assume that this capture wouldn't be a good move. passed STC https://tests.stockfishchess.org/tests/view/5ea8544b53a4548a0348ee5b LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 236040 W: 44420 L: 43894 D: 147726 Ptnml(0-2): 3830, 27202, 55496, 27596, 3896 passed LTC https://tests.stockfishchess.org/tests/view/5ea87c842141237a731f0c7d LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 81336 W: 10429 L: 10028 D: 60879 Ptnml(0-2): 589, 7356, 24404, 7703, 616 closes https://github.com/official-stockfish/Stockfish/pull/2651 bench 4405247 --- src/search.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index a3d4a329..55c520a4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1049,6 +1049,13 @@ moves_loop: // When in check, search starts from here && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) continue; + // Futility pruning for captures + if ( !givesCheck + && lmrDepth < 6 + && !ss->inCheck + && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) + continue; + // See based pruning if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) continue; From 353e20674b2019094059caaa3567e9a44abe9cd1 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 29 Apr 2020 17:39:25 +0200 Subject: [PATCH 245/281] Small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2628 No functional change --- src/evaluate.cpp | 6 ++++-- src/pawns.cpp | 4 ++-- src/pawns.h | 4 ++-- src/position.cpp | 2 +- src/position.h | 2 +- src/search.cpp | 14 +++++++------- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cbcebd04..9d7728c4 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -740,7 +740,7 @@ namespace { // Now apply the bonus: note that we find the attacking side by extracting the // sign of the midgame or endgame values, and that we carefully cap the bonus // so that the midgame and endgame scores do not change sign after the bonus. - int u = ((mg > 0) - (mg < 0)) * std::max(std::min(complexity + 50, 0), -abs(mg)); + int u = ((mg > 0) - (mg < 0)) * Utility::clamp(complexity + 50, -abs(mg), 0); int v = ((eg > 0) - (eg < 0)) * std::max(complexity, -abs(eg)); if (T) @@ -815,7 +815,8 @@ namespace { initialize(); initialize(); - // Pieces should be evaluated first (populate attack tables) + // Pieces evaluated first (also populates attackedBy, attackedBy2). + // Note that the order of evaluation of the terms is left unspecified score += pieces() - pieces() + pieces() - pieces() + pieces() - pieces() @@ -823,6 +824,7 @@ namespace { score += mobility[WHITE] - mobility[BLACK]; + // More complex interactions that require fully populated attack bitboards score += king< WHITE>() - king< BLACK>() + threats() - threats() + passed< WHITE>() - passed< BLACK>() diff --git a/src/pawns.cpp b/src/pawns.cpp index 066146e2..7b266e77 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -86,7 +86,6 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); - e->blockedCount[Us] = 0; // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -106,7 +105,7 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount[Us] += blocked || more_than_one(leverPush); + e->blockedCount += blocked || more_than_one(leverPush); // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. @@ -178,6 +177,7 @@ Entry* probe(const Position& pos) { return e; e->key = key; + e->blockedCount = 0; e->scores[WHITE] = evaluate(pos, e); e->scores[BLACK] = evaluate(pos, e); diff --git a/src/pawns.h b/src/pawns.h index 41a88c6f..a3284a0f 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -38,7 +38,7 @@ struct Entry { Bitboard passed_pawns(Color c) const { return passedPawns[c]; } Bitboard pawn_attacks_span(Color c) const { return pawnAttacksSpan[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); } - int blocked_count() const { return blockedCount[WHITE] + blockedCount[BLACK]; } + int blocked_count() const { return blockedCount; } template Score king_safety(const Position& pos) { @@ -60,7 +60,7 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; - int blockedCount[COLOR_NB]; + int blockedCount; }; typedef HashTable Table; diff --git a/src/position.cpp b/src/position.cpp index 6bbb7914..40ebb959 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -306,7 +306,7 @@ void Position::set_castling_right(Color c, Square rfrom) { Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) - & ~(square_bb(kfrom) | rfrom); + & ~(kfrom | rfrom); } diff --git a/src/position.h b/src/position.h index f79c5463..34a6abc3 100644 --- a/src/position.h +++ b/src/position.h @@ -269,7 +269,7 @@ inline bool Position::can_castle(CastlingRights cr) const { } inline int Position::castling_rights(Color c) const { - return st->castlingRights & (c == WHITE ? WHITE_CASTLING : BLACK_CASTLING); + return c & CastlingRights(st->castlingRights); } inline bool Position::castling_impeded(CastlingRights cr) const { diff --git a/src/search.cpp b/src/search.cpp index 55c520a4..7f29f771 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -61,8 +61,8 @@ namespace { // Different node types, used as a template parameter enum NodeType { NonPV, PV }; - constexpr uint64_t ttHitAverageWindow = 4096; - constexpr uint64_t ttHitAverageResolution = 1024; + constexpr uint64_t TtHitAverageWindow = 4096; + constexpr uint64_t TtHitAverageResolution = 1024; // Razor and futility margins constexpr int RazorMargin = 531; @@ -378,7 +378,7 @@ void Thread::search() { multiPV = std::max(multiPV, (size_t)4); multiPV = std::min(multiPV, rootMoves.size()); - ttHitAverage = ttHitAverageWindow * ttHitAverageResolution / 2; + ttHitAverage = TtHitAverageWindow * TtHitAverageResolution / 2; int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns @@ -702,8 +702,8 @@ namespace { thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); // thisThread->ttHitAverage can be used to approximate the running average of ttHit - thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow - + ttHitAverageResolution * ttHit; + thisThread->ttHitAverage = (TtHitAverageWindow - 1) * thisThread->ttHitAverage / TtHitAverageWindow + + TtHitAverageResolution * ttHit; // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -1170,12 +1170,12 @@ moves_loop: // When in check, search starts from here || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha || cutNode - || thisThread->ttHitAverage < 375 * ttHitAverageResolution * ttHitAverageWindow / 1024)) + || thisThread->ttHitAverage < 375 * TtHitAverageResolution * TtHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); // Decrease reduction if the ttHit running average is large - if (thisThread->ttHitAverage > 500 * ttHitAverageResolution * ttHitAverageWindow / 1024) + if (thisThread->ttHitAverage > 500 * TtHitAverageResolution * TtHitAverageWindow / 1024) r--; // Reduction if other threads are searching this position. From 7f8166db89120960effa2ddda1a25188e5ab95b8 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Sat, 25 Apr 2020 15:55:35 -0400 Subject: [PATCH 246/281] Tuned safe checks and minor piece king protectors A combination of terms related to king safety one tuned safe check weights, the other tuned knight and bishop king protector weights separately with some compensation in the high outpost bonuses given to the minor pieces. passed STC LLR: 2.95 (-2.94,2.94) {-0.50,1.50} Total: 39892 W: 7594 L: 7350 D: 24948 Ptnml(0-2): 643, 4559, 9314, 4771, 659 https://tests.stockfishchess.org/tests/view/5ea49635b908f6dd28f34b82 passed LTC LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 104934 W: 13300 L: 12834 D: 78800 Ptnml(0-2): 697, 9571, 31514, 9939, 746 https://tests.stockfishchess.org/tests/view/5ea4abf6b908f6dd28f34bcb closes https://github.com/official-stockfish/Stockfish/pull/2649 Bench 4800754 --- AUTHORS | 1 + src/evaluate.cpp | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/AUTHORS b/AUTHORS index 79eb98a0..9fceebf7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,6 +42,7 @@ Eelco de Groot (KingDefender) Elvin Liu (solarlight2) erbsenzaehler Ernesto Gatti +Linmiao Xu (linrock) Fabian Beuke (madnight) Fabian Fichter (ianfab) fanon diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9d7728c4..874faa6b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -81,10 +81,10 @@ namespace { constexpr int KingAttackWeights[PIECE_TYPE_NB] = { 0, 0, 81, 52, 44, 10 }; // Penalties for enemy's safe checks - constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 1078; - constexpr int BishopSafeCheck = 635; - constexpr int KnightSafeCheck = 790; + constexpr int QueenSafeCheck = 772; + constexpr int RookSafeCheck = 1084; + constexpr int BishopSafeCheck = 645; + constexpr int KnightSafeCheck = 792; #define S(mg, eg) make_score(mg, eg) @@ -131,11 +131,14 @@ namespace { constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); - constexpr Score KingProtector = S( 7, 8); + constexpr Score BishopKingProtector = S( 6, 9); + constexpr Score KnightKingProtector = S( 8, 9); constexpr Score KnightOnQueen = S( 16, 11); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score Outpost = S( 30, 21); + constexpr Score KnightOutpost = S( 56, 36); + constexpr Score BishopOutpost = S( 30, 23); + constexpr Score ReachableOutpost = S( 31, 22); constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); @@ -293,17 +296,17 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & attackedBy[Us][PAWN] & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost * (Pt == KNIGHT ? 2 : 1); - + score += (Pt == KNIGHT) ? KnightOutpost : BishopOutpost; else if (Pt == KNIGHT && bb & b & ~pos.pieces(Us)) - score += Outpost; + score += ReachableOutpost; // Bonus for a knight or bishop shielded by pawn if (shift(pos.pieces(PAWN)) & s) score += MinorBehindPawn; // Penalty if the piece is far from the king - score -= KingProtector * distance(pos.square(Us), s); + score -= (Pt == KNIGHT ? KnightKingProtector + : BishopKingProtector) * distance(pos.square(Us), s); if (Pt == BISHOP) { @@ -399,7 +402,7 @@ namespace { // Enemy rooks checks rookChecks = b1 & safe & attackedBy[Them][ROOK]; if (rookChecks) - kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 3/2 + kingDanger += more_than_one(rookChecks) ? RookSafeCheck * 175/100 : RookSafeCheck; else unsafeChecks |= b1 & attackedBy[Them][ROOK]; @@ -412,7 +415,7 @@ namespace { & ~attackedBy[Us][QUEEN] & ~rookChecks; if (queenChecks) - kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 3/2 + kingDanger += more_than_one(queenChecks) ? QueenSafeCheck * 145/100 : QueenSafeCheck; // Enemy bishops checks: we count them only if they are from squares from @@ -430,7 +433,7 @@ namespace { // Enemy knights checks knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; if (knightChecks & safe) - kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 3/2 + kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100 : KnightSafeCheck; else unsafeChecks |= knightChecks; From eb4a124b8859a6029b61f403e0a9415fa748e4bd Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Sat, 2 May 2020 16:45:20 +0300 Subject: [PATCH 247/281] Refine scale factor of opposite colored bishops endgames. This patch makes it dependant on the count of passed pawns of the strong side instead of 22/64 in every case. passed STC https://tests.stockfishchess.org/tests/view/5ead60966ffeed51f6e32591 LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 50336 W: 9473 L: 9241 D: 31622 Ptnml(0-2): 570, 5371, 13098, 5515, 614 passed LTC https://tests.stockfishchess.org/tests/view/5ead6d3b6ffeed51f6e325b0 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 21952 W: 2810 L: 2603 D: 16539 Ptnml(0-2): 101, 1791, 7005, 1958, 121 closes https://github.com/official-stockfish/Stockfish/pull/2658 bench 4247490 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 874faa6b..67e05921 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -768,7 +768,7 @@ namespace { { if ( pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = 22; + sf = 18 + 4 * popcount(pe->passed_pawns(strongSide)); else sf = 22 + 3 * pos.count(strongSide); } From c527c3ad44f7465c79cef93f1e8cfebd998dc627 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 4 Apr 2015 08:54:15 +0200 Subject: [PATCH 248/281] Fishtest Tuning Framework The purpose of the code is to allow developers to easily and flexibly setup SF for a tuning session. Mainly you have just to remove 'const' qualifiers from the variables you want to tune and flag them for tuning, so if you have: int myKing = 10; Score myBonus = S(5, 15); Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } }; and at the end of the update you may want to call a post update function: void my_post_update(); If instead of default Option's min-max values, you prefer your custom ones, returned by: std::pair my_range(int value) Or you jus want to set the range directly, you can simply add below: TUNE(SetRange(my_range), myKing, SetRange(-200, 200), myBonus, myValue, my_post_update); And all the magic happens :-) At startup all the parameters are printed in a format suitable to be copy-pasted in fishtest. In case the post update function is slow and you have many parameters to tune, you can add: UPDATE_ON_LAST(); And the values update, including post update function call, will be done only once, after the engine receives the last UCI option. The last option is the one defined and created as the last one, so this assumes that the GUI sends the options in the same order in which have been defined. closes https://github.com/official-stockfish/Stockfish/pull/2654 No functional change. --- src/Makefile | 2 +- src/main.cpp | 1 + src/tune.cpp | 146 ++++++++++++++++++++++++++++++++++++++ src/tune.h | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/types.h | 2 + 5 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 src/tune.cpp create mode 100644 src/tune.h diff --git a/src/Makefile b/src/Makefile index 15ad6353..0998a551 100644 --- a/src/Makefile +++ b/src/Makefile @@ -38,7 +38,7 @@ PGOBENCH = ./$(EXE) bench ### Object files OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \ material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \ - search.o thread.o timeman.o tt.o uci.o ucioption.o syzygy/tbprobe.o + search.o thread.o timeman.o tt.o uci.o ucioption.o tune.o syzygy/tbprobe.o ### Establish the operating system name KERNEL = $(shell uname -s) diff --git a/src/main.cpp b/src/main.cpp index 182cf105..6eeda66d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ int main(int argc, char* argv[]) { std::cout << engine_info() << std::endl; UCI::init(Options); + Tune::init(); PSQT::init(); Bitboards::init(); Position::init(); diff --git a/src/tune.cpp b/src/tune.cpp new file mode 100644 index 00000000..fe61151f --- /dev/null +++ b/src/tune.cpp @@ -0,0 +1,146 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2015-2020 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "types.h" +#include "misc.h" +#include "uci.h" + +using std::string; + +bool Tune::update_on_last; +const UCI::Option* LastOption = nullptr; +BoolConditions Conditions; +static std::map TuneResults; + +string Tune::next(string& names, bool pop) { + + string name; + + do { + string token = names.substr(0, names.find(',')); + + if (pop) + names.erase(0, token.size() + 1); + + std::stringstream ws(token); + name += (ws >> token, token); // Remove trailing whitespace + + } while ( std::count(name.begin(), name.end(), '(') + - std::count(name.begin(), name.end(), ')')); + + return name; +} + +static void on_tune(const UCI::Option& o) { + + if (!Tune::update_on_last || LastOption == &o) + Tune::read_options(); +} + +static void make_option(const string& n, int v, const SetRange& r) { + + // Do not generate option when there is nothing to tune (ie. min = max) + if (r(v).first == r(v).second) + return; + + if (TuneResults.count(n)) + v = TuneResults[n]; + + Options[n] << UCI::Option(v, r(v).first, r(v).second, on_tune); + LastOption = &Options[n]; + + // Print formatted parameters, ready to be copy-pasted in fishtest + std::cout << n << "," + << v << "," + << r(v).first << "," << r(v).second << "," + << (r(v).second - r(v).first) / 20.0 << "," + << "0.0020" + << std::endl; +} + +template<> void Tune::Entry::init_option() { make_option(name, value, range); } + +template<> void Tune::Entry::read_option() { + if (Options.count(name)) + value = Options[name]; +} + +template<> void Tune::Entry::init_option() { make_option(name, value, range); } + +template<> void Tune::Entry::read_option() { + if (Options.count(name)) + value = Value(int(Options[name])); +} + +template<> void Tune::Entry::init_option() { + make_option("m" + name, mg_value(value), range); + make_option("e" + name, eg_value(value), range); +} + +template<> void Tune::Entry::read_option() { + if (Options.count("m" + name)) + value = make_score(Options["m" + name], eg_value(value)); + + if (Options.count("e" + name)) + value = make_score(mg_value(value), Options["e" + name]); +} + +// Instead of a variable here we have a PostUpdate function: just call it +template<> void Tune::Entry::init_option() {} +template<> void Tune::Entry::read_option() { value(); } + + +// Set binary conditions according to a probability that depends +// on the corresponding parameter value. + +void BoolConditions::set() { + + static PRNG rng(now()); + static bool startup = true; // To workaround fishtest bench + + for (size_t i = 0; i < binary.size(); i++) + binary[i] = !startup && (values[i] + int(rng.rand() % variance) > threshold); + + startup = false; + + for (size_t i = 0; i < binary.size(); i++) + sync_cout << binary[i] << sync_endl; +} + + +// Init options with tuning session results instead of default values. Useful to +// get correct bench signature after a tuning session or to test tuned values. +// Just copy fishtest tuning results in a result.txt file and extract the +// values with: +// +// cat results.txt | sed 's/^param: \([^,]*\), best: \([^,]*\).*/ TuneResults["\1"] = int(round(\2));/' +// +// Then paste the output below, as the function body + +#include + +void Tune::read_results() { + + /* ...insert your values here... */ +} diff --git a/src/tune.h b/src/tune.h new file mode 100644 index 00000000..27c3f961 --- /dev/null +++ b/src/tune.h @@ -0,0 +1,195 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008-2017 Marco Costalba, Joona Kiiski, Tord Romstad + Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef TUNE_H_INCLUDED +#define TUNE_H_INCLUDED + +#include +#include +#include +#include + +typedef std::pair Range; // Option's min-max values +typedef Range (RangeFun) (int); + +// Default Range function, to calculate Option's min-max values +inline Range default_range(int v) { + return v > 0 ? Range(0, 2 * v) : Range(2 * v, 0); +} + +struct SetRange { + explicit SetRange(RangeFun f) : fun(f) {} + SetRange(int min, int max) : fun(nullptr), range(min, max) {} + Range operator()(int v) const { return fun ? fun(v) : range; } + + RangeFun* fun; + Range range; +}; + +#define SetDefaultRange SetRange(default_range) + + +/// BoolConditions struct is used to tune boolean conditions in the +/// code by toggling them on/off according to a probability that +/// depends on the value of a tuned integer parameter: for high +/// values of the parameter condition is always disabled, for low +/// values is always enabled, otherwise it is enabled with a given +/// probability that depnends on the parameter under tuning. + +struct BoolConditions { + void init(size_t size) { values.resize(size, defaultValue), binary.resize(size, 0); } + void set(); + + std::vector binary, values; + int defaultValue = 465, variance = 40, threshold = 500; + SetRange range = SetRange(0, 1000); +}; + +extern BoolConditions Conditions; + +inline void set_conditions() { Conditions.set(); } + + +/// Tune class implements the 'magic' code that makes the setup of a fishtest +/// tuning session as easy as it can be. Mainly you have just to remove const +/// qualifiers from the variables you want to tune and flag them for tuning, so +/// if you have: +/// +/// const Score myScore = S(10, 15); +/// const Value myValue[][2] = { { V(100), V(20) }, { V(7), V(78) } }; +/// +/// If you have a my_post_update() function to run after values have been updated, +/// and a my_range() function to set custom Option's min-max values, then you just +/// remove the 'const' qualifiers and write somewhere below in the file: +/// +/// TUNE(SetRange(my_range), myScore, myValue, my_post_update); +/// +/// You can also set the range directly, and restore the default at the end +/// +/// TUNE(SetRange(-100, 100), myScore, SetDefaultRange); +/// +/// In case update function is slow and you have many parameters, you can add: +/// +/// UPDATE_ON_LAST(); +/// +/// And the values update, including post update function call, will be done only +/// once, after the engine receives the last UCI option, that is the one defined +/// and created as the last one, so the GUI should send the options in the same +/// order in which have been defined. + +class Tune { + + typedef void (PostUpdate) (); // Post-update function + + Tune() { read_results(); } + Tune(const Tune&) = delete; + void operator=(const Tune&) = delete; + void read_results(); + + static Tune& instance() { static Tune t; return t; } // Singleton + + // Use polymorphism to accomodate Entry of different types in the same vector + struct EntryBase { + virtual ~EntryBase() = default; + virtual void init_option() = 0; + virtual void read_option() = 0; + }; + + template + struct Entry : public EntryBase { + + static_assert(!std::is_const::value, "Parameter cannot be const!"); + + static_assert( std::is_same::value + || std::is_same::value + || std::is_same::value + || std::is_same::value, "Parameter type not supported!"); + + Entry(const std::string& n, T& v, const SetRange& r) : name(n), value(v), range(r) {} + void operator=(const Entry&) = delete; // Because 'value' is a reference + void init_option() override; + void read_option() override; + + std::string name; + T& value; + SetRange range; + }; + + // Our facilty to fill the container, each Entry corresponds to a parameter to tune. + // We use variadic templates to deal with an unspecified number of entries, each one + // of a possible different type. + static std::string next(std::string& names, bool pop = true); + + int add(const SetRange&, std::string&&) { return 0; } + + template + int add(const SetRange& range, std::string&& names, T& value, Args&&... args) { + list.push_back(std::unique_ptr(new Entry(next(names), value, range))); + return add(range, std::move(names), args...); + } + + // Template specialization for arrays: recursively handle multi-dimensional arrays + template + int add(const SetRange& range, std::string&& names, T (&value)[N], Args&&... args) { + for (size_t i = 0; i < N; i++) + add(range, next(names, i == N - 1) + "[" + std::to_string(i) + "]", value[i]); + return add(range, std::move(names), args...); + } + + // Template specialization for SetRange + template + int add(const SetRange&, std::string&& names, SetRange& value, Args&&... args) { + return add(value, (next(names), std::move(names)), args...); + } + + // Template specialization for BoolConditions + template + int add(const SetRange& range, std::string&& names, BoolConditions& cond, Args&&... args) { + for (size_t size = cond.values.size(), i = 0; i < size; i++) + add(cond.range, next(names, i == size - 1) + "_" + std::to_string(i), cond.values[i]); + return add(range, std::move(names), args...); + } + + std::vector> list; + +public: + template + static int add(const std::string& names, Args&&... args) { + return instance().add(SetDefaultRange, names.substr(1, names.size() - 2), args...); // Remove trailing parenthesis + } + static void init() { for (auto& e : instance().list) e->init_option(); read_options(); } // Deferred, due to UCI::Options access + static void read_options() { for (auto& e : instance().list) e->read_option(); } + static bool update_on_last; +}; + +// Some macro magic :-) we define a dummy int variable that compiler initializes calling Tune::add() +#define STRINGIFY(x) #x +#define UNIQUE2(x, y) x ## y +#define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__ +#define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__) + +#define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true + +// Some macro to tune toggling of boolean conditions +#define CONDITION(x) (Conditions.binary[__COUNTER__] || (x)) +#define TUNE_CONDITIONS() int UNIQUE(c, __LINE__) = (Conditions.init(__COUNTER__), 0); \ + TUNE(Conditions, set_conditions) + +#endif // #ifndef TUNE_H_INCLUDED diff --git a/src/types.h b/src/types.h index cd8d2320..7b896803 100644 --- a/src/types.h +++ b/src/types.h @@ -465,3 +465,5 @@ constexpr bool is_ok(Move m) { } #endif // #ifndef TYPES_H_INCLUDED + +#include "tune.h" // Global visibility to tuning setup From a91cb9fc1bc403dd610b3e17f022b5afa94dff49 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 6 May 2020 08:44:39 +0100 Subject: [PATCH 249/281] Penalty for all enemy pawns xrayed by our bishop. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 159760 W: 30229 L: 29813 D: 99718 Ptnml(0-2): 2659, 18309, 37534, 18713, 2665 https://tests.stockfishchess.org/tests/view/5eb1d5032326444a3b6d33ce LTC: LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 26496 W: 3908 L: 3656 D: 18932 Ptnml(0-2): 192, 2512, 7610, 2720, 214 https://tests.stockfishchess.org/tests/view/5eb1e2dd2326444a3b6d33f9 closes https://github.com/official-stockfish/Stockfish/pull/2662 Bench 5185517 --- src/evaluate.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 67e05921..e663f21f 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -128,6 +128,7 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); constexpr Score Hanging = S( 69, 36); @@ -318,6 +319,9 @@ namespace { score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); + // Penalty for all enemy pawns x-rayed + score -= BishopXRayPawns * popcount(PseudoAttacks[BISHOP][s] & pos.pieces(Them, PAWN)); + // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) score += LongDiagonalBishop; From fcaf0736feb17f1eb639a7ae071acc920b308f74 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Fri, 8 May 2020 12:07:42 +0100 Subject: [PATCH 250/281] Fix syzygy dependencies issue fixes https://github.com/official-stockfish/Stockfish/issues/2660 The problem was caused by .depend being created with a rule for tbprobe.o not for syzygy/tbprobe.o. This patch keeps an explicit list of sources (SRCS), generates OBJS, and compiles all object files to the src/ directory, consistent with .depend. VPATH is used to search the syzygy directory as needed. joint work with @gvreuls closes https://github.com/official-stockfish/Stockfish/pull/2664 No functional change --- src/Makefile | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0998a551..016aafec 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,10 +35,14 @@ BINDIR = $(PREFIX)/bin ### Built-in benchmark for pgo-builds PGOBENCH = ./$(EXE) bench -### Object files -OBJS = benchmark.o bitbase.o bitboard.o endgame.o evaluate.o main.o \ - material.o misc.o movegen.o movepick.o pawns.o position.o psqt.o \ - search.o thread.o timeman.o tt.o uci.o ucioption.o tune.o syzygy/tbprobe.o +### Source and object files +SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ + material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \ + search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp + +OBJS = $(notdir $(SRCS:.cpp=.o)) + +VPATH = syzygy ### Establish the operating system name KERNEL = $(shell uname -s) @@ -450,7 +454,7 @@ objclean: # clean auxiliary profiling files profileclean: @rm -rf profdir - @rm -f bench.txt *.gcda ./syzygy/*.gcda *.gcno ./syzygy/*.gcno + @rm -f bench.txt *.gcda *.gcno @rm -f stockfish.profdata *.profraw default: @@ -536,7 +540,7 @@ icc-profile-use: all .depend: - -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null + -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null -include .depend From 8a1de2655ce9790d5f0360e2baefb0f5c0fe2944 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 9 May 2020 19:45:07 +0200 Subject: [PATCH 251/281] Use posix_memalign instead of aligned_alloc should be a little more portable to older linux systems (before glibc-2.16). fixes https://github.com/official-stockfish/Stockfish/issues/2665 closes https://github.com/official-stockfish/Stockfish/pull/2668 No functional change. --- src/misc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index 4d6483e7..94681008 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -303,7 +303,8 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { constexpr size_t alignment = 2 * 1024 * 1024; // assumed 2MB page sizes size_t size = ((allocSize + alignment - 1) / alignment) * alignment; // multiple of alignment - mem = aligned_alloc(alignment, size); + if (posix_memalign(&mem, alignment, size)) + mem = nullptr; madvise(mem, allocSize, MADV_HUGEPAGE); return mem; } From 66ed8b6c479932f1ec2274b5f567b5a6aecae0a4 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Fri, 8 May 2020 16:59:06 +0200 Subject: [PATCH 252/281] Tune pawn value Small tune of PawnValue parameters -4 / -7 with "closedpos.epd" opening book. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 58776 W: 11787 L: 11511 D: 35478 Ptnml(0-2): 975, 6876, 13443, 7086, 1008 https://tests.stockfishchess.org/tests/view/5eb5aa712326444a3b6d3e33 LTC: LLR: 2.98 (-2.94,2.94) {0.25,1.75} Total: 137544 W: 19687 L: 19115 D: 98742 Ptnml(0-2): 988, 13219, 39901, 13561, 1103 https://tests.stockfishchess.org/tests/view/5eb67a392326444a3b6d3e9a Non regression STC with "noob_3moves.epd" opening book LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 98168 W: 18545 L: 18499 D: 61124 Ptnml(0-2): 1647, 11396, 22951, 11444, 1646 https://tests.stockfishchess.org/tests/view/5eb7e489e0300e8e8c896203 closes https://github.com/official-stockfish/Stockfish/pull/2670 Bench 4696646 --- src/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.h b/src/types.h index 7b896803..580c846a 100644 --- a/src/types.h +++ b/src/types.h @@ -181,7 +181,7 @@ enum Value : int { VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE_IN_MAX_PLY, - PawnValueMg = 128, PawnValueEg = 213, + PawnValueMg = 124, PawnValueEg = 206, KnightValueMg = 781, KnightValueEg = 854, BishopValueMg = 825, BishopValueEg = 915, RookValueMg = 1276, RookValueEg = 1380, From 86ee4eb84d54dac3f9de5b455ba41909c7722173 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Tue, 12 May 2020 21:41:55 +0200 Subject: [PATCH 253/281] Use a trivially copyable struct for TBTables::Entry instead of a tuple. fixes https://github.com/official-stockfish/Stockfish/issues/2673 which is a warning issued by recent gcc (10.1) closes https://github.com/official-stockfish/Stockfish/pull/2674 No functional change --- AUTHORS | 1 + src/syzygy/tbprobe.cpp | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9fceebf7..36c2a47b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -151,6 +151,7 @@ thaspel theo77186 Tom Truscott Tom Vijlbrief (tomtor) +Tomasz Sobczyk (Sopel97) Torsten Franz (torfranz, tfranzer) Tracey Emery (basepr1me) Uri Blass (uriblass) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index f1fd695c..843f049a 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -60,7 +60,7 @@ namespace { constexpr int TBPIECES = 7; // Max number of supported pieces enum { BigEndian, LittleEndian }; -enum TBType { KEY, WDL, DTZ }; // Used as template parameter +enum TBType { WDL, DTZ }; // Used as template parameter // Each table has a set of flags: all of them refer to DTZ tables, the last one to WDL tables enum TBFlag { STM = 1, Mapped = 2, WinPlies = 4, LossPlies = 8, Wide = 16, SingleValue = 128 }; @@ -403,7 +403,18 @@ TBTable::TBTable(const TBTable& wdl) : TBTable() { // at init time, accessed at probe time. class TBTables { - typedef std::tuple*, TBTable*> Entry; + struct Entry + { + Key key; + TBTable* wdl; + TBTable* dtz; + + template + TBTable* get() const { + return (TBTable*)(Type == WDL ? (void*)wdl : (void*)dtz); + } + }; + static_assert(std::is_trivially_copyable::value, ""); static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket @@ -415,12 +426,12 @@ class TBTables { void insert(Key key, TBTable* wdl, TBTable* dtz) { uint32_t homeBucket = (uint32_t)key & (Size - 1); - Entry entry = std::make_tuple(key, wdl, dtz); + Entry entry{ key, wdl, dtz }; // Ensure last element is empty to avoid overflow when looking up for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket) { - Key otherKey = std::get(hashTable[bucket]); - if (otherKey == key || !std::get(hashTable[bucket])) { + Key otherKey = hashTable[bucket].key; + if (otherKey == key || !hashTable[bucket].get()) { hashTable[bucket] = entry; return; } @@ -429,7 +440,7 @@ class TBTables { // insert here and search for a new spot for the other element instead. uint32_t otherHomeBucket = (uint32_t)otherKey & (Size - 1); if (otherHomeBucket > homeBucket) { - swap(entry, hashTable[bucket]); + std::swap(entry, hashTable[bucket]); key = otherKey; homeBucket = otherHomeBucket; } @@ -442,8 +453,8 @@ public: template TBTable* get(Key key) { for (const Entry* entry = &hashTable[(uint32_t)key & (Size - 1)]; ; ++entry) { - if (std::get(*entry) == key || !std::get(*entry)) - return std::get(*entry); + if (entry->key == key || !entry->get()) + return entry->get(); } } From d4763424d2728fe2dfd0a6fe747666feb6a2fdbb Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Mon, 4 May 2020 20:49:27 +0300 Subject: [PATCH 254/281] Add support for Windows large pages for users that set the needed privilige "Lock Pages in Memory" large pages will be automatically enabled (see Readme.md). This expert setting might improve speed, 5% - 30%, depending on the hardware, the number of threads and hash size. More for large hashes, large number of threads and NUMA. If the operating system can not allocate large pages (easier after a reboot), default allocation is used automatically. The engine log provides details. closes https://github.com/official-stockfish/Stockfish/pull/2656 fixes https://github.com/official-stockfish/Stockfish/issues/2619 No functional change --- Readme.md | 26 +++++++++++++++- src/main.cpp | 1 + src/misc.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/misc.h | 1 + src/tt.cpp | 9 +++++- 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index a759eff6..35ff095d 100644 --- a/Readme.md +++ b/Readme.md @@ -42,7 +42,7 @@ Currently, Stockfish has the following UCI options: this equal to the number of CPU cores available. * #### Hash - The size of the hash table in MB. + The size of the hash table in MB. It is recommended to set Hash after setting Threads. * #### Clear Hash Clear the hash table. @@ -138,6 +138,30 @@ more compact than Nalimov tablebases, while still storing all information needed for optimal play and in addition being able to take into account the 50-move rule. +## Large Pages + +Stockfish supports large pages on Linux and Windows. Large pages make +the hash access more efficient, improving the engine speed, especially +on large hash sizes. Typical increases are 5..10% in terms of nps, but +speed increases up to 30% have been measured. The support is +automatic. Stockfish attempts to use large pages when available and +will fall back to regular memory allocation when this is not the case. + +### Support on Linux + +Large page support on Linux is obtained by the Linux kernel +transparent huge pages functionality. Typically, transparent huge pages +are already enabled and no configuration is needed. + +### Support on Windows + +The use of large pages requires "Lock Pages in Memory" privilege. See +[Enable the Lock Pages in Memory Option (Windows)](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows) +on how to enable this privilege. Logout/login may be needed +afterwards. Due to memory fragmentation, it may not always be +possible to allocate large pages even when enabled. A reboot +might alleviate this problem. To determine whether large pages +are in use, see the engine log. ## Compiling Stockfish yourself from the sources diff --git a/src/main.cpp b/src/main.cpp index 6eeda66d..c7cf2c6f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) { UCI::loop(argc, argv); + TT.resize(0); Threads.set(0); return 0; } diff --git a/src/misc.cpp b/src/misc.cpp index 94681008..b1c0feeb 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -309,6 +309,69 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { return mem; } +#elif defined(_WIN64) + +static void* aligned_ttmem_alloc_large_pages(size_t allocSize) { + + HANDLE hProcessToken { }; + LUID luid { }; + void* mem = nullptr; + + const size_t largePageSize = GetLargePageMinimum(); + if (!largePageSize) + return nullptr; + + // We need SeLockMemoryPrivilege, so try to enable it for the process + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) + return nullptr; + + if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid)) + { + TOKEN_PRIVILEGES tp { }; + TOKEN_PRIVILEGES prevTp { }; + DWORD prevTpLen = 0; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds, + // we still need to query GetLastError() to ensure that the privileges were actually obtained... + if (AdjustTokenPrivileges( + hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) && + GetLastError() == ERROR_SUCCESS) + { + // round up size to full pages and allocate + allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1); + mem = VirtualAlloc( + NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + + // privilege no longer needed, restore previous state + AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL); + } + } + + CloseHandle(hProcessToken); + + return mem; +} + +void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { + + // try to allocate large pages + mem = aligned_ttmem_alloc_large_pages(allocSize); + if (mem) + sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; + else + sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + + // fall back to regular, page aligned, allocation if necessary + if (!mem) + mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + return mem; +} + #else void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { @@ -322,6 +385,28 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { #endif +/// aligned_ttmem_free will free the previously allocated ttmem +#if defined(_WIN64) + +void aligned_ttmem_free(void* mem) { + + if (!VirtualFree(mem, 0, MEM_RELEASE)) + { + DWORD err = GetLastError(); + std::cerr << "Failed to free transposition table. Error code: 0x" << + std::hex << err << std::dec << std::endl; + exit(EXIT_FAILURE); + } +} + +#else + +void aligned_ttmem_free(void *mem) { + free(mem); +} + +#endif + namespace WinProcGroup { diff --git a/src/misc.h b/src/misc.h index e0e0e98b..9d53c2da 100644 --- a/src/misc.h +++ b/src/misc.h @@ -34,6 +34,7 @@ const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); void* aligned_ttmem_alloc(size_t size, void*& mem); +void aligned_ttmem_free(void* mem); void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 7e95a2a4..6ee63138 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,7 +63,14 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - free(mem); + if (mem) + aligned_ttmem_free(mem); + + if (!mbSize) + { + mem = nullptr; + return; + } clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); From cca643669db016f20c6e91f50892a0b44f297a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 8 May 2020 10:32:52 +0200 Subject: [PATCH 255/281] Move 50 moves counter to initiative. simplify the usage of the 50 moves counter, moving it frome the scale factor to initiative. This patch was inspired by recent games where a blocked or semi-blocked position was 'blundered', by moving a pawn, into a lost endgame. This patch improves this situation, finding a more robust move more often. for example (1s searches with many threads): ``` FEN 8/p3kp2/Pp2p3/1n2PpP1/5P2/1Kp5/8/R7 b - - 68 143 master: 6 bestmove b5c7 6 bestmove e7e8 12 bestmove e7d8 176 bestmove e7d7 patch: 3 bestmove b5c7 5 bestmove e7d8 192 bestmove e7d7 ``` fixes https://github.com/official-stockfish/Stockfish/issues/2620 the patch also tests well passed STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 50168 W: 9508 L: 9392 D: 31268 Ptnml(0-2): 818, 5873, 11616, 5929, 848 https://tests.stockfishchess.org/tests/view/5ebb07287dd5693aad4e680b passed LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 7520 W: 981 L: 870 D: 5669 Ptnml(0-2): 49, 647, 2256, 760, 48 https://tests.stockfishchess.org/tests/view/5ebbff747dd5693aad4e6858 closes https://github.com/official-stockfish/Stockfish/pull/2666 Bench: 4395562 --- src/evaluate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e663f21f..d972db5a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -739,6 +739,7 @@ namespace { + 24 * infiltration + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable + - 2 * pos.rule50_count() -110 ; Value mg = mg_value(score); @@ -778,8 +779,6 @@ namespace { } else sf = std::min(sf, 36 + 7 * pos.count(strongSide)); - - sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); @@ -856,7 +855,8 @@ namespace { Trace::add(TOTAL, score); } - return (pos.side_to_move() == WHITE ? v : -v) + Tempo; // Side to move point of view + // Side to move point of view + return (pos.side_to_move() == WHITE ? v : -v) + Tempo; } } // namespace From beb327f910ed782f358d69201643ccd99b982a48 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Thu, 14 May 2020 12:00:35 +0300 Subject: [PATCH 256/281] Fix a Windows-only crash on exit without 'quit' There was a bug in commit d4763424d2728fe2dfd0a6fe747666feb6a2fdbb (Add support for Windows large pages) that could result in trying to free memory allocated with VirtualAlloc incorrectly with free(). Fix this by reverting the TT.resize(0) logic in the previous commit, and instead, just call aligned_ttmem_free() in TranspositionTable::~TranspositionTable(). fixes https://github.com/official-stockfish/Stockfish/issues/2677 closes https://github.com/official-stockfish/Stockfish/pull/2679 No functional change --- src/main.cpp | 1 - src/misc.cpp | 2 +- src/misc.h | 2 +- src/tt.cpp | 9 +-------- src/tt.h | 2 +- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c7cf2c6f..6eeda66d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,6 @@ int main(int argc, char* argv[]) { UCI::loop(argc, argv); - TT.resize(0); Threads.set(0); return 0; } diff --git a/src/misc.cpp b/src/misc.cpp index b1c0feeb..e0cc6ed5 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -390,7 +390,7 @@ void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { void aligned_ttmem_free(void* mem) { - if (!VirtualFree(mem, 0, MEM_RELEASE)) + if (mem && !VirtualFree(mem, 0, MEM_RELEASE)) { DWORD err = GetLastError(); std::cerr << "Failed to free transposition table. Error code: 0x" << diff --git a/src/misc.h b/src/misc.h index 9d53c2da..05bfc7de 100644 --- a/src/misc.h +++ b/src/misc.h @@ -34,7 +34,7 @@ const std::string compiler_info(); void prefetch(void* addr); void start_logger(const std::string& fname); void* aligned_ttmem_alloc(size_t size, void*& mem); -void aligned_ttmem_free(void* mem); +void aligned_ttmem_free(void* mem); // nop if mem == nullptr void dbg_hit_on(bool b); void dbg_hit_on(bool c, bool b); diff --git a/src/tt.cpp b/src/tt.cpp index 6ee63138..4e06bed9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -63,14 +63,7 @@ void TranspositionTable::resize(size_t mbSize) { Threads.main()->wait_for_search_finished(); - if (mem) - aligned_ttmem_free(mem); - - if (!mbSize) - { - mem = nullptr; - return; - } + aligned_ttmem_free(mem); clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster); table = static_cast(aligned_ttmem_alloc(clusterCount * sizeof(Cluster), mem)); diff --git a/src/tt.h b/src/tt.h index 8b70f797..bd723a86 100644 --- a/src/tt.h +++ b/src/tt.h @@ -75,7 +75,7 @@ class TranspositionTable { static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); public: - ~TranspositionTable() { free(mem); } + ~TranspositionTable() { aligned_ttmem_free(mem); } void new_search() { generation8 += 8; } // Lower 3 bits are used by PV flag and Bound TTEntry* probe(const Key key, bool& found) const; int hashfull() const; From c6ce612f0ada9b5f0d9530128545d1ee7d58b3e5 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 13 May 2020 11:52:41 -0600 Subject: [PATCH 257/281] Simplify Time Management This is a functional simplification of the time management system. With this patch, there is a simple equation for each of two distinct time controls: basetime + increment, and x moves in y seconds (+increment). These equations are easy to plot and understand making future modifications or adding additional time controls much easier. SlowMover is reset to 100 so that is has no effect unless a user changes it. There are two scaling variables: * Opt_scale is a scale factor (or percentage) of time to use for this current move. * Max_scale is a scale factor to apply to the resulting optimumTime. There seems to be some elo gain in most scenarios. Better performance is attributable to one of two things: * minThinkingTime was not allowing reasonable time calculations for very short games like 10+0 or 10+0.01. This is because adding almost no increment and substracting move overhead for 50 moves quickly results in almost 0 time very early in the game. Master depended on minThinkingTime to handle these short games instead of good time management. This patch addresses this issue by lowering minThinkingTime to 0 and adjusting moverOverhead if there are very low increments. * Notice that the time distribution curves tail downward for the first 10 moves or so. This causes less time to attribute for very early moves leaving more time available for middle moves where more important decisions happen. Here is a summary of tests for this version at different time controls: SMP 5+0.05 LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 46544 W: 7175 L: 7089 D: 32280 Ptnml(0-2): 508, 4826, 12517, 4914, 507 https://tests.stockfishchess.org/tests/user/protonspring STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 20480 W: 3872 L: 3718 D: 12890 Ptnml(0-2): 295, 2364, 4824, 2406, 351 https://tests.stockfishchess.org/tests/view/5ebc343e7dd5693aad4e6873 STC, sudden death LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 7024 W: 1706 L: 1489 D: 3829 Ptnml(0-2): 149, 813, 1417, 938, 195 https://tests.stockfishchess.org/tests/view/5ebc346f7dd5693aad4e6875 STC, TCEC style LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 4192 W: 1014 L: 811 D: 2367 Ptnml(0-2): 66, 446, 912, 563, 109 https://tests.stockfishchess.org/tests/view/5ebc34857dd5693aad4e6877 40/10 LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 54032 W: 10592 L: 10480 D: 32960 Ptnml(0-2): 967, 6148, 12677, 6254, 970 https://tests.stockfishchess.org/tests/view/5ebc50597dd5693aad4e688d LTC, sudden death LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 9152 W: 1391 L: 1263 D: 6498 Ptnml(0-2): 75, 888, 2526, 1008, 79 https://tests.stockfishchess.org/tests/view/5ebc6f5c7dd5693aad4e689b LTC LLR: 2.98 (-2.94,2.94) {-1.50,0.50} Total: 12344 W: 1563 L: 1459 D: 9322 Ptnml(0-2): 70, 1103, 3740, 1171, 88 https://tests.stockfishchess.org/tests/view/5ebc6f4c7dd5693aad4e6899 closes https://github.com/official-stockfish/Stockfish/pull/2678 Bench: 4395562 --- src/timeman.cpp | 111 +++++++++++++++++----------------------------- src/ucioption.cpp | 4 +- 2 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index 0848be42..f794ab13 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -28,58 +28,10 @@ TimeManagement Time; // Our global time management object -namespace { - - enum TimeType { OptimumTime, MaxTime }; - - constexpr int MoveHorizon = 50; // Plan time management at most this many moves ahead - constexpr double MaxRatio = 7.3; // When in trouble, we can step over reserved time with this ratio - constexpr double StealRatio = 0.34; // However we must not steal time from remaining moves over this ratio - - - // move_importance() is a skew-logistic function based on naive statistical - // analysis of "how many games are still undecided after n half-moves". Game - // is considered "undecided" as long as neither side has >275cp advantage. - // Data was extracted from the CCRL game database with some simple filtering criteria. - - double move_importance(int ply) { - - constexpr double XScale = 6.85; - constexpr double XShift = 64.5; - constexpr double Skew = 0.171; - - return pow((1 + exp((ply - XShift) / XScale)), -Skew) + DBL_MIN; // Ensure non-zero - } - - template - TimePoint remaining(TimePoint myTime, int movesToGo, int ply, TimePoint slowMover) { - - constexpr double TMaxRatio = (T == OptimumTime ? 1.0 : MaxRatio); - constexpr double TStealRatio = (T == OptimumTime ? 0.0 : StealRatio); - - double moveImportance = (move_importance(ply) * slowMover) / 100.0; - double otherMovesImportance = 0.0; - - for (int i = 1; i < movesToGo; ++i) - otherMovesImportance += move_importance(ply + 2 * i); - - double ratio1 = (TMaxRatio * moveImportance) / (TMaxRatio * moveImportance + otherMovesImportance); - double ratio2 = (moveImportance + TStealRatio * otherMovesImportance) / (moveImportance + otherMovesImportance); - - return TimePoint(myTime * std::min(ratio1, ratio2)); // Intel C++ asks for an explicit cast - } - -} // namespace - - -/// init() is called at the beginning of the search and calculates the allowed -/// thinking time out of the time control and current game ply. We support four -/// different kinds of time controls, passed in 'limits': -/// -/// inc == 0 && movestogo == 0 means: x basetime [sudden death!] -/// inc == 0 && movestogo != 0 means: x moves in y minutes -/// inc > 0 && movestogo == 0 means: x basetime + z increment -/// inc > 0 && movestogo != 0 means: x moves in y minutes + z increment +/// init() is called at the beginning of the search and calculates the bounds +/// of time allowed for the current game ply. We currently support: +// 1) x basetime (+z increment) +// 2) x moves in y seconds (+z increment) void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { @@ -87,7 +39,10 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { TimePoint moveOverhead = Options["Move Overhead"]; TimePoint slowMover = Options["Slow Mover"]; TimePoint npmsec = Options["nodestime"]; - TimePoint hypMyTime; + + // opt_scale is a percentage of available time to use for the current move. + // max_scale is a multiplier applied to optimumTime. + double opt_scale, max_scale; // If we have to play in 'nodes as time' mode, then convert from time // to nodes, and use resulting values in time management formulas. @@ -105,29 +60,43 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { } startTime = limits.startTime; - optimumTime = maximumTime = std::max(limits.time[us], minThinkingTime); - const int maxMTG = limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon; + //Maximum move horizon of 50 moves + int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; - // We calculate optimum time usage for different hypothetical "moves to go" values - // and choose the minimum of calculated search time values. Usually the greatest - // hypMTG gives the minimum values. - for (int hypMTG = 1; hypMTG <= maxMTG; ++hypMTG) + // Adjust moveOverhead if there are tiny increments + moveOverhead = std::max(10, std::min(limits.inc[us] / 2, moveOverhead)); + + // Make sure timeLeft is > 0 since we may use it as a divisor + TimePoint timeLeft = std::max(TimePoint(1), + limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); + + // A user may scale time usage by setting UCI option "Slow Mover" + // Default is 100 and changing this value will probably lose elo. + timeLeft = slowMover * timeLeft / 100; + + // x basetime (+ z increment) + // If there is a healthy increment, timeLeft can exceed actual available + // game time for the current move, so also cap to 20% of available game time. + if (limits.movestogo == 0) { - // Calculate thinking time for hypothetical "moves to go"-value - hypMyTime = limits.time[us] - + limits.inc[us] * (hypMTG - 1) - - moveOverhead * (2 + std::min(hypMTG, 40)); - - hypMyTime = std::max(hypMyTime, TimePoint(0)); - - TimePoint t1 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - TimePoint t2 = minThinkingTime + remaining(hypMyTime, hypMTG, ply, slowMover); - - optimumTime = std::min(t1, optimumTime); - maximumTime = std::min(t2, maximumTime); + opt_scale = std::min(0.007 + std::pow(ply + 3.0, 0.5) / 250.0, + 0.2 * limits.time[us] / double(timeLeft)); + max_scale = 4 + std::pow(ply + 3, 0.3); } + // x moves in y seconds (+ z increment) + else + { + opt_scale = std::min((0.8 + ply / 128.0) / mtg, + 0.8 * limits.time[us] / double(timeLeft)); + max_scale = std::min(6.3, 1.5 + 0.11 * mtg); + } + + // Never use more than 80% of the available time for this move + optimumTime = std::max(minThinkingTime, opt_scale * timeLeft); + maximumTime = std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime); + if (Options["Ponder"]) optimumTime += optimumTime / 4; } diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 26fcf302..ad576fda 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -69,8 +69,8 @@ void init(OptionsMap& o) { o["MultiPV"] << Option(1, 1, 500); o["Skill Level"] << Option(20, 0, 20); o["Move Overhead"] << Option(30, 0, 5000); - o["Minimum Thinking Time"] << Option(20, 0, 5000); - o["Slow Mover"] << Option(84, 10, 1000); + o["Minimum Thinking Time"] << Option( 0, 0, 5000); + o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); o["UCI_Chess960"] << Option(false); o["UCI_AnalyseMode"] << Option(false); From d116e27f0f6c89c887420890ffe61c6708ef5c08 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 15 May 2020 19:37:56 +0200 Subject: [PATCH 258/281] Workaround for older compiler gcc < 5 doesn't fully support the c++11 `std::is_trivially_copyable::value` Remove it, as it is not essential. fixes https://github.com/official-stockfish/Stockfish/issues/2681 closes https://github.com/official-stockfish/Stockfish/pull/2682 No functional change. --- src/syzygy/tbprobe.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 843f049a..adc45d58 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -414,7 +414,6 @@ class TBTables { return (TBTable*)(Type == WDL ? (void*)wdl : (void*)dtz); } }; - static_assert(std::is_trivially_copyable::value, ""); static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket From 83c9e5911ef7fe6ff71dc116856fac85bb9076eb Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 15 May 2020 17:23:49 -0600 Subject: [PATCH 259/281] Don't adjust MoveOverhead by increment This is a change to address a potential timing issue for slow networks. Move Overhead was limited by TC increment, which might be problematic if small increments (or sudden death) on slow networks (needing high Move Overhead) are used. STC, sudden death. LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 169368 W: 38023 L: 38054 D: 93291 Ptnml(0-2): 3767, 20250, 36595, 20391, 3681 https://tests.stockfishchess.org/tests/view/5ebf25efe9d85f94dc42986f STC, 10+0.1 LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 83896 W: 16092 L: 16026 D: 51778 Ptnml(0-2): 1401, 9697, 19670, 9795, 1385 https://tests.stockfishchess.org/tests/view/5ec0239de9d85f94dc42991e closes https://github.com/official-stockfish/Stockfish/pull/2684 No functional change. --- src/timeman.cpp | 3 --- src/ucioption.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index f794ab13..0021e96b 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -64,9 +64,6 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { //Maximum move horizon of 50 moves int mtg = limits.movestogo ? std::min(limits.movestogo, 50) : 50; - // Adjust moveOverhead if there are tiny increments - moveOverhead = std::max(10, std::min(limits.inc[us] / 2, moveOverhead)); - // Make sure timeLeft is > 0 since we may use it as a divisor TimePoint timeLeft = std::max(TimePoint(1), limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); diff --git a/src/ucioption.cpp b/src/ucioption.cpp index ad576fda..66fd42d1 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -68,7 +68,7 @@ void init(OptionsMap& o) { o["Ponder"] << Option(false); o["MultiPV"] << Option(1, 1, 500); o["Skill Level"] << Option(20, 0, 20); - o["Move Overhead"] << Option(30, 0, 5000); + o["Move Overhead"] << Option(10, 0, 5000); o["Minimum Thinking Time"] << Option( 0, 0, 5000); o["Slow Mover"] << Option(100, 10, 1000); o["nodestime"] << Option(0, 0, 10000); From dd1adce7488b20b4125946077bcbbf665b9797f7 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Sun, 17 May 2020 20:46:25 +0100 Subject: [PATCH 260/281] Increase base time use and limit max used. This change increases the base part of optimumTime at all depths. It also reduces the size of max_scale and thus maximumTime by using a linear scale instead of pow(x, 0.3) and by limiting max_scale to no more than 7 (previously as high as 8 or 9 at very high depths). Tested using the closedpos book: STC 10+0.1: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 83696 W: 16813 L: 16508 D: 50375 Ptnml(0-2): 1315, 9649, 19686, 9812, 1386 https://tests.stockfishchess.org/tests/view/5ebfa92de9d85f94dc42989b LTC 60+0.6: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 39384 W: 5868 L: 5582 D: 27934 Ptnml(0-2): 276, 3697, 11489, 3925, 305 https://tests.stockfishchess.org/tests/view/5ec0a6dce9d85f94dc42995a Test for non-regression: STC Sudden Death 10+0 : LLR: 2.94 (-2.94,2.94) {-2.00,0.00} Total: 111976 W: 25661 L: 25768 D: 60547 Ptnml(0-2): 2567, 13420, 24118, 13319, 2564 https://tests.stockfishchess.org/tests/view/5ec23b3be9d85f94dc429a58 closes https://github.com/official-stockfish/Stockfish/pull/2685 Bench 4395562 --- src/timeman.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/timeman.cpp b/src/timeman.cpp index 0021e96b..45e9db58 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -77,9 +77,9 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { // game time for the current move, so also cap to 20% of available game time. if (limits.movestogo == 0) { - opt_scale = std::min(0.007 + std::pow(ply + 3.0, 0.5) / 250.0, + opt_scale = std::min(0.008 + std::pow(ply + 3.0, 0.5) / 250.0, 0.2 * limits.time[us] / double(timeLeft)); - max_scale = 4 + std::pow(ply + 3, 0.3); + max_scale = 4 + std::min(36, ply) / 12.0; } // x moves in y seconds (+ z increment) From b36a1fa1b4ffded06aba53e1003b40827c39803c Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Tue, 19 May 2020 12:08:01 +0300 Subject: [PATCH 261/281] Avoid sending info strings before 'uci' has been received Do not send the following info string on the first call to aligned_ttmem_alloc() on Windows: info string Hash table allocation: Windows large pages [not] used. The first call occurs before the 'uci' command has been received. This confuses some GUIs, which expect the first engine-sent command to be 'id' as the response to the 'uci' command. (see https://github.com/official-stockfish/Stockfish/issues/2681) closes https://github.com/official-stockfish/Stockfish/pull/2689 No functional change. --- src/misc.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index e0cc6ed5..c6254784 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -358,12 +358,21 @@ static void* aligned_ttmem_alloc_large_pages(size_t allocSize) { void* aligned_ttmem_alloc(size_t allocSize, void*& mem) { + static bool firstCall = true; + // try to allocate large pages mem = aligned_ttmem_alloc_large_pages(allocSize); - if (mem) - sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; - else - sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + + // Suppress info strings on the first call. The first call occurs before 'uci' + // is received and in that case this output confuses some GUIs. + if (!firstCall) + { + if (mem) + sync_cout << "info string Hash table allocation: Windows large pages used." << sync_endl; + else + sync_cout << "info string Hash table allocation: Windows large pages not used." << sync_endl; + } + firstCall = false; // fall back to regular, page aligned, allocation if necessary if (!mem) From 20ceeac8b3a3bd13a64d6a224ef190d6cdd94f63 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 20 May 2020 08:33:59 -0600 Subject: [PATCH 262/281] Simplify evaluation for blocked passers. This is a functional simplification of the evaluation code for blocked passers. I've also changed a few variable names for clarity. STC LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 141984 W: 27450 L: 27466 D: 87068 Ptnml(0-2): 2414, 16511, 33175, 16461, 2431 https://tests.stockfishchess.org/tests/view/5ec4001b05aa4bc72d9759e7 LTC LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 30536 W: 3966 L: 3885 D: 22685 Ptnml(0-2): 216, 2841, 9073, 2922, 216 https://tests.stockfishchess.org/tests/view/5ec4bd0d377121ac09e101b7 Closes https://github.com/official-stockfish/Stockfish/pull/2690 Bench: 4704681 --- src/evaluate.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d972db5a..d04d724a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -591,25 +591,22 @@ namespace { return std::min(distance(pos.square(c), s), 5); }; - Bitboard b, bb, squaresToQueen, unsafeSquares, candidatePassers, leverable; + Bitboard b, bb, squaresToQueen, unsafeSquares, blockedPassers, helpers; Score score = SCORE_ZERO; b = pe->passed_pawns(Us); - candidatePassers = b & shift(pos.pieces(Them, PAWN)); - if (candidatePassers) + blockedPassers = b & shift(pos.pieces(Them, PAWN)); + if (blockedPassers) { - // Can we lever the blocker of a candidate passer? - leverable = shift(pos.pieces(Us, PAWN)) - & ~pos.pieces(Them) - & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]) - & (~(attackedBy[Them][KNIGHT] | attackedBy[Them][BISHOP]) - | (attackedBy[Us ][KNIGHT] | attackedBy[Us ][BISHOP])); + helpers = shift(pos.pieces(Us, PAWN)) + & ~pos.pieces(Them) + & (~attackedBy2[Them] | attackedBy[Us][ALL_PIECES]); - // Remove candidate otherwise - b &= ~candidatePassers - | shift(leverable) - | shift(leverable); + // Remove blocked candidate passers that don't have help to pass + b &= ~blockedPassers + | shift(helpers) + | shift(helpers); } while (b) From 6c1af710d16c6a358cc09c51a133120605c39e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Wed, 20 May 2020 17:06:42 +0200 Subject: [PATCH 263/281] A combo of parameters tweaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is a combinaison of two recent parameters tweaks which had failed narrowly (yellow) at long time control: • improvement in move ordering during search by softening the distinction between bad captures and good captures during move generation, leading to improved awareness of Stockfish of potential piece sacrifices (idea by Rahul Dsilva) • increase in the weight of pawns in the "initiative" part of the evaluation function. With this change Stockfish should have more incentive to exchange pawns when losing, and to keep pawns when winning. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 10704 W: 2178 L: 1974 D: 6552 Ptnml(0-2): 168, 1185, 2464, 1345, 190 https://tests.stockfishchess.org/tests/view/5ec5553b377121ac09e1023d LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 60592 W: 7835 L: 7494 D: 45263 Ptnml(0-2): 430, 5514, 18086, 5817, 449 https://tests.stockfishchess.org/tests/view/5ec55ca2377121ac09e10249 Closes https://github.com/official-stockfish/Stockfish/pull/2691 Bench: 4519117 --- src/evaluate.cpp | 2 +- src/movepick.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index d04d724a..449cf6d7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -730,7 +730,7 @@ namespace { // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() - + 11 * pos.count() + + 12 * pos.count() + 9 * outflanking + 21 * pawnsOnBothFlanks + 24 * infiltration diff --git a/src/movepick.cpp b/src/movepick.cpp index b1e10587..e26f42ef 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -169,7 +169,7 @@ top: case GOOD_CAPTURE: if (select([&](){ - return pos.see_ge(*cur, Value(-55 * cur->value / 1024)) ? + return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ? // Move losing capture to endBadCaptures to be tried later true : (*endBadCaptures++ = *cur, false); })) return *(cur - 1); From 09c6917d053582267a2960e8c375883e0d9461da Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 21 May 2020 12:29:36 +0200 Subject: [PATCH 264/281] Tweak knight mobility New tuned values for knight mobility in endgames. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 112576 W: 21999 L: 21644 D: 68933 Ptnml(0-2): 2009, 13084, 25735, 13463, 1997 https://tests.stockfishchess.org/tests/view/5ec58379377121ac09e10272 LTC: LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 125192 W: 16200 L: 15671 D: 93321 Ptnml(0-2): 891, 11584, 37182, 11983, 956 https://tests.stockfishchess.org/tests/view/5ec5c0b8377121ac09e1028b Closes https://github.com/official-stockfish/Stockfish/pull/2693 Bench: 4778956 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 449cf6d7..e80e9442 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -91,8 +91,8 @@ namespace { // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. constexpr Score MobilityBonus[][32] = { - { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knight - S( 22, 23), S( 28, 27), S( 33, 33) }, + { S(-62,-81), S(-53,-56), S(-12,-31), S( -4,-16), S( 3, 5), S( 13, 11), // Knight + S( 22, 17), S( 28, 20), S( 33, 25) }, { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishop S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, From cdf5cfdb92b4ac7df8c2c3d891797787081c1ca2 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 22 May 2020 11:08:44 +0200 Subject: [PATCH 265/281] Add doubled isolated pawn penalty. This patch gives an additional penalty if a doubled isolated pawn is stopped only by a single opponent pawn on the same file. Thanks to NKONSTANTAKIS, who shared this idea on the forum! https://groups.google.com/forum/?fromgroups=#!topic/fishcooking/vC4Qn-PMlS4. STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 84872 W: 16688 L: 16370 D: 51814 Ptnml(0-2): 1507, 9940, 19274, 10158, 1557 https://tests.stockfishchess.org/tests/view/5ec65bd955202b947dc5d4ac LTC: LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 58104 W: 7614 L: 7278 D: 43212 Ptnml(0-2): 411, 5369, 17196, 5625, 451 https://tests.stockfishchess.org/tests/view/5ec6e9f2c23f5b0710632b19 Closes https://github.com/official-stockfish/Stockfish/pull/2694 Bench: 5148950 --- src/pawns.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7b266e77..c20cb529 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,12 +32,13 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); - constexpr Score Doubled = S(11, 56); - constexpr Score Isolated = S( 5, 15); - constexpr Score WeakLever = S( 0, 56); - constexpr Score WeakUnopposed = S(13, 27); + constexpr Score Backward = S( 9, 24); + constexpr Score BlockedStorm = S(82, 82); + constexpr Score Doubled = S(11, 56); + constexpr Score DoubledIsolated = S(15, 57); + constexpr Score Isolated = S( 5, 15); + constexpr Score WeakLever = S( 0, 56); + constexpr Score WeakUnopposed = S(13, 27); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -144,9 +145,16 @@ namespace { } else if (!neighbours) + { score -= Isolated + WeakUnopposed * !opposed; + if ( (ourPawns & forward_file_bb(Them, s)) + && popcount(opposed) == 1 + && !(theirPawns & adjacent_files_bb(s))) + score -= DoubledIsolated; + } + else if (backward) score -= Backward + WeakUnopposed * !opposed; From 669b5d83ef1d930c80854236f324de2fdcecf57c Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 21 May 2020 08:25:37 +0200 Subject: [PATCH 266/281] Improve CI testing also enable CXXFLAGS="-D_GLIBCXX_DEBUG" in CI. closes https://github.com/official-stockfish/Stockfish/pull/2692 No functional change. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e2b42e6d..e2ae61be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ script: - echo "Reference bench:" $benchref # # Verify bench number against various builds - - export CXXFLAGS=-Werror + - export CXXFLAGS="-Werror -D_GLIBCXX_DEBUG" - make clean && make -j2 ARCH=x86-64 optimize=no debug=yes build && ../tests/signature.sh $benchref - make clean && make -j2 ARCH=x86-32 optimize=no debug=yes build && ../tests/signature.sh $benchref - make clean && make -j2 ARCH=x86-32 build && ../tests/signature.sh $benchref From d940e59dad51e78d5146bb21c8f792379df64816 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Thu, 21 May 2020 21:17:21 +0100 Subject: [PATCH 267/281] Keep low ply history from previous move This patch keeps the low-ply history from the previous move, shifting the data down by 2 ply. Tested with closedpos book: STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 71584 W: 14175 L: 13891 D: 43518 Ptnml(0-2): 1069, 8228, 16993, 8354, 1148 https://tests.stockfishchess.org/tests/view/5ec0eaafe9d85f94dc429974 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 96552 W: 13946 L: 13498 D: 69108 Ptnml(0-2): 676, 9082, 28375, 9404, 739 https://tests.stockfishchess.org/tests/view/5ec145efe9d85f94dc4299b0 closes https://github.com/official-stockfish/Stockfish/pull/2688 Bench 5148950 --- src/search.cpp | 3 +++ src/thread.cpp | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7f29f771..5e9cd463 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -357,6 +357,9 @@ void Thread::search() { mainThread->iterValue[i] = mainThread->bestPreviousScore; } + std::copy(&lowPlyHistory[2][0], &lowPlyHistory.back().back() + 1, &lowPlyHistory[0][0]); + std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); + size_t multiPV = Options["MultiPV"]; // Pick integer skill levels, but non-deterministically round up or down diff --git a/src/thread.cpp b/src/thread.cpp index 88331f06..2e0c216e 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -212,7 +212,6 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); - th->lowPlyHistory.fill(0); } setupStates->back() = tmp; From 383b12e1a5cc03a122e9a071eebde87eac85b116 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 23 May 2020 13:26:13 +0200 Subject: [PATCH 268/281] small cleanups closes https://github.com/official-stockfish/Stockfish/pull/2653 No functional change --- src/bitboard.cpp | 2 +- src/evaluate.cpp | 2 +- src/main.cpp | 2 +- src/movegen.cpp | 44 ++++++++++++++++++++++++++++-------------- src/pawns.cpp | 5 ++--- src/position.cpp | 2 +- src/position.h | 7 +++---- src/search.cpp | 14 +++++++------- src/syzygy/tbprobe.cpp | 6 +++--- src/thread.cpp | 2 +- src/timeman.cpp | 12 ++++++------ src/tt.cpp | 6 +++--- src/tune.cpp | 6 +++--- src/ucioption.cpp | 4 ++-- 14 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 69bbc77b..f650eef6 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -69,7 +69,7 @@ const std::string Bitboards::pretty(Bitboard b) { void Bitboards::init() { for (unsigned i = 0; i < (1 << 16); ++i) - PopCnt16[i] = std::bitset<16>(i).count(); + PopCnt16[i] = uint8_t(std::bitset<16>(i).count()); for (Square s = SQ_A1; s <= SQ_H8; ++s) SquareBB[s] = (1ULL << s); diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e80e9442..2d1f4b9e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -311,7 +311,7 @@ namespace { if (Pt == BISHOP) { - // Penalty according to number of pawns on the same color square as the + // Penalty according to the number of our pawns on the same color square as the // bishop, bigger when the center files are blocked with pawns and smaller // when the bishop is outside the pawn chain. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); diff --git a/src/main.cpp b/src/main.cpp index 6eeda66d..fafefee2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { Position::init(); Bitbases::init(); Endgames::init(); - Threads.set(Options["Threads"]); + Threads.set(size_t(Options["Threads"])); Search::clear(); // After threads are up UCI::loop(argc, argv); diff --git a/src/movegen.cpp b/src/movegen.cpp index a3abcde8..5787d174 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -213,8 +213,31 @@ namespace { template - ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) { + ExtMove* generate_all(const Position& pos, ExtMove* moveList) { constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations + Bitboard target; + + switch (Type) + { + case CAPTURES: + target = pos.pieces(~Us); + break; + case QUIETS: + case QUIET_CHECKS: + target = ~pos.pieces(); + break; + case EVASIONS: + { + Square checksq = lsb(pos.checkers()); + target = between_bb(pos.square(Us), checksq) | checksq; + break; + } + case NON_EVASIONS: + target = ~pos.pieces(Us); + break; + default: + static_assert(true, "Unsupported type in generate_all()"); + } moveList = generate_pawn_moves(pos, moveList, target); moveList = generate_moves(pos, moveList, Us, target); @@ -255,12 +278,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Color us = pos.side_to_move(); - Bitboard target = Type == CAPTURES ? pos.pieces(~us) - : Type == QUIETS ? ~pos.pieces() - : Type == NON_EVASIONS ? ~pos.pieces(us) : 0; - - return us == WHITE ? generate_all(pos, moveList, target) - : generate_all(pos, moveList, target); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } // Explicit template instantiations @@ -293,8 +312,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { *moveList++ = make_move(from, pop_lsb(&b)); } - return us == WHITE ? generate_all(pos, moveList, ~pos.pieces()) - : generate_all(pos, moveList, ~pos.pieces()); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } @@ -325,11 +344,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { return moveList; // Double check, only a king move can save the day // Generate blocking evasions or captures of the checking piece - Square checksq = lsb(pos.checkers()); - Bitboard target = between_bb(checksq, ksq) | checksq; - - return us == WHITE ? generate_all(pos, moveList, target) - : generate_all(pos, moveList, target); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } diff --git a/src/pawns.cpp b/src/pawns.cpp index c20cb529..b883dda2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -87,6 +87,7 @@ namespace { e->passedPawns[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = e->pawnAttacksSpan[Us] = pawn_attacks_bb(ourPawns); + e->blockedCount += popcount(shift(ourPawns) & (theirPawns | doubleAttackThem)); // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) @@ -106,8 +107,6 @@ namespace { phalanx = neighbours & rank_bb(s); support = neighbours & rank_bb(s - Up); - e->blockedCount += blocked || more_than_one(leverPush); - // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. backward = !(neighbours & forward_ranks_bb(Them, s + Up)) @@ -216,7 +215,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { b = theirPawns & file_bb(f); int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; - File d = File(edge_distance(f)); + int d = edge_distance(f); bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) diff --git a/src/position.cpp b/src/position.cpp index 40ebb959..f5ff3da1 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -591,7 +591,7 @@ bool Position::pseudo_legal(const Move m) const { if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture && !((from + pawn_push(us) == to) && empty(to)) // Not a single push && !( (from + 2 * pawn_push(us) == to) // Not a double push - && (rank_of(from) == relative_rank(us, RANK_2)) + && (relative_rank(us, from) == RANK_2) && empty(to) && empty(to - pawn_push(us)))) return false; diff --git a/src/position.h b/src/position.h index 34a6abc3..ae624926 100644 --- a/src/position.h +++ b/src/position.h @@ -98,7 +98,7 @@ public: bool is_on_semiopen_file(Color c, Square s) const; // Castling - int castling_rights(Color c) const; + CastlingRights castling_rights(Color c) const; bool can_castle(CastlingRights cr) const; bool castling_impeded(CastlingRights cr) const; Square castling_rook_square(CastlingRights cr) const; @@ -268,7 +268,7 @@ inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } -inline int Position::castling_rights(Color c) const { +inline CastlingRights Position::castling_rights(Color c) const { return c & CastlingRights(st->castlingRights); } @@ -399,8 +399,7 @@ inline Thread* Position::this_thread() const { inline void Position::put_piece(Piece pc, Square s) { board[s] = pc; - byTypeBB[ALL_PIECES] |= s; - byTypeBB[type_of(pc)] |= s; + byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s; byColorBB[color_of(pc)] |= s; index[s] = pieceCount[pc]++; pieceList[pc][index[s]] = s; diff --git a/src/search.cpp b/src/search.cpp index 5e9cd463..3b3c0f2a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -272,9 +272,9 @@ void MainThread::search() { Thread* bestThread = this; // Check if there are threads with a better score than main thread - if ( Options["MultiPV"] == 1 + if ( int(Options["MultiPV"]) == 1 && !Limits.depth - && !(Skill(Options["Skill Level"]).enabled() || Options["UCI_LimitStrength"]) + && !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) && rootMoves[0].pv[0] != MOVE_NONE) { std::map votes; @@ -350,17 +350,17 @@ void Thread::search() { if (mainThread) { if (mainThread->bestPreviousScore == VALUE_INFINITE) - for (int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) mainThread->iterValue[i] = VALUE_ZERO; else - for (int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) mainThread->iterValue[i] = mainThread->bestPreviousScore; } std::copy(&lowPlyHistory[2][0], &lowPlyHistory.back().back() + 1, &lowPlyHistory[0][0]); std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); - size_t multiPV = Options["MultiPV"]; + size_t multiPV = size_t(Options["MultiPV"]); // Pick integer skill levels, but non-deterministically round up or down // such that the average integer skill corresponds to the input floating point one. @@ -540,8 +540,8 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; + double fallingEval = (332 + 6 * (mainThread->bestPreviousScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 704.0; fallingEval = Utility::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index adc45d58..6bfd78ad 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -530,7 +530,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) { // I(k) = k * d->span + d->span / 2 (1) // First step is to get the 'k' of the I(k) nearest to our idx, using definition (1) - uint32_t k = idx / d->span; + uint32_t k = uint32_t(idx / d->span); // Then we read the corresponding SparseIndex[] entry uint32_t block = number(&d->sparseIndex[k].block); @@ -576,7 +576,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) { // All the symbols of a given length are consecutive integers (numerical // sequence property), so we can compute the offset of our symbol of // length len, stored at the beginning of buf64. - sym = (buf64 - d->base64[len]) >> (64 - len - d->minSymLen); + sym = Sym((buf64 - d->base64[len]) >> (64 - len - d->minSymLen)); // Now add the value of the lowest symbol of length len to get our symbol sym += number(&d->lowestSym[len]); @@ -984,7 +984,7 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) { d->sizeofBlock = 1ULL << *data++; d->span = 1ULL << *data++; - d->sparseIndexSize = (tbSize + d->span - 1) / d->span; // Round up + d->sparseIndexSize = size_t((tbSize + d->span - 1) / d->span); // Round up auto padding = number(data++); d->blocksNum = number(data); data += sizeof(uint32_t); d->blockLengthSize = d->blocksNum + padding; // Padded to ensure SparseIndex[] diff --git a/src/thread.cpp b/src/thread.cpp index 2e0c216e..c1713122 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -151,7 +151,7 @@ void ThreadPool::set(size_t requested) { clear(); // Reallocate the hash with the new threadpool size - TT.resize(Options["Hash"]); + TT.resize(size_t(Options["Hash"])); // Init thread number dependent search params. Search::init(); diff --git a/src/timeman.cpp b/src/timeman.cpp index 45e9db58..1f598745 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -35,10 +35,10 @@ TimeManagement Time; // Our global time management object void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { - TimePoint minThinkingTime = Options["Minimum Thinking Time"]; - TimePoint moveOverhead = Options["Move Overhead"]; - TimePoint slowMover = Options["Slow Mover"]; - TimePoint npmsec = Options["nodestime"]; + TimePoint minThinkingTime = TimePoint(Options["Minimum Thinking Time"]); + TimePoint moveOverhead = TimePoint(Options["Move Overhead"]); + TimePoint slowMover = TimePoint(Options["Slow Mover"]); + TimePoint npmsec = TimePoint(Options["nodestime"]); // opt_scale is a percentage of available time to use for the current move. // max_scale is a multiplier applied to optimumTime. @@ -91,8 +91,8 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) { } // Never use more than 80% of the available time for this move - optimumTime = std::max(minThinkingTime, opt_scale * timeLeft); - maximumTime = std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime); + optimumTime = std::max(minThinkingTime, TimePoint(opt_scale * timeLeft)); + maximumTime = TimePoint(std::min(0.8 * limits.time[us] - moveOverhead, max_scale * optimumTime)); if (Options["Ponder"]) optimumTime += optimumTime / 4; diff --git a/src/tt.cpp b/src/tt.cpp index 4e06bed9..0a3c54a1 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -94,8 +94,8 @@ void TranspositionTable::clear() { WinProcGroup::bindThisThread(idx); // Each thread will zero its part of the hash table - const size_t stride = clusterCount / Options["Threads"], - start = stride * idx, + const size_t stride = size_t(clusterCount / Options["Threads"]), + start = size_t(stride * idx), len = idx != Options["Threads"] - 1 ? stride : clusterCount - start; @@ -103,7 +103,7 @@ void TranspositionTable::clear() { }); } - for (std::thread& th: threads) + for (std::thread& th : threads) th.join(); } diff --git a/src/tune.cpp b/src/tune.cpp index fe61151f..696b4cb8 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -83,7 +83,7 @@ template<> void Tune::Entry::init_option() { make_option(name, value, range template<> void Tune::Entry::read_option() { if (Options.count(name)) - value = Options[name]; + value = int(Options[name]); } template<> void Tune::Entry::init_option() { make_option(name, value, range); } @@ -100,10 +100,10 @@ template<> void Tune::Entry::init_option() { template<> void Tune::Entry::read_option() { if (Options.count("m" + name)) - value = make_score(Options["m" + name], eg_value(value)); + value = make_score(int(Options["m" + name]), eg_value(value)); if (Options.count("e" + name)) - value = make_score(mg_value(value), Options["e" + name]); + value = make_score(mg_value(value), int(Options["e" + name])); } // Instead of a variable here we have a PostUpdate function: just call it diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 66fd42d1..16add76e 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -38,9 +38,9 @@ namespace UCI { /// 'On change' actions, triggered by an option's value change void on_clear_hash(const Option&) { Search::clear(); } -void on_hash_size(const Option& o) { TT.resize(o); } +void on_hash_size(const Option& o) { TT.resize(size_t(o)); } void on_logger(const Option& o) { start_logger(o); } -void on_threads(const Option& o) { Threads.set(o); } +void on_threads(const Option& o) { Threads.set(size_t(o)); } void on_tb_path(const Option& o) { Tablebases::init(o); } From 86575bcdd88f6d211b4f182966e44a40faf1e315 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 23 May 2020 12:22:34 +0300 Subject: [PATCH 269/281] Queen Mobility Tweak It's ok to have low mobility values for the Queen in the middlegame, but it's absolutely not ok to have low mobility values for the Queen in the endgame. Decrease penalty for bad mobility in MG and increase it in EG. STC: LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 17264 W: 3424 L: 3206 D: 10634 Ptnml(0-2): 279, 2004, 3893, 2132, 324 https://tests.stockfishchess.org/tests/view/5ec8f9c1526edcbe9091eba1 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 175016 W: 22071 L: 21404 D: 131541 Ptnml(0-2): 1195, 15796, 52914, 16353, 1250 https://tests.stockfishchess.org/tests/view/5ec9057c404591b2793007df closes https://github.com/official-stockfish/Stockfish/pull/2697 Bench: 4487054 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2d1f4b9e..7aa67f26 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -99,7 +99,7 @@ namespace { { S(-60,-78), S(-20,-17), S( 2, 23), S( 3, 39), S( 3, 70), S( 11, 99), // Rook S( 22,103), S( 31,121), S( 40,134), S( 40,139), S( 41,158), S( 48,164), S( 57,168), S( 57,169), S( 62,172) }, - { S(-34,-36), S(-15,-21), S(-10, -1), S(-10, 22), S( 20, 41), S( 23, 56), // Queen + { S(-30,-48), S(-12,-30), S( -8, -7), S( -9, 19), S( 20, 40), S( 23, 55), // Queen S( 23, 59), S( 35, 75), S( 38, 78), S( 53, 96), S( 64, 96), S( 65,100), S( 65,121), S( 66,127), S( 67,131), S( 67,133), S( 72,136), S( 72,141), S( 77,147), S( 79,150), S( 93,151), S(108,168), S(108,168), S(108,171), From 81c58855e43572e5493497a9894ac5060936005c Mon Sep 17 00:00:00 2001 From: ElbertoOne Date: Sat, 23 May 2020 13:14:02 +0200 Subject: [PATCH 270/281] Remove and replace DoubledIsolated penalty by Doubled The values for both penalties were very close, so DoubledIsolated can be removed and replaced by Doubled. Passed STC (simplification): https://tests.stockfishchess.org/tests/view/5ec7c18e2a585b485af54407 LLR: 2.97 (-2.94,2.94) {-1.50,0.50} Total: 105360 W: 20175 L: 20136 D: 65049 Ptnml(0-2): 1803, 12230, 24572, 12275, 1800 Passed LTC: LLR: 2.94 (-2.94,2.94) {-1.50,0.50} Total: 15440 W: 1978 L: 1877 D: 11585 Ptnml(0-2): 92, 1405, 4667, 1422, 134 closes https://github.com/official-stockfish/Stockfish/pull/2696 Bench: 4668875 --- src/pawns.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index b883dda2..f9dbcae2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -32,13 +32,12 @@ namespace { #define S(mg, eg) make_score(mg, eg) // Pawn penalties - constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); - constexpr Score Doubled = S(11, 56); - constexpr Score DoubledIsolated = S(15, 57); - constexpr Score Isolated = S( 5, 15); - constexpr Score WeakLever = S( 0, 56); - constexpr Score WeakUnopposed = S(13, 27); + constexpr Score Backward = S( 9, 24); + constexpr Score BlockedStorm = S(82, 82); + constexpr Score Doubled = S(11, 56); + constexpr Score Isolated = S( 5, 15); + constexpr Score WeakLever = S( 0, 56); + constexpr Score WeakUnopposed = S(13, 27); // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -151,7 +150,7 @@ namespace { if ( (ourPawns & forward_file_bb(Them, s)) && popcount(opposed) == 1 && !(theirPawns & adjacent_files_bb(s))) - score -= DoubledIsolated; + score -= Doubled; } else if (backward) From 7f2c8a2b81af19033a62845408b7ae19ed513053 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 24 May 2020 01:54:37 +0200 Subject: [PATCH 271/281] Remove attacked pawns from storm evaluation STC: LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 54456 W: 11009 L: 10737 D: 32710 Ptnml(0-2): 929, 6326, 12523, 6444, 1006 https://tests.stockfishchess.org/tests/view/5ec962e4404591b2793008a5 LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 62448 W: 9018 L: 8664 D: 44766 Ptnml(0-2): 462, 5928, 18121, 6220, 493 https://tests.stockfishchess.org/tests/view/5ec976a8a586eee45aa2ab40 Non regression STC with "noob_3moves.epd" opening book LLR: 3.81 (-2.94,2.94) {-1.50,0.50} Total: 91896 W: 17770 L: 17653 D: 56473 Ptnml(0-2): 1598, 10782, 21124, 10793, 1651 https://tests.stockfishchess.org/tests/view/5ec9b83ea586eee45aa2ab96 closes https://github.com/official-stockfish/Stockfish/pull/2698 Bench 4488597 --- src/pawns.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index f9dbcae2..8354cc15 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -33,12 +33,13 @@ namespace { // Pawn penalties constexpr Score Backward = S( 9, 24); - constexpr Score BlockedStorm = S(82, 82); constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); constexpr Score WeakLever = S( 0, 56); constexpr Score WeakUnopposed = S(13, 27); + constexpr Score BlockedStorm[RANK_NB] = {S( 0, 0), S( 0, 0), S( 76, 78), S(-10, 15), S(-7, 10), S(-4, 6), S(-1, 2)}; + // Connected pawn bonus constexpr int Connected[RANK_NB] = { 0, 7, 8, 12, 29, 48, 86 }; @@ -200,8 +201,8 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { constexpr Color Them = ~Us; Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); - Bitboard ourPawns = b & pos.pieces(Us); - Bitboard theirPawns = b & pos.pieces(Them); + Bitboard ourPawns = b & pos.pieces(Us) & ~pawnAttacks[Them]; + Bitboard theirPawns = b & pos.pieces(Them) & ~pawnAttacks[Us]; Score bonus = make_score(5, 5); @@ -218,7 +219,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { bonus += make_score(ShelterStrength[d][ourRank], 0); if (ourRank && (ourRank == theirRank - 1)) - bonus -= BlockedStorm * int(theirRank == RANK_3); + bonus -= BlockedStorm[theirRank]; else bonus -= make_score(UnblockedStorm[d][theirRank], 0); } From d40d04c17ceadff6f15d1cb1d4d469f823a35a02 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Mon, 25 May 2020 21:14:07 +0300 Subject: [PATCH 272/281] Give bonus for rooks that are alligned with enemy kingring The idea of this patch is that if rooks are not directly attacking the opponent king, they can support king attacks staying behind pawns or minor pieces and be really deadly if position slightly opens up at enemy king ring ranks. Loosely based on some stockfish games where it underestimated attacks on it king when enemy has one or two rooks supporting pawn pushes towards it king. passed STC https://tests.stockfishchess.org/tests/view/5ecb093680f2c838b96550f9 LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 53672 W: 10535 L: 10265 D: 32872 Ptnml(0-2): 952, 6210, 12258, 6448, 968 passed LTC https://tests.stockfishchess.org/tests/view/5ecb639f80f2c838b9655117 LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 62424 W: 8094 L: 7748 D: 46582 Ptnml(0-2): 426, 5734, 18565, 6042, 445 closes https://github.com/official-stockfish/Stockfish/pull/2700 Bench: 4663220 --- src/evaluate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7aa67f26..8e8cc091 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -143,6 +143,7 @@ namespace { constexpr Score PassedFile = S( 11, 8); constexpr Score PawnlessFlank = S( 17, 95); constexpr Score RestrictedPiece = S( 7, 7); + constexpr Score RookOnKingRing = S( 16, 0); constexpr Score RookOnQueenFile = S( 5, 9); constexpr Score SliderOnQueen = S( 59, 18); constexpr Score ThreatByKing = S( 24, 89); @@ -287,6 +288,8 @@ namespace { kingAttackersWeight[Us] += KingAttackWeights[Pt]; kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } + else if (Pt == ROOK && (file_bb(s) & kingRing[Them])) + score += RookOnKingRing; int mob = popcount(b & mobilityArea[Us]); From fb8095718bd0789d2743fa6216c6aa522555dc4b Mon Sep 17 00:00:00 2001 From: xoto10 Date: Tue, 26 May 2020 00:27:05 +0100 Subject: [PATCH 273/281] In BlockedStorm, theirPawns includes ones attacked by us. Pawns heading towards our king tend to be dangerous whether or not we are attacking them so remove this test. STC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 91184 W: 18196 L: 18137 D: 54851 Ptnml(0-2): 1580, 10656, 21092, 10653, 1611 https://tests.stockfishchess.org/tests/view/5ecc3f7080f2c838b9655841 LTC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 14152 W: 2045 L: 1937 D: 10170 Ptnml(0-2): 99, 1325, 4130, 1413, 109 https://tests.stockfishchess.org/tests/view/5ecc4f3180f2c838b9655861 closes https://github.com/official-stockfish/Stockfish/pull/2702 Bench 4828973 --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 8354cc15..3ce89630 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -202,7 +202,7 @@ Score Entry::evaluate_shelter(const Position& pos, Square ksq) { Bitboard b = pos.pieces(PAWN) & ~forward_ranks_bb(Them, ksq); Bitboard ourPawns = b & pos.pieces(Us) & ~pawnAttacks[Them]; - Bitboard theirPawns = b & pos.pieces(Them) & ~pawnAttacks[Us]; + Bitboard theirPawns = b & pos.pieces(Them); Score bonus = make_score(5, 5); From a5e3b4eddede900c1df610e8e25026a79d706500 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 28 May 2020 09:48:31 -0600 Subject: [PATCH 274/281] Consolidate all attacks bitboards This is a non-functional simplification that simplifies getting attacks bitboards. * consolidates all attacks to attacks_bb (remove Position::attacks_from(..)). * attacks_bb(square) gets pseudo attacks * attacks_bb(square, bitboard) gets attacks considering occupied squares in the bitboard). * pawn_attacks_bb(Color, Square) gets pawn attacks like other pawn attack bitboards. * Wraps all access to PawnAttacks arrays and PseudoAttacks arrays and adds asserts as appropriate. Passed STC LLR: 2.95 (-2.94,2.94) {-1.50,0.50} Total: 90208 W: 17533 L: 17482 D: 55193 Ptnml(0-2): 1412, 10232, 21798, 10217, 1445 https://tests.stockfishchess.org/tests/view/5ece996275787cc0c05d9790 closes https://github.com/official-stockfish/Stockfish/pull/2703 No functional change --- src/bitbase.cpp | 10 +++++----- src/bitboard.h | 35 ++++++++++++++++++++++++++++++----- src/endgame.cpp | 10 +++++----- src/evaluate.cpp | 16 ++++++++-------- src/movegen.cpp | 20 ++++++++++---------- src/pawns.cpp | 6 +++--- src/position.cpp | 30 +++++++++++++++--------------- src/position.h | 21 --------------------- 8 files changed, 76 insertions(+), 72 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index bef2dc49..be6f0d0a 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -112,7 +112,7 @@ namespace { if ( distance(ksq[WHITE], ksq[BLACK]) <= 1 || ksq[WHITE] == psq || ksq[BLACK] == psq - || (stm == WHITE && (PawnAttacks[WHITE][psq] & ksq[BLACK]))) + || (stm == WHITE && (pawn_attacks_bb(WHITE, psq) & ksq[BLACK]))) result = INVALID; // Immediate win if a pawn can be promoted without getting captured @@ -120,13 +120,13 @@ namespace { && rank_of(psq) == RANK_7 && ksq[stm] != psq + NORTH && ( distance(ksq[~stm], psq + NORTH) > 1 - || (PseudoAttacks[KING][ksq[stm]] & (psq + NORTH)))) + || (attacks_bb(ksq[stm]) & (psq + NORTH)))) result = WIN; // Immediate draw if it is a stalemate or a king captures undefended pawn else if ( stm == BLACK - && ( !(PseudoAttacks[KING][ksq[stm]] & ~(PseudoAttacks[KING][ksq[~stm]] | PawnAttacks[~stm][psq])) - || (PseudoAttacks[KING][ksq[stm]] & psq & ~PseudoAttacks[KING][ksq[~stm]]))) + && ( !(attacks_bb(ksq[stm]) & ~(attacks_bb(ksq[~stm]) | pawn_attacks_bb(~stm, psq))) + || (attacks_bb(ksq[stm]) & psq & ~attacks_bb(ksq[~stm])))) result = DRAW; // Position will be classified later @@ -149,7 +149,7 @@ namespace { const Result Bad = (stm == WHITE ? DRAW : WIN); Result r = INVALID; - Bitboard b = PseudoAttacks[KING][ksq[stm]]; + Bitboard b = attacks_bb(ksq[stm]); while (b) r |= stm == WHITE ? db[index(BLACK, ksq[BLACK] , pop_lsb(&b), psq)] diff --git a/src/bitboard.h b/src/bitboard.h index 9252c3dc..93f838f8 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -176,6 +176,12 @@ constexpr Bitboard pawn_attacks_bb(Bitboard b) { : shift(b) | shift(b); } +inline Bitboard pawn_attacks_bb(Color c, Square s) { + + assert(is_ok(s)); + return PawnAttacks[c][s]; +} + /// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the /// given color from the squares in the given bitboard. @@ -266,19 +272,38 @@ inline Bitboard safe_destination(Square s, int step) return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0); } -/// attacks_bb() returns a bitboard representing all the squares attacked by a -/// piece of type Pt (bishop or rook) placed on 's'. +/// attacks_bb(Square) returns the pseudo attacks of the give piece type +/// assuming an empty board. + +template +inline Bitboard attacks_bb(Square s) { + + assert((Pt != PAWN) && (is_ok(s))); + + return PseudoAttacks[Pt][s]; +} + +/// attacks_bb(Square, Bitboard) returns the attacks by the given piece +/// assuming the board is occupied according to the passed Bitboard. +/// Sliding piece attacks do not continue passed an occupied square. template inline Bitboard attacks_bb(Square s, Bitboard occupied) { - const Magic& m = Pt == ROOK ? RookMagics[s] : BishopMagics[s]; - return m.attacks[m.index(occupied)]; + assert((Pt != PAWN) && (is_ok(s))); + + switch (Pt) + { + case BISHOP: return BishopMagics[s].attacks[BishopMagics[s].index(occupied)]; + case ROOK : return RookMagics[s].attacks[ RookMagics[s].index(occupied)]; + case QUEEN : return attacks_bb(s, occupied) | attacks_bb(s, occupied); + default : return PseudoAttacks[Pt][s]; + } } inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) { - assert(pt != PAWN); + assert((pt != PAWN) && (is_ok(s))); switch (pt) { diff --git a/src/endgame.cpp b/src/endgame.cpp index e232da62..7b9c145e 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -391,8 +391,8 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && relative_rank(weakSide, pos.square(strongSide)) >= RANK_4 && relative_rank(weakSide, rsq) == RANK_3 && ( pos.pieces(weakSide, PAWN) - & pos.attacks_from(kingSq) - & pos.attacks_from(rsq, strongSide))) + & attacks_bb(kingSq) + & pawn_attacks_bb(strongSide, rsq))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@ -535,7 +535,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { // the corner if ( rk == RANK_6 && distance(psq + 2 * push, ksq) <= 1 - && (PseudoAttacks[BISHOP][bsq] & (psq + push)) + && (attacks_bb(bsq) & (psq + push)) && distance(bsq, psq) >= 2) return ScaleFactor(8); } @@ -670,14 +670,14 @@ ScaleFactor Endgame::operator()(const Position& pos) const { if ( ksq == blockSq1 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 - || (pos.attacks_from(blockSq2) & pos.pieces(weakSide, BISHOP)) + || (attacks_bb(blockSq2, pos.pieces()) & pos.pieces(weakSide, BISHOP)) || distance(psq1, psq2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq1 - || (pos.attacks_from(blockSq1) & pos.pieces(weakSide, BISHOP)))) + || (attacks_bb(blockSq1, pos.pieces()) & pos.pieces(weakSide, BISHOP)))) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8e8cc091..ad79db5c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -235,7 +235,7 @@ namespace { mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them)); // Initialize attackedBy[] for king and pawns - attackedBy[Us][KING] = pos.attacks_from(ksq); + attackedBy[Us][KING] = attacks_bb(ksq); attackedBy[Us][PAWN] = pe->pawn_attacks(Us); attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); @@ -243,7 +243,7 @@ namespace { // Init our king safety tables Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G), Utility::clamp(rank_of(ksq), RANK_2, RANK_7)); - kingRing[Us] = PseudoAttacks[KING][s] | s; + kingRing[Us] = attacks_bb(s) | s; kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@ -273,7 +273,7 @@ namespace { // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) : Pt == ROOK ? attacks_bb< ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK)) - : pos.attacks_from(s); + : attacks_bb(s, pos.pieces()); if (pos.blockers_for_king(Us) & s) b &= LineBB[pos.square(Us)][s]; @@ -323,7 +323,7 @@ namespace { * (!(attackedBy[Us][PAWN] & s) + popcount(blocked & CenterFiles)); // Penalty for all enemy pawns x-rayed - score -= BishopXRayPawns * popcount(PseudoAttacks[BISHOP][s] & pos.pieces(Them, PAWN)); + score -= BishopXRayPawns * popcount(attacks_bb(s) & pos.pieces(Them, PAWN)); // Bonus for bishop on a long diagonal which can "see" both center squares if (more_than_one(attacks_bb(s, pos.pieces(PAWN)) & Center)) @@ -438,7 +438,7 @@ namespace { unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks - knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + knightChecks = attacks_bb(ksq) & attackedBy[Them][KNIGHT]; if (knightChecks & safe) kingDanger += more_than_one(knightChecks & safe) ? KnightSafeCheck * 162/100 : KnightSafeCheck; @@ -564,12 +564,12 @@ namespace { Square s = pos.square(Them); safe = mobilityArea[Us] & ~stronglyProtected; - b = attackedBy[Us][KNIGHT] & pos.attacks_from(s); + b = attackedBy[Us][KNIGHT] & attacks_bb(s); score += KnightOnQueen * popcount(b & safe); - b = (attackedBy[Us][BISHOP] & pos.attacks_from(s)) - | (attackedBy[Us][ROOK ] & pos.attacks_from(s)); + b = (attackedBy[Us][BISHOP] & attacks_bb(s, pos.pieces())) + | (attackedBy[Us][ROOK ] & attacks_bb(s, pos.pieces())); score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]); } diff --git a/src/movegen.cpp b/src/movegen.cpp index 5787d174..81b8c929 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -40,7 +40,7 @@ namespace { // Knight promotion is the only promotion that can give a direct check // that's not already included in the queen promotion. - if (Type == QUIET_CHECKS && (PseudoAttacks[KNIGHT][to] & ksq)) + if (Type == QUIET_CHECKS && (attacks_bb(to) & ksq)) *moveList++ = make(to - D, to, KNIGHT); else (void)ksq; // Silence a warning under MSVC @@ -84,8 +84,8 @@ namespace { if (Type == QUIET_CHECKS) { - b1 &= pos.attacks_from(ksq, Them); - b2 &= pos.attacks_from(ksq, Them); + b1 &= pawn_attacks_bb(Them, ksq); + b2 &= pawn_attacks_bb(Them, ksq); // Add pawn pushes which give discovered check. This is possible only // if the pawn is not on the same file as the enemy king, because we @@ -166,7 +166,7 @@ namespace { if (Type == EVASIONS && !(target & (pos.ep_square() - Up))) return moveList; - b1 = pawnsNotOn7 & pos.attacks_from(pos.ep_square(), Them); + b1 = pawnsNotOn7 & pawn_attacks_bb(Them, pos.ep_square()); assert(b1); @@ -192,14 +192,14 @@ namespace { if (Checks) { if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) - && !(PseudoAttacks[Pt][from] & target & pos.check_squares(Pt))) + && !(attacks_bb(from) & target & pos.check_squares(Pt))) continue; if (pos.blockers_for_king(~us) & from) continue; } - Bitboard b = pos.attacks_from(from) & target; + Bitboard b = attacks_bb(from, pos.pieces()) & target; if (Checks) b &= pos.check_squares(Pt); @@ -248,7 +248,7 @@ namespace { if (Type != QUIET_CHECKS && Type != EVASIONS) { Square ksq = pos.square(Us); - Bitboard b = pos.attacks_from(ksq) & target; + Bitboard b = attacks_bb(ksq) & target; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); @@ -303,10 +303,10 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Square from = pop_lsb(&dc); PieceType pt = type_of(pos.piece_on(from)); - Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces(); + Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces(); if (pt == KING) - b &= ~PseudoAttacks[QUEEN][pos.square(~us)]; + b &= ~attacks_bb(pos.square(~us)); while (b) *moveList++ = make_move(from, pop_lsb(&b)); @@ -336,7 +336,7 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { sliderAttacks |= LineBB[ksq][pop_lsb(&sliders)] & ~pos.checkers(); // Generate evasions for king, capture and non capture moves - Bitboard b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; + Bitboard b = attacks_bb(ksq) & ~pos.pieces(us) & ~sliderAttacks; while (b) *moveList++ = make_move(ksq, pop_lsb(&b)); diff --git a/src/pawns.cpp b/src/pawns.cpp index 3ce89630..467137b3 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -100,8 +100,8 @@ namespace { opposed = theirPawns & forward_file_bb(Us, s); blocked = theirPawns & (s + Up); stoppers = theirPawns & passed_pawn_span(Us, s); - lever = theirPawns & PawnAttacks[Us][s]; - leverPush = theirPawns & PawnAttacks[Us][s + Up]; + lever = theirPawns & pawn_attacks_bb(Us, s); + leverPush = theirPawns & pawn_attacks_bb(Us, s + Up); doubled = ourPawns & (s - Up); neighbours = ourPawns & adjacent_files_bb(s); phalanx = neighbours & rank_bb(s); @@ -253,7 +253,7 @@ Score Entry::do_king_safety(const Position& pos) { Bitboard pawns = pos.pieces(Us, PAWN); int minPawnDist = 6; - if (pawns & PseudoAttacks[KING][ksq]) + if (pawns & attacks_bb(ksq)) minPawnDist = 1; else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); diff --git a/src/position.cpp b/src/position.cpp index f5ff3da1..d2e33b30 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -139,7 +139,7 @@ void Position::init() { for (Piece pc : Pieces) for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2) - if (PseudoAttacks[type_of(pc)][s1] & s2) + if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2)) { Move move = make_move(s1, s2); Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side; @@ -319,10 +319,10 @@ void Position::set_check_info(StateInfo* si) const { Square ksq = square(~sideToMove); - si->checkSquares[PAWN] = attacks_from(ksq, ~sideToMove); - si->checkSquares[KNIGHT] = attacks_from(ksq); - si->checkSquares[BISHOP] = attacks_from(ksq); - si->checkSquares[ROOK] = attacks_from(ksq); + si->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq); + si->checkSquares[KNIGHT] = attacks_bb(ksq); + si->checkSquares[BISHOP] = attacks_bb(ksq, pieces()); + si->checkSquares[ROOK] = attacks_bb(ksq, pieces()); si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK]; si->checkSquares[KING] = 0; } @@ -455,8 +455,8 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners pinners = 0; // Snipers are sliders that attack 's' when a piece and other snipers are removed - Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) - | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; + Bitboard snipers = ( (attacks_bb< ROOK>(s) & pieces(QUEEN, ROOK)) + | (attacks_bb(s) & pieces(QUEEN, BISHOP))) & sliders; Bitboard occupancy = pieces() ^ snipers; while (snipers) @@ -480,12 +480,12 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners Bitboard Position::attackers_to(Square s, Bitboard occupied) const { - return (attacks_from(s, BLACK) & pieces(WHITE, PAWN)) - | (attacks_from(s, WHITE) & pieces(BLACK, PAWN)) - | (attacks_from(s) & pieces(KNIGHT)) + return (pawn_attacks_bb(BLACK, s) & pieces(WHITE, PAWN)) + | (pawn_attacks_bb(WHITE, s) & pieces(BLACK, PAWN)) + | (attacks_bb(s) & pieces(KNIGHT)) | (attacks_bb< ROOK>(s, occupied) & pieces( ROOK, QUEEN)) | (attacks_bb(s, occupied) & pieces(BISHOP, QUEEN)) - | (attacks_from(s) & pieces(KING)); + | (attacks_bb(s) & pieces(KING)); } @@ -588,7 +588,7 @@ bool Position::pseudo_legal(const Move m) const { if ((Rank8BB | Rank1BB) & to) return false; - if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture + if ( !(pawn_attacks_bb(us, from) & pieces(~us) & to) // Not a capture && !((from + pawn_push(us) == to) && empty(to)) // Not a single push && !( (from + 2 * pawn_push(us) == to) // Not a double push && (relative_rank(us, from) == RANK_2) @@ -596,7 +596,7 @@ bool Position::pseudo_legal(const Move m) const { && empty(to - pawn_push(us)))) return false; } - else if (!(attacks_from(type_of(pc), from) & to)) + else if (!(attacks_bb(type_of(pc), from, pieces()) & to)) return false; // Evasions generator already takes care to avoid some kind of illegal moves @@ -670,7 +670,7 @@ bool Position::gives_check(Move m) const { Square kto = relative_square(sideToMove, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(sideToMove, rfrom > kfrom ? SQ_F1 : SQ_D1); - return (PseudoAttacks[ROOK][rto] & square(~sideToMove)) + return (attacks_bb(rto) & square(~sideToMove)) && (attacks_bb(rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square(~sideToMove)); } default: @@ -794,7 +794,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { { // Set en-passant square if the moved pawn can be captured if ( (int(to) ^ int(from)) == 16 - && (attacks_from(to - pawn_push(us), us) & pieces(them, PAWN))) + && (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN))) { st->epSquare = to - pawn_push(us); k ^= Zobrist::enpassant[file_of(st->epSquare)]; diff --git a/src/position.h b/src/position.h index ae624926..8f8c8f7a 100644 --- a/src/position.h +++ b/src/position.h @@ -112,9 +112,6 @@ public: // Attacks to/from a given square Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s, Bitboard occupied) const; - Bitboard attacks_from(PieceType pt, Square s) const; - template Bitboard attacks_from(Square s) const; - template Bitboard attacks_from(Square s, Color c) const; Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; // Properties of moves @@ -284,24 +281,6 @@ inline Square Position::castling_rook_square(CastlingRights cr) const { return castlingRookSquare[cr]; } -template -inline Bitboard Position::attacks_from(Square s) const { - static_assert(Pt != PAWN, "Pawn attacks need color"); - - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, pieces()) - : Pt == QUEEN ? attacks_from(s) | attacks_from(s) - : PseudoAttacks[Pt][s]; -} - -template<> -inline Bitboard Position::attacks_from(Square s, Color c) const { - return PawnAttacks[c][s]; -} - -inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, pieces()); -} - inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, pieces()); } From 616eb60008308f686930c0c94116aab170398dc1 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 28 May 2020 22:34:43 +0200 Subject: [PATCH 275/281] Less pruning in draw PV lines. no futility pruning for certain captures if the PvNode has a draw eval. passed STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 59392 W: 11576 L: 11302 D: 36514 Ptnml(0-2): 977, 6816, 13920, 6922, 1061 https://tests.stockfishchess.org/tests/view/5ed0b1bb042fa6d77c355295 passed LTC: LLR: 2.94 (-2.94,2.94) {0.25,1.75} Total: 64040 W: 8273 L: 7923 D: 47844 Ptnml(0-2): 424, 5842, 19220, 6028, 506 https://tests.stockfishchess.org/tests/view/5ed145e0042fa6d77c35531c closes https://github.com/official-stockfish/Stockfish/pull/2705 Bench: 4704615 --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index 3b3c0f2a..4747beb2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1055,6 +1055,7 @@ moves_loop: // When in check, search starts from here // Futility pruning for captures if ( !givesCheck && lmrDepth < 6 + && !(PvNode && abs(bestValue) < 2) && !ss->inCheck && ss->staticEval + 270 + 384 * lmrDepth + PieceValue[MG][type_of(pos.piece_on(to_sq(move)))] <= alpha) continue; From 8c3d9d996af7aa34f019785818eecbeb9338b95f Mon Sep 17 00:00:00 2001 From: ElbertoOne Date: Sun, 31 May 2020 16:39:03 +0200 Subject: [PATCH 276/281] Isolated pawns tweak Give opposed doubled isolated pawns only the Doubled penalty. The other isolated pawns get the Isolated penalty and the WeakUnopposed penalty. The popcount condition has been replaced with an opposed check, which is non-functional, but probably gives a speed-up. Passed STC (https://tests.stockfishchess.org/tests/view/5ed0f0f0042fa6d77c3552f5): LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 121832 W: 23562 L: 23195 D: 75075 Ptnml(0-2): 2092, 14064, 28313, 14279, 2168 LTC: (https://tests.stockfishchess.org/tests/view/5ed22e40042fa6d77c355387) LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 103368 W: 13232 L: 12768 D: 77368 Ptnml(0-2): 693, 9484, 30919, 9842, 746 closes https://github.com/official-stockfish/Stockfish/pull/2706 Bench: 4085694 --- src/pawns.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 467137b3..c1119a41 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -145,13 +145,13 @@ namespace { else if (!neighbours) { - score -= Isolated - + WeakUnopposed * !opposed; - - if ( (ourPawns & forward_file_bb(Them, s)) - && popcount(opposed) == 1 + if ( opposed + && (ourPawns & forward_file_bb(Them, s)) && !(theirPawns & adjacent_files_bb(s))) score -= Doubled; + else + score -= Isolated + + WeakUnopposed * !opposed; } else if (backward) From d1ec10cd4fe1e67114178f444cfebd2ff1183408 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 31 May 2020 17:00:47 +0200 Subject: [PATCH 277/281] Give bonus for bishops that are alligned with enemy kingring. Inspired by the succesful patch "Give bonus for rooks that are alligned with enemy kingring" from Vizvezdenec, this idea has been reused for bishops. Here, we only consider attacks that are not blocked by any pawn. Also we have a 50% higher bonus than for the rooks. STC: LLR: 2.94 (-2.94,2.94) {-0.50,1.50} Total: 68960 W: 13495 L: 13202 D: 42263 Ptnml(0-2): 1213, 8018, 15802, 8157, 1290 https://tests.stockfishchess.org/tests/view/5ed27495042fa6d77c3553aa LTC: LLR: 2.96 (-2.94,2.94) {0.25,1.75} Total: 54560 W: 7105 L: 6780 D: 40675 Ptnml(0-2): 379, 4986, 16254, 5253, 408 https://tests.stockfishchess.org/tests/view/5ed30375596e6dc1e1f97425 closes https://github.com/official-stockfish/Stockfish/pull/2708 Bench: 4860021 --- src/evaluate.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ad79db5c..dc7134a8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -128,6 +128,7 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); + constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score CorneredBishop = S( 50, 50); constexpr Score FlankAttacks = S( 8, 0); @@ -288,9 +289,13 @@ namespace { kingAttackersWeight[Us] += KingAttackWeights[Pt]; kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]); } + else if (Pt == ROOK && (file_bb(s) & kingRing[Them])) score += RookOnKingRing; + else if (Pt == BISHOP && (attacks_bb(s, pos.pieces(PAWN)) & kingRing[Them])) + score += BishopOnKingRing; + int mob = popcount(b & mobilityArea[Us]); mobility[Us] += MobilityBonus[Pt - 2][mob]; From 16566a8fcf76b9b72b6e746f318f77045df90017 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Tue, 2 Jun 2020 22:27:11 +0200 Subject: [PATCH 278/281] Singular quiet LMR If ttMove is a capture and had a singular extension, it is probably the best move. No need to make a decrease of LMR on other moves. STC LLR: 2.96 (-2.94,2.94) {-0.50,1.50} Total: 41968 W: 8170 L: 7918 D: 25880 Ptnml(0-2): 733, 4770, 9726, 5022, 733 https://tests.stockfishchess.org/tests/view/5ed6b666f29b40b0fc95a884 LTC LLR: 2.95 (-2.94,2.94) {0.25,1.75} Total: 71376 W: 9200 L: 8827 D: 53349 Ptnml(0-2): 486, 6544, 21342, 6743, 573 https://tests.stockfishchess.org/tests/view/5ed7578bf29b40b0fc95a8c9 closes https://github.com/official-stockfish/Stockfish/pull/2713 Bench: 4733799 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4747beb2..1e133447 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -630,7 +630,8 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; bool ttHit, ttPv, formerPv, givesCheck, improving, didLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, + ttCapture, singularQuietLMR; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -971,7 +972,7 @@ moves_loop: // When in check, search starts from here depth > 12 ? ss->ply : MAX_PLY); value = bestValue; - singularLMR = moveCountPruning = false; + singularQuietLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); // Mark this node as being searched @@ -1092,7 +1093,7 @@ moves_loop: // When in check, search starts from here if (value < singularBeta) { extension = 1; - singularLMR = true; + singularQuietLMR = !ttCapture; } // Multi-cut pruning @@ -1198,7 +1199,7 @@ moves_loop: // When in check, search starts from here r--; // Decrease reduction if ttMove has been singularly extended (~3 Elo) - if (singularLMR) + if (singularQuietLMR) r -= 1 + formerPv; if (!captureOrPromotion) From 784263596ff9b01187341274b6f3cbd8971a2d2c Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 31 May 2020 16:51:38 +0200 Subject: [PATCH 279/281] Minimal thinking time, even if only one rootMove. without search, the eval returned can be misleading (e.g. mate instead of draw), leading to wrong adjudication. With a minimal search, this is avoided. This patch leads to 1ms long searches if there is only 1 move, similar patches all indicate a small Elo gain. Fixes https://github.com/official-stockfish/Stockfish/issues/2707 Passed non-regression STC: LLR: 2.93 (-2.94,2.94) {-1.50,0.50} Total: 22312 W: 4350 L: 4204 D: 13758 Ptnml(0-2): 323, 2488, 5437, 2536, 372 https://tests.stockfishchess.org/tests/view/5ed562b0f29b40b0fc95a7d0 closes https://github.com/official-stockfish/Stockfish/pull/2709 Bench: 4733799 --- src/search.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 1e133447..35110538 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -556,9 +556,11 @@ void Thread::search() { } double bestMoveInstability = 1 + totBestMoveChanges / Threads.size(); - // Stop the search if we have only one legal move, or if available time elapsed - if ( rootMoves.size() == 1 - || Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability) + double totalTime = rootMoves.size() == 1 ? 0 : + Time.optimum() * fallingEval * reduction * bestMoveInstability; + + // Stop the search if we have exceeded the totalTime, at least 1ms search. + if (Time.elapsed() > totalTime) { // If we are allowed to ponder do not stop the search now but // keep pondering until the GUI sends "ponderhit" or "stop". @@ -569,7 +571,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6) + && Time.elapsed() > totalTime * 0.6) Threads.increaseDepth = false; else Threads.increaseDepth = true; From fd8e88427b1268bfddc0b2ab72f639f758b7be0b Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 3 Jun 2020 18:06:49 -0600 Subject: [PATCH 280/281] small speed-up in movegen pass color as a template parameter. closes https://github.com/official-stockfish/Stockfish/pull/2715 No functional change. --- src/movegen.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 81b8c929..b57f41a9 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -179,13 +179,12 @@ namespace { } - template - ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, - Bitboard target) { + template + ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) { static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()"); - const Square* pl = pos.squares(us); + const Square* pl = pos.squares(Us); for (Square from = *pl; from != SQ_NONE; from = *++pl) { @@ -195,7 +194,7 @@ namespace { && !(attacks_bb(from) & target & pos.check_squares(Pt))) continue; - if (pos.blockers_for_king(~us) & from) + if (pos.blockers_for_king(~Us) & from) continue; } @@ -240,10 +239,10 @@ namespace { } moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target); - moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); + moveList = generate_moves(pos, moveList, target); if (Type != QUIET_CHECKS && Type != EVASIONS) { From 15e190e9428b21fbfe29ce020c456077dc5fdd04 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Sat, 6 Jun 2020 12:56:38 +0200 Subject: [PATCH 281/281] Use lowply-history also on low depths STC: https://tests.stockfishchess.org/tests/view/5ed75078f29b40b0fc95a8b9 LLR: 2.93 (-2.94,2.94) {-0.50,1.50} Total: 73928 W: 14301 L: 14005 D: 45622 Ptnml(0-2): 1243, 8572, 17096, 8752, 1301 LTC: https://tests.stockfishchess.org/tests/view/5ed895e0f29b40b0fc95a976 LLR: 2.93 (-2.94,2.94) {0.25,1.75} Total: 154848 W: 19684 L: 19074 D: 116090 Ptnml(0-2): 1048, 14108, 46627, 14468, 1173 closes https://github.com/official-stockfish/Stockfish/pull/2718 bench: 4582693 --- src/movepick.cpp | 2 +- src/search.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index e26f42ef..78102c52 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -110,7 +110,7 @@ void MovePicker::score() { + 2 * (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + 2 * (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] - + (ply < MAX_LPH ? 4 * (*lowPlyHistory)[ply][from_to(m)] : 0); + + (ply < MAX_LPH ? std::min(4, depth / 3) * (*lowPlyHistory)[ply][from_to(m)] : 0); else // Type == EVASIONS { diff --git a/src/search.cpp b/src/search.cpp index 35110538..efa7b9c5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -971,7 +971,7 @@ moves_loop: // When in check, search starts from here contHist, countermove, ss->killers, - depth > 12 ? ss->ply : MAX_PLY); + ss->ply); value = bestValue; singularQuietLMR = moveCountPruning = false;