From ea5505821dabb70eb01cc25f7b4489b0fdc17d2b Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 24 Mar 2019 10:37:38 -0600 Subject: [PATCH 01/35] Simplify Passed Pawns (#2058) This is a non-functional simplification/speedup. The truth-table for popcount(support) >= popcount(lever) - 1 is: ------------------lever ------------------0-------1---------2 support--0------X-------X---------0 -----------1------X-------X---------X -----------2------X-------X---------X Thus, it is functionally equivalent to just do: support || !more_than_one(lever) which removes the expensive popcounts and the -1. Result of 20 runs: base (...h_master.exe) = 1451680 +/- 8202 test (./stockfish ) = 1454781 +/- 8604 diff = +3101 +/- 931 STC LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 35424 W: 7768 L: 7674 D: 19982 Http://tests.stockfishchess.org/tests/view/5c970f170ebc5925cfff5e28 No functional change. --- src/pawns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 6072745b..7eb584d2 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -114,7 +114,7 @@ namespace { // which could become passed after one or two pawn pushes when are // not attacked more times than defended. if ( !(stoppers ^ lever ^ leverPush) - && popcount(support) >= popcount(lever) - 1 + && (support || !more_than_one(lever)) && popcount(phalanx) >= popcount(leverPush)) e->passedPawns[Us] |= s; From 2f11c03bbf61d8da2e2b201e4607c4aa9b5a5dc4 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 24 Mar 2019 17:40:29 +0100 Subject: [PATCH 02/35] Remove unneeded condition. (#2057) This is covered by the line just before. If we would like to protect against the piece value of e.g. a N == B, this could be done by an assert, no need to do this at runtime. No functional change. --- src/material.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/material.cpp b/src/material.cpp index 294744f4..773f332f 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -70,14 +70,12 @@ namespace { bool is_KBPsK(const Position& pos, Color us) { return pos.non_pawn_material(us) == BishopValueMg - && pos.count(us) == 1 && pos.count(us) >= 1; } bool is_KQKRPs(const Position& pos, Color us) { return !pos.count(us) && pos.non_pawn_material(us) == QueenValueMg - && pos.count(us) == 1 && pos.count(~us) == 1 && pos.count(~us) >= 1; } From 7133598a98301cf84857d39194026b876da48b96 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 24 Mar 2019 10:41:25 -0600 Subject: [PATCH 03/35] Simplify pawn asymmetry (remove use of semiopen files). (#2054) This is a functional simplification. To me, the exclusive OR of semiopenFiles here is quite convoluted. Looks like it can be removed. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 43885 W: 9731 L: 9653 D: 24501 http://tests.stockfishchess.org/tests/view/5c9041680ebc5925cfff10ea LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 68437 W: 11577 L: 11533 D: 45327 http://tests.stockfishchess.org/tests/view/5c9101740ebc5925cfff1cbf bench 3575627 --- src/evaluate.cpp | 6 +++--- src/pawns.cpp | 3 +-- src/pawns.h | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 27e1dd3d..99c0cd6e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -743,12 +743,12 @@ namespace { && (pos.pieces(PAWN) & KingSide); // Compute the initiative bonus for the attacking side - int complexity = 9 * pe->pawn_asymmetry() + int complexity = 9 * pe->passed_count() + 11 * pos.count() + 9 * outflanking + 18 * pawnsOnBothFlanks + 49 * !pos.non_pawn_material() - -121 ; + -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 @@ -776,7 +776,7 @@ namespace { if ( pos.opposite_bishops() && pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) - sf = 8 + 4 * pe->pawn_asymmetry(); + sf = 16 + 4 * pe->passed_count(); else sf = std::min(40 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide), sf); diff --git a/src/pawns.cpp b/src/pawns.cpp index 7eb584d2..b0fcfad3 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -185,8 +185,7 @@ Entry* probe(const Position& pos) { e->key = key; e->scores[WHITE] = evaluate(pos, e); e->scores[BLACK] = evaluate(pos, e); - e->asymmetry = popcount( (e->passedPawns[WHITE] | e->passedPawns[BLACK]) - | (e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK])); + e->passedCount= popcount(e->passedPawns[WHITE] | e->passedPawns[BLACK]); return e; } diff --git a/src/pawns.h b/src/pawns.h index 67f966ad..0426ec36 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 weak_unopposed(Color c) const { return weakUnopposed[c]; } - int pawn_asymmetry() const { return asymmetry; } + int passed_count() const { return passedCount; } int semiopen_file(Color c, File f) const { return semiopenFiles[c] & (1 << f); @@ -71,7 +71,7 @@ struct Entry { int castlingRights[COLOR_NB]; int semiopenFiles[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] - int asymmetry; + int passedCount; }; typedef HashTable Table; From 796d0ad70eaadf1a354d6565181331c981432f2d Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 31 Mar 2019 02:43:20 -0600 Subject: [PATCH 04/35] Accessor for SquareBB #2067 This is a non-functional code style change. If we add an accessor function for SquareBB we can consolidate all of the asserts. This is also a bit cleaner because all SquareBB accesses go through this method making future changes easier to manage. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 63406 W: 14084 L: 14045 D: 35277 http://tests.stockfishchess.org/tests/view/5c9ea6100ebc5925cfffc9af No functional change. --- src/bitboard.cpp | 2 +- src/bitboard.h | 30 ++++++++---------------------- src/pawns.cpp | 2 +- src/position.h | 2 +- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index f66d971b..e7430415 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -124,7 +124,7 @@ void Bitboards::init() { if (PseudoAttacks[pt][s1] & s2) { LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; - BetweenBB[s1][s2] = attacks_bb(pt, s1, SquareBB[s2]) & attacks_bb(pt, s2, SquareBB[s1]); + BetweenBB[s1][s2] = attacks_bb(pt, s1, square_bb(s2)) & attacks_bb(pt, s2, square_bb(s1)); } } } diff --git a/src/bitboard.h b/src/bitboard.h index af7b592a..6907f184 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -106,30 +106,16 @@ extern Magic BishopMagics[SQUARE_NB]; /// Overloads of bitwise operators between a Bitboard and a Square for testing /// whether a given bit is set in a bitboard, and for setting and clearing bits. -inline Bitboard operator&(Bitboard b, Square s) { +inline Bitboard square_bb(Square s) { assert(s >= SQ_A1 && s <= SQ_H8); - return b & SquareBB[s]; -} - -inline Bitboard operator|(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); - return b | SquareBB[s]; -} - -inline Bitboard operator^(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); - return b ^ SquareBB[s]; -} - -inline Bitboard& operator|=(Bitboard& b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); - return b |= SquareBB[s]; -} - -inline Bitboard& operator^=(Bitboard& b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); - return b ^= SquareBB[s]; + return SquareBB[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^( 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); } constexpr bool more_than_one(Bitboard b) { return b & (b - 1); diff --git a/src/pawns.cpp b/src/pawns.cpp index b0fcfad3..88474751 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -118,7 +118,7 @@ namespace { && popcount(phalanx) >= popcount(leverPush)) e->passedPawns[Us] |= s; - else if ( stoppers == SquareBB[s + Up] + else if ( stoppers == square_bb(s + Up) && relative_rank(Us, s) >= RANK_5) { b = shift(support) & ~theirPawns; diff --git a/src/position.h b/src/position.h index b65522b7..ce13017d 100644 --- a/src/position.h +++ b/src/position.h @@ -413,7 +413,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 = SquareBB[from] ^ SquareBB[to]; + Bitboard fromTo = square_bb(from) ^ square_bb(to); byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo; From d1f76ebcd8cc475d08b468efe4b467e014efef14 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 31 Mar 2019 10:44:55 +0200 Subject: [PATCH 05/35] Remove duplication. (#2068) always use the implementation of gives_check in position, no need to hand-inline part of the implementation in search. LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 57895 W: 12632 L: 12582 D: 32681 http://tests.stockfishchess.org/tests/view/5c9eaa4b0ebc5925cfffc9e3 No functional change. --- src/search.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 7043e49d..3319ee94 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -116,13 +116,6 @@ namespace { 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); - inline bool gives_check(const Position& pos, Move move) { - Color us = pos.side_to_move(); - return type_of(move) == NORMAL && !(pos.blockers_for_king(~us) & pos.pieces(us)) - ? pos.check_squares(type_of(pos.moved_piece(move))) & to_sq(move) - : pos.gives_check(move); - } - // 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. template @@ -887,7 +880,7 @@ moves_loop: // When in check, search starts from here extension = DEPTH_ZERO; captureOrPromotion = pos.capture_or_promotion(move); movedPiece = pos.moved_piece(move); - givesCheck = gives_check(pos, move); + givesCheck = pos.gives_check(move); // Step 13. Extensions (~70 Elo) @@ -1313,7 +1306,7 @@ moves_loop: // When in check, search starts from here { assert(is_ok(move)); - givesCheck = gives_check(pos, move); + givesCheck = pos.gives_check(move); moveCount++; From c8589903777b6e0289640b43fae966ded442af48 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 31 Mar 2019 02:48:27 -0600 Subject: [PATCH 06/35] Replace std::mins/max with clamp function (#2062) Adding a clamp function makes some of these range limitations a bit prettier and removes some #include's. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 28117 W: 6300 L: 6191 D: 15626 http://tests.stockfishchess.org/tests/view/5c9aa1df0ebc5925cfff8fcc Non functional change. --- src/bitbase.cpp | 1 - src/bitboard.cpp | 2 +- src/bitboard.h | 3 +++ src/endgame.cpp | 1 - src/evaluate.cpp | 1 - src/material.cpp | 3 +-- src/pawns.cpp | 3 +-- src/position.cpp | 1 - src/search.cpp | 3 +-- src/thread.cpp | 1 - src/timeman.cpp | 1 - src/ucioption.cpp | 1 - 12 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 097da917..8c8c4702 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include #include diff --git a/src/bitboard.cpp b/src/bitboard.cpp index e7430415..e4287f35 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -18,8 +18,8 @@ along with this program. If not, see . */ -#include #include +#include #include "bitboard.h" #include "misc.h" diff --git a/src/bitboard.h b/src/bitboard.h index 6907f184..aa29abf2 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -249,6 +249,9 @@ template inline int distance(T2 x, T2 y); template<> inline int distance(Square x, Square y) { return distance(file_of(x), file_of(y)); } template<> inline int distance(Square x, Square y) { return distance(rank_of(x), rank_of(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/endgame.cpp b/src/endgame.cpp index 3e572205..b1b3d664 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include "bitboard.h" diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 99c0cd6e..deb8211a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include // For std::memset #include diff --git a/src/material.cpp b/src/material.cpp index 773f332f..2e68ee68 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include // For std::min #include #include // For std::memset @@ -130,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 = std::max(EndgameLimit, std::min(npm_w + npm_b, MidgameLimit)); + Value npm = 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/pawns.cpp b/src/pawns.cpp index 88474751..c9c9e599 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include "bitboard.h" @@ -208,7 +207,7 @@ Value Entry::evaluate_shelter(const Position& pos, Square ksq) { Value safety = (shift(theirPawns) & (FileABB | FileHBB) & BlockRanks & ksq) ? Value(374) : Value(5); - File center = std::max(FILE_B, std::min(FILE_G, file_of(ksq))); + File center = 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/position.cpp b/src/position.cpp index 812eabca..2bdf1009 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include // For offsetof() #include // For std::memset, std::memcmp diff --git a/src/search.cpp b/src/search.cpp index 3319ee94..4dd4d789 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include #include // For std::memset @@ -461,7 +460,7 @@ void Thread::search() { && !mainThread->stopOnPonderhit) { double fallingEval = (306 + 9 * (mainThread->previousScore - bestValue)) / 581.0; - fallingEval = std::max(0.5, std::min(1.5, fallingEval)); + 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; diff --git a/src/thread.cpp b/src/thread.cpp index 6c1d7299..64dd9e18 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include // For std::count #include #include "movegen.h" diff --git a/src/timeman.cpp b/src/timeman.cpp index 484aaa65..fafde2aa 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 813a0890..54f33c9a 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -18,7 +18,6 @@ along with this program. If not, see . */ -#include #include #include #include From 76f1807baa90eb69f66001d25df2a28533f9406f Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Sun, 31 Mar 2019 10:51:08 +0200 Subject: [PATCH 07/35] Shuffle detection #2064 Shuffle detection procedure : Shuffling positions are detected if the last 36 moves are reversible (rule50_count() > 36), the position have been already in the TT, there is a still a pawn on the board (to avoid special endings like KBN vs K). The position is then judged as a draw. An extension is realized if we already made 14 successive reversible moves in PV to accelerate the detection of the eventual draw. To go further : we can still improve the idea. The length of the tests need a lot of ressources. the limit of 36 is logic but must be checked again for special zugzwang positions, this limit can be decreased in special positions, the limit of 14 moves for extension has not been tuned. STC LLR: -2.94 (-2.94,2.94) [0.50,4.50] Total: 32595 W: 7273 L: 7275 D: 18047 Elo +0.43 http://tests.stockfishchess.org/tests/view/5c90aa330ebc5925cfff1768 LTC LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 51249 W: 8807 L: 8486 D: 33956 Elo +1.85 http://tests.stockfishchess.org/tests/view/5c90b2450ebc5925cfff1800 VLTC LLR: 2.96 (-2.94,2.94) [0.00,3.50] Total: 137974 W: 20503 L: 19983 D: 97488 Elo +1.05 http://tests.stockfishchess.org/tests/view/5c9243a90ebc5925cfff2a93 Bench: 3548313 --- src/search.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 4dd4d789..cfa737db 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -602,6 +602,15 @@ namespace { : ttHit ? tte->move() : MOVE_NONE; ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY); + // if position has been searched at higher depths and we are shuffling, return value_draw + if (pos.rule50_count() > 36 + && ss->ply > 36 + && depth < 3 * ONE_PLY + && ttHit + && tte->depth() > depth + && pos.count() > 0) + return VALUE_DRAW; + // At non-PV nodes we check for an early TT cutoff if ( !PvNode && ttHit @@ -920,6 +929,10 @@ moves_loop: // When in check, search starts from here && (pos.blockers_for_king(~us) & from_sq(move) || pos.see_ge(move))) extension = ONE_PLY; + // Shuffle extension + else if(pos.rule50_count() > 14 && ss->ply > 14 && depth < 3 * ONE_PLY && PvNode) + extension = ONE_PLY; + // Castling extension else if (type_of(move) == CASTLING) extension = ONE_PLY; From 95ba7f78d5e025499ec8124e37e9f3b769660e4a Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 25 Mar 2019 13:04:14 -0600 Subject: [PATCH 08/35] Use simple array for Pawns Connected bonus #2061 Simplification which removes the pawns connected array. Instead of storing the values in an array, the values are calculated real-time. This is about 1.6% faster on my machines. Performance: master ave nps: 159,248,672 patch ave nps: 161,905,592 STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 20363 W: 4579 L: 4455 D: 11329 http://tests.stockfishchess.org/tests/view/5c9925ba0ebc5925cfff79a6 Non functional change. --- src/main.cpp | 1 - src/pawns.cpp | 33 ++++++++------------------------- src/pawns.h | 1 - 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a093b5bf..fc78b38c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,7 +42,6 @@ int main(int argc, char* argv[]) { Position::init(); Bitbases::init(); Search::init(); - Pawns::init(); Threads.set(Options["Threads"]); Search::clear(); // After threads are up diff --git a/src/pawns.cpp b/src/pawns.cpp index c9c9e599..7edaa6e1 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -35,8 +35,8 @@ namespace { constexpr Score Doubled = S(11, 56); constexpr Score Isolated = S( 5, 15); - // Connected pawn bonus by opposed, phalanx, #support and rank - Score Connected[2][2][3][RANK_NB]; + // Connected pawn bonus + constexpr int Connected[RANK_NB] = { 0, 13, 24, 18, 65, 100, 175, 330 }; // Strength of pawn shelter for our king by [distance from edge][rank]. // RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king. @@ -128,8 +128,12 @@ namespace { // Score this pawn if (support | phalanx) - score += Connected[opposed][bool(phalanx)][popcount(support)][relative_rank(Us, s)]; - + { + int r = relative_rank(Us, s); + int v = phalanx ? Connected[r] + Connected[r + 1] : 2 * Connected[r]; + v = 17 * popcount(support) + (v >> (opposed + 1)); + score += make_score(v, v * (r - 2) / 4); + } else if (!neighbours) score -= Isolated, e->weakUnopposed[Us] += !opposed; @@ -147,27 +151,6 @@ namespace { namespace Pawns { -/// Pawns::init() initializes some tables needed by evaluation. Instead of using -/// hard-coded tables, when makes sense, we prefer to calculate them with a formula -/// to reduce independent parameters and to allow easier tuning and better insight. - -void init() { - - static constexpr int Seed[RANK_NB] = { 0, 13, 24, 18, 65, 100, 175, 330 }; - - for (int opposed = 0; opposed <= 1; ++opposed) - for (int phalanx = 0; phalanx <= 1; ++phalanx) - for (int support = 0; support <= 2; ++support) - for (Rank r = RANK_2; r < RANK_8; ++r) - { - int v = 17 * support; - v += (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed; - - Connected[opposed][phalanx][support][r] = make_score(v, v * (r - 2) / 4); - } -} - - /// Pawns::probe() looks up the current position's pawns configuration in /// the pawns hash table. It returns a pointer to the Entry if the position /// is found. Otherwise a new Entry is computed and stored there, so we don't diff --git a/src/pawns.h b/src/pawns.h index 0426ec36..71d18ee8 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -76,7 +76,6 @@ struct Entry { typedef HashTable Table; -void init(); Entry* probe(const Position& pos); } // namespace Pawns From 82ad9ce9cfb0eff33f1d781f329f7c5dc0b277eb Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 31 Mar 2019 11:47:36 +0200 Subject: [PATCH 09/35] Assorted trivial cleanups 3/2019 (#2030) No functional change. --- src/bitboard.cpp | 3 +-- src/bitboard.h | 11 +++++------ src/endgame.cpp | 19 ++++++++----------- src/material.cpp | 4 ++-- src/misc.h | 2 +- src/position.cpp | 2 +- src/position.h | 2 +- src/search.cpp | 28 ++++++++++++++-------------- src/thread.cpp | 2 +- 9 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index e4287f35..2adf2779 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -27,13 +27,12 @@ uint8_t PopCnt16[1 << 16]; uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; -Bitboard SquareBB[SQUARE_NB]; -Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; Bitboard DistanceRingBB[SQUARE_NB][8]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; +Bitboard SquareBB[SQUARE_NB]; Bitboard KingFlank[FILE_NB] = { QueenSide ^ FileDBB, QueenSide, QueenSide, diff --git a/src/bitboard.h b/src/bitboard.h index aa29abf2..77986638 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -68,13 +68,13 @@ constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); extern uint8_t PopCnt16[1 << 16]; extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; -extern Bitboard SquareBB[SQUARE_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; extern Bitboard DistanceRingBB[SQUARE_NB][8]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; extern Bitboard KingFlank[FILE_NB]; +extern Bitboard SquareBB[SQUARE_NB]; /// Magic holds all magic bitboards relevant data for a single square @@ -102,15 +102,14 @@ struct Magic { extern Magic RookMagics[SQUARE_NB]; extern Magic BishopMagics[SQUARE_NB]; - -/// Overloads of bitwise operators between a Bitboard and a Square for testing -/// whether a given bit is set in a bitboard, and for setting and clearing bits. - inline Bitboard square_bb(Square s) { assert(s >= SQ_A1 && s <= SQ_H8); return SquareBB[s]; } - + +/// Overloads of bitwise operators between a Bitboard and a Square for testing +/// whether a given bit is set in a bitboard, and for setting and clearing bits. + 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); } diff --git a/src/endgame.cpp b/src/endgame.cpp index b1b3d664..efc41a98 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -76,10 +76,7 @@ namespace { if (file_of(pos.square(strongSide)) >= FILE_E) sq = Square(sq ^ 7); // Mirror SQ_H1 -> SQ_A1 - if (strongSide == BLACK) - sq = ~sq; - - return sq; + return strongSide == WHITE ? sq : ~sq; } } // namespace @@ -285,18 +282,18 @@ Value Endgame::operator()(const Position& pos) const { } -/// KNN vs KP. Simply push the opposing king to the corner. +/// KNN vs KP. Simply push the opposing king to the corner template<> Value Endgame::operator()(const Position& pos) const { - assert(verify_material(pos, strongSide, 2 * KnightValueMg, 0)); - assert(verify_material(pos, weakSide, VALUE_ZERO, 1)); + 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 = 2 * KnightValueEg + - PawnValueEg + + PushToEdges[pos.square(weakSide)]; - return strongSide == pos.side_to_move() ? result : -result; + return strongSide == pos.side_to_move() ? result : -result; } diff --git a/src/material.cpp b/src/material.cpp index 2e68ee68..ee5d4bce 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -149,9 +149,9 @@ Entry* probe(const Position& pos) { // OK, we didn't find any special evaluation function for the current material // configuration. Is there a suitable specialized scaling function? - const EndgameBase* sf; + const auto* sf = pos.this_thread()->endgames.probe(key); - if ((sf = pos.this_thread()->endgames.probe(key)) != nullptr) + if (sf) { e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned return e; diff --git a/src/misc.h b/src/misc.h index 3cba4867..4b238df5 100644 --- a/src/misc.h +++ b/src/misc.h @@ -53,7 +53,7 @@ struct HashTable { Entry* operator[](Key key) { return &table[(uint32_t)key & (Size - 1)]; } private: - std::vector table = std::vector(Size); + std::vector table = std::vector(Size); // Allocate on the heap }; diff --git a/src/position.cpp b/src/position.cpp index 2bdf1009..84892d09 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -628,7 +628,7 @@ bool Position::pseudo_legal(const Move m) const { { // We have already handled promotion moves, so destination // cannot be on the 8th/1st rank. - if (rank_of(to) == relative_rank(us, RANK_8)) + if ((Rank8BB | Rank1BB) & to) return false; if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture diff --git a/src/position.h b/src/position.h index ce13017d..03c00148 100644 --- a/src/position.h +++ b/src/position.h @@ -413,7 +413,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 = square_bb(from) | square_bb(to); byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo; diff --git a/src/search.cpp b/src/search.cpp index cfa737db..21b669c4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -84,11 +84,10 @@ namespace { return d > 17 ? 0 : 29 * d * d + 138 * d - 134; } - // Add a small random component to draw evaluations to keep search dynamic - // and to avoid 3fold-blindness. + // Add a small random component to draw evaluations to avoid 3fold-blindness Value value_draw(Depth depth, Thread* thisThread) { return depth < 4 ? VALUE_DRAW - : VALUE_DRAW + Value(2 * (thisThread->nodes.load(std::memory_order_relaxed) % 2) - 1); + : VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); } // Skill structure is used to implement strength limit @@ -162,12 +161,12 @@ void Search::clear() { Time.availableNodes = 0; TT.clear(); Threads.clear(); - Tablebases::init(Options["SyzygyPath"]); // Free up mapped files + Tablebases::init(Options["SyzygyPath"]); // Free mapped files } -/// MainThread::search() is called by the main thread when the program receives -/// the UCI 'go' command. It searches from the root position and outputs the "bestmove". +/// MainThread::search() is started when the program receives the UCI 'go' +/// command. It searches from the root position and outputs the "bestmove". void MainThread::search() { @@ -221,8 +220,9 @@ void MainThread::search() { if (Limits.npmsec) Time.availableNodes += Limits.inc[us] - Threads.nodes_searched(); - // Check if there are threads with a better score than main thread Thread* bestThread = this; + + // Check if there are threads with a better score than main thread if ( Options["MultiPV"] == 1 && !Limits.depth && !Skill(Options["Skill Level"]).enabled() @@ -273,9 +273,9 @@ void MainThread::search() { void Thread::search() { - // To allow access to (ss-5) up to (ss+2), the stack must be oversized. + // To allow access to (ss-7) up to (ss+2), the stack must be oversized. // The former is needed to allow update_continuation_histories(ss-1, ...), - // which accesses its argument at ss-4, also near the root. + // which accesses its argument at ss-6, also near the root. // The latter is needed for statScores and killer initialization. Stack stack[MAX_PLY+10], *ss = stack+7; Move pv[MAX_PLY+1]; @@ -317,7 +317,7 @@ void Thread::search() { : Options["Analysis Contempt"] == "Black" && us == WHITE ? -ct : ct; - // In evaluate.cpp the evaluation is from the white point of view + // Evaluation score is from the white point of view contempt = (us == WHITE ? make_score(ct, ct / 2) : -make_score(ct, ct / 2)); @@ -832,8 +832,7 @@ namespace { } // Step 11. Internal iterative deepening (~2 Elo) - if ( depth >= 8 * ONE_PLY - && !ttMove) + if (depth >= 8 * ONE_PLY && !ttMove) { search(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode); @@ -847,6 +846,7 @@ 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 }; + Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, @@ -854,8 +854,8 @@ moves_loop: // When in check, search starts from here contHist, countermove, ss->killers); - value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc + value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); @@ -946,7 +946,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 / ONE_PLY); if ( !captureOrPromotion && !givesCheck diff --git a/src/thread.cpp b/src/thread.cpp index 64dd9e18..f216c321 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -31,7 +31,7 @@ ThreadPool Threads; // Global object /// Thread constructor launches the thread and waits until it goes to sleep -/// in idle_loop(). Note that 'searching' and 'exit' should be alredy set. +/// in idle_loop(). Note that 'searching' and 'exit' should be already set. Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) { From aa0166fba66d1bd3d2756f8f16b7f6161064d0a3 Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Thu, 4 Apr 2019 08:49:35 +0200 Subject: [PATCH 10/35] Add attacked by 2 pawns to attackedBy2 (#2074) Add squares attacked by 2 pawns to the attackedBy2 array STC : LLR: -2.95 (-2.94,2.94) [0.50,4.50] Total: 132722 W: 29583 L: 29090 D: 74049 http://tests.stockfishchess.org/tests/view/5ca231ba0ebc5925cf000794 LTC : LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 94589 W: 16161 L: 15718 D: 62710 http://tests.stockfishchess.org/tests/view/5ca25d180ebc5925cf000ba4 Bench: 3337864 --- src/evaluate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index deb8211a..51cba651 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -228,6 +228,8 @@ namespace { const Square ksq = pos.square(Us); + Bitboard dblAttackByPawn = pawn_double_attacks_bb(pos.pieces(Us, PAWN)); + // Find our pawns that are blocked or on the first two ranks Bitboard b = pos.pieces(Us, PAWN) & (shift(pos.pieces()) | LowRanks); @@ -239,7 +241,8 @@ namespace { attackedBy[Us][KING] = pos.attacks_from(ksq); attackedBy[Us][PAWN] = pe->pawn_attacks(Us); attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; - attackedBy2[Us] = attackedBy[Us][KING] & attackedBy[Us][PAWN]; + attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN]) + | dblAttackByPawn; // Init our king safety tables kingRing[Us] = attackedBy[Us][KING]; @@ -256,7 +259,7 @@ namespace { kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; // Remove from kingRing[] the squares defended by two pawns - kingRing[Us] &= ~pawn_double_attacks_bb(pos.pieces(Us, PAWN)); + kingRing[Us] &= ~dblAttackByPawn; } From 0f63b35120e79fe6cc76abdd293d58243ccdbacb Mon Sep 17 00:00:00 2001 From: Moez Jellouli <37274752+MJZ1977@users.noreply.github.com> Date: Fri, 29 Mar 2019 14:05:02 +0100 Subject: [PATCH 11/35] Remove pureStaticEval #2069 Remove pureStaticEval variable and keep only one static evaluation (ss->staticEval). STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 64617 W: 14348 L: 14312 D: 35957 Elo -0.24 http://tests.stockfishchess.org/tests/view/5c9e1ad70ebc5925cfffc106 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 82200 W: 13703 L: 13680 D: 54817 Elo -0.24 http://tests.stockfishchess.org/tests/view/5c9e4efd0ebc5925cfffc68b Bench : 3506898 --- src/search.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 21b669c4..972482eb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -533,7 +533,7 @@ namespace { Key posKey; Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; - Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; + Value bestValue, value, ttValue, eval, maxValue; bool ttHit, ttPv, inCheck, givesCheck, improving; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; @@ -697,16 +697,16 @@ namespace { // Step 6. Static evaluation of the position if (inCheck) { - ss->staticEval = eval = pureStaticEval = VALUE_NONE; + ss->staticEval = eval = VALUE_NONE; improving = false; goto moves_loop; // Skip early pruning when in check } else if (ttHit) { // Never assume anything on values stored in TT - ss->staticEval = eval = pureStaticEval = tte->eval(); + ss->staticEval = eval = tte->eval(); if (eval == VALUE_NONE) - ss->staticEval = eval = pureStaticEval = evaluate(pos); + ss->staticEval = eval = evaluate(pos); // Can ttValue be used as a better position evaluation? if ( ttValue != VALUE_NONE @@ -719,13 +719,12 @@ namespace { { int bonus = -(ss-1)->statScore / 512; - pureStaticEval = evaluate(pos); - ss->staticEval = eval = pureStaticEval + bonus; + ss->staticEval = eval = evaluate(pos) + bonus; } else - ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo; + ss->staticEval = eval = -(ss-1)->staticEval + 2 * Eval::Tempo; - tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); + tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } // Step 7. Razoring (~2 Elo) @@ -749,7 +748,7 @@ namespace { && (ss-1)->currentMove != MOVE_NULL && (ss-1)->statScore < 23200 && eval >= beta - && pureStaticEval >= beta - 36 * depth / ONE_PLY + 225 + && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -1189,7 +1188,7 @@ moves_loop: // When in check, search starts from here tte->save(posKey, value_to_tt(bestValue, ss->ply), ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, - depth, bestMove, pureStaticEval); + depth, bestMove, ss->staticEval); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); From 1982fe25f817c29aef9dd156869a53e520ce3629 Mon Sep 17 00:00:00 2001 From: xoto10 Date: Wed, 3 Apr 2019 08:35:55 +0100 Subject: [PATCH 12/35] Use average bestMoveChanges across all threads #2072 The current update only by main thread depends on the luck of whether main thread sees any/many changes to the best move or not. It then makes large, lumpy changes to the time to be used (1x, 2x, 3x, etc) depending on that sample of 1. Use the average across all threads to get a more reliable number with a smoother distribution. STC @ 5+0.05 th 4 : LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 51899 W: 11446 L: 11029 D: 29424 http://tests.stockfishchess.org/tests/view/5ca32ff20ebc5925cf0016fb STC @ 5+0.05 th 8 : LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 13851 W: 2843 L: 2620 D: 8388 http://tests.stockfishchess.org/tests/view/5ca35ae00ebc5925cf001adb LTC @ 20+0.2 th 8 : LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 48527 W: 7941 L: 7635 D: 32951 http://tests.stockfishchess.org/tests/view/5ca37cb70ebc5925cf001cec Further work: Similar changes might be possible for the fallingEval and timeReduction calculations (and elsewhere?), using either the min, average or max values across all threads. Bench 3506898 --- src/search.cpp | 21 ++++++++++++--------- src/thread.h | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 972482eb..30f28072 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -191,8 +191,11 @@ void MainThread::search() { else { for (Thread* th : Threads) + { + th->bestMoveChanges = 0; if (th != this) th->start_searching(); + } Thread::search(); // Let's start searching! } @@ -283,7 +286,7 @@ void Thread::search() { Move lastBestMove = MOVE_NONE; Depth lastBestMoveDepth = DEPTH_ZERO; MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); - double timeReduction = 1.0; + double timeReduction = 1, totBestMoveChanges = 0; Color us = rootPos.side_to_move(); std::memset(ss-7, 0, 10 * sizeof(Stack)); @@ -294,9 +297,6 @@ void Thread::search() { bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; - if (mainThread) - mainThread->bestMoveChanges = 0; - size_t multiPV = Options["MultiPV"]; Skill skill(Options["Skill Level"]); @@ -328,7 +328,7 @@ void Thread::search() { { // Age out PV variability metric if (mainThread) - mainThread->bestMoveChanges *= 0.517; + totBestMoveChanges /= 2; // Save the last iteration's scores before first PV line is searched and // all the move scores except the (new) PV are set to -VALUE_INFINITE. @@ -459,7 +459,7 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (306 + 9 * (mainThread->previousScore - bestValue)) / 581.0; + double fallingEval = (314 + 9 * (mainThread->previousScore - bestValue)) / 581.0; fallingEval = clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly @@ -467,7 +467,10 @@ void Thread::search() { double reduction = std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction; // Use part of the gained time from a previous stable move for the current move - double bestMoveInstability = 1.0 + mainThread->bestMoveChanges; + for (Thread* th : Threads) + totBestMoveChanges += th->bestMoveChanges; + + 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 @@ -1101,8 +1104,8 @@ moves_loop: // When in check, search starts from here // We record how often the best move has been changed in each // iteration. This information is used for time management: When // the best move changes frequently, we allocate some more time. - if (moveCount > 1 && thisThread == Threads.main()) - ++static_cast(thisThread)->bestMoveChanges; + if (moveCount > 1) + ++thisThread->bestMoveChanges; } else // All other moves but the PV are set to the lowest value: this diff --git a/src/thread.h b/src/thread.h index af506609..7a27aab1 100644 --- a/src/thread.h +++ b/src/thread.h @@ -63,7 +63,7 @@ public: size_t pvIdx, pvLast; int selDepth, nmpMinPly; Color nmpColor; - std::atomic nodes, tbHits; + std::atomic nodes, tbHits, bestMoveChanges; Position rootPos; Search::RootMoves rootMoves; @@ -85,7 +85,7 @@ struct MainThread : public Thread { void search() override; void check_time(); - double bestMoveChanges, previousTimeReduction; + double previousTimeReduction; Value previousScore; int callsCnt; bool stopOnPonderhit; From fdd799bc16bbb39216cf5e7ef12d302d1c201ef1 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 6 Apr 2019 02:03:15 +0200 Subject: [PATCH 13/35] Fix a missing assignment in previous commit While reformatting the patch, I got wrong a statement and converted it badly. --- src/search.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 30f28072..36c8a5eb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -468,8 +468,10 @@ void Thread::search() { // Use part of the gained time from a previous stable move for the current move for (Thread* th : Threads) + { totBestMoveChanges += th->bestMoveChanges; - + th->bestMoveChanges = 0; + } double bestMoveInstability = 1 + totBestMoveChanges / Threads.size(); // Stop the search if we have only one legal move, or if available time elapsed From 49a1fdd3fe894d170a2c2781238c0f0f907c08cc Mon Sep 17 00:00:00 2001 From: erbsenzaehler Date: Sun, 27 Jan 2019 09:20:38 +0100 Subject: [PATCH 14/35] Make ONE_PLY value independent again And a Trevis CI test to catch future issues. No functional change. --- .travis.yml | 3 +++ src/search.cpp | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4f68ae5..f27f9c95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,6 +55,9 @@ script: - 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 + + # Verify bench number is ONE_PLY independent by doubling its value + - sed -i '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 diff --git a/src/search.cpp b/src/search.cpp index 36c8a5eb..a9a62dbf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -86,8 +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 ? VALUE_DRAW - : VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); + return depth < 4 * ONE_PLY ? VALUE_DRAW + : VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); } // Skill structure is used to implement strength limit @@ -785,7 +785,7 @@ namespace { // 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; + thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / (4 * ONE_PLY); thisThread->nmpColor = us; Value v = search(pos, ss, beta-1, beta, depth-R, false); @@ -912,8 +912,9 @@ moves_loop: // When in check, search starts from here && pos.legal(move)) { Value singularBeta = ttValue - 2 * depth / ONE_PLY; + Depth halfDepth = depth / (2 * ONE_PLY) * ONE_PLY; // ONE_PLY invariant ss->excludedMove = move; - value = search(pos, ss, singularBeta - 1, singularBeta, depth / 2, cutNode); + value = search(pos, ss, singularBeta - 1, singularBeta, halfDepth, cutNode); ss->excludedMove = MOVE_NONE; if (value < singularBeta) @@ -961,7 +962,8 @@ 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) / ONE_PLY; + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO); + lmrDepth /= ONE_PLY; // Countermoves based pruning (~20 Elo) if ( lmrDepth < 3 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) From 8fa6273ff6d9aed4fb044cac0bfef9cc927eee65 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 6 Apr 2019 12:43:41 +0200 Subject: [PATCH 15/35] Fix sed for OS X (#2080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sed command is a bit different in Mac OS X (why not!). The ‘-i’ option required a parameter to tell what extension to add for the backup file. To fix it, just add extension for backup file, for example ‘.bak’ Fix broken Trevis CI test No functional change. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f27f9c95..1d56a23e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,7 +57,7 @@ script: - 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 's/.*\(ONE_PLY = [0-9]*\),.*/\1 * 2,/g' types.h + - 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 From f98c77413b68d506977bc078de7a47455968a926 Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 4 Apr 2019 21:45:52 -0600 Subject: [PATCH 16/35] Remove BetweenBB Array #2076 Non functional change. --- src/bitboard.cpp | 4 ---- src/bitboard.h | 10 ++++------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 2adf2779..94dfa70f 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -27,7 +27,6 @@ uint8_t PopCnt16[1 << 16]; uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; -Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; Bitboard DistanceRingBB[SQUARE_NB][8]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; @@ -121,10 +120,7 @@ void Bitboards::init() { for (PieceType pt : { BISHOP, ROOK }) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) if (PseudoAttacks[pt][s1] & s2) - { LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; - BetweenBB[s1][s2] = attacks_bb(pt, s1, square_bb(s2)) & attacks_bb(pt, s2, square_bb(s1)); - } } } diff --git a/src/bitboard.h b/src/bitboard.h index 77986638..b1d961f4 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -68,7 +68,6 @@ constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); extern uint8_t PopCnt16[1 << 16]; extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; -extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; extern Bitboard DistanceRingBB[SQUARE_NB][8]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; @@ -185,13 +184,12 @@ inline Bitboard adjacent_files_bb(File f) { } -/// between_bb() returns a bitboard representing all the squares between the two -/// given ones. For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with -/// the bits for square d5 and e6 set. If s1 and s2 are not on the same rank, -/// file or diagonal, 0 is returned. +/// between_bb() returns squares that are linearly between the given squares +/// If the given squares are not on a same file/rank/diagonal, return 0. inline Bitboard between_bb(Square s1, Square s2) { - return BetweenBB[s1][s2]; + return LineBB[s1][s2] & ( (AllSquares << (s1 + (s1 < s2))) + ^(AllSquares << (s2 + !(s1 < s2)))); } From ab4b94e1737fcdf9f5174a96e80bbdc985c95267 Mon Sep 17 00:00:00 2001 From: 31m059 <37052095+31m059@users.noreply.github.com> Date: Tue, 9 Apr 2019 13:35:17 -0400 Subject: [PATCH 17/35] Raise kingDanger threshold and adjust constant term #2087 The kingDanger term is intended to give a penalty which increases rapidly in the middlegame but less so in the endgame. To this end, the middlegame component is quadratic, and the endgame component is linear. However, this produces unintended consequences for relatively small values of kingDanger: the endgame penalty will exceed the middlegame penalty. This remains true up to kingDanger = 256 (a S(16, 16) penalty), so some of these inaccurate penalties are actually rather large. In this patch, we increase the threshold for applying the kingDanger penalty to eliminate some of this unintended behavior. This was very nearly, but not quite, sufficient to pass on its own. The patch was finally successful by integrating a second kingDanger tweak by @Vizvezdenec, increasing the kingDanger constant term slightly and improving both STC and LTC performance. Where do we go from here? I propose that in the future, any attempts to tune kingDanger coefficients should also consider tuning the kingDanger threshold. The evidence shows clearly that it should not be automatically taken to be zero. Special thanks to @Vizvezdenec for the kingDanger constant tweak. Thanks also to all the approvers and CPU donors who made this possible! STC: LLR: -2.96 (-2.94,2.94) [0.00,4.00] Total: 141225 W: 31239 L: 30846 D: 79140 http://tests.stockfishchess.org/tests/view/5cabbdb20ebc5925cf00b86c LTC: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 30708 W: 5296 L: 5043 D: 20369 http://tests.stockfishchess.org/tests/view/5cabff760ebc5925cf00c22d Bench: 3445945 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 51cba651..7408a77c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -472,10 +472,10 @@ namespace { - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) + 5 * kingFlankAttacks * kingFlankAttacks / 16 - - 25; + - 15; // Transform the kingDanger units into a Score, and subtract it from the evaluation - if (kingDanger > 0) + if (kingDanger > 100) score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); // Penalty when our king is on a pawnless flank From ec49e676a70435472cb70a9cf0c0376dfab31af4 Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 10 Apr 2019 11:33:57 -0600 Subject: [PATCH 18/35] Simplify castlingPath (#2088) Instead of looping through kfrom,kto, rfrom, rto, we can use BetweenBB. This is less lines of code and it is more clear what castlingPath actually is. Personal benchmarks are all over the place. However, this code is only executed when loading a position, so performance doesn't seem that relevant. No functional change. --- src/position.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 84892d09..ada03fbc 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -340,13 +340,8 @@ void Position::set_castling_right(Color c, Square 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); - for (Square s = std::min(rfrom, rto); s <= std::max(rfrom, rto); ++s) - if (s != kfrom && s != rfrom) - castlingPath[cr] |= s; - - for (Square s = std::min(kfrom, kto); s <= std::max(kfrom, kto); ++s) - if (s != kfrom && s != rfrom) - castlingPath[cr] |= s; + castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) + & ~(square_bb(kfrom) | rfrom); } From 5b5687d76e7dc10af9ebaa91f03190db9a9f8d27 Mon Sep 17 00:00:00 2001 From: miguel-l Date: Thu, 11 Apr 2019 01:35:47 +0800 Subject: [PATCH 19/35] Extend dangerous passed pawn moves (#2089) Introduce a new search extension when pushing an advanced passed pawn is also suggested by the first killer move. There have been previous tests which have similar ideas, mostly about pawn pushes, but it seems to be overkill to extend too many moves. My idea is to limit the extension to when a move happens to be noteworthy in some other way as well, such as in this case, when it is also a killer move. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 19027 W: 4326 L: 4067 D: 10634 http://tests.stockfishchess.org/tests/view/5cac2cde0ebc5925cf00c36d LTC: LLR: 2.94 (-2.94,2.94) [0.00,3.50] Total: 93390 W: 15995 L: 15555 D: 61840 http://tests.stockfishchess.org/tests/view/5cac42270ebc5925cf00c4b9 For future tests, it looks like this will interact heavily with passed pawn evaluation. It may be good to try more variants of some of the more promising evaluations tests/tweaks. Bench: 3666092 --- src/search.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index a9a62dbf..7fffae26 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -942,6 +942,12 @@ moves_loop: // When in check, search starts from here else if (type_of(move) == CASTLING) extension = ONE_PLY; + // Passed pawn extension + else if ( move == ss->killers[0] + && pos.advanced_pawn_push(move) + && pos.pawn_passed(us, to_sq(move))) + extension = ONE_PLY; + // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; From 5928cb2b300baafb040495ce41f9a5f42132d141 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Fri, 12 Apr 2019 13:35:32 +0200 Subject: [PATCH 20/35] Revert "Shuffle detection #2064" It causes a serious regression hanging a simple fixed depth search. Reproducible with: position fen q1B5/1P1q4/8/8/8/6R1/8/1K1k4 w - - 0 1 go depth 13 The reason is a search tree explosion due to: if (... && depth < 3 * ONE_PLY) extension = ONE_PLY; This is very dangerous code by itself because triggers **at the leafs** and in the above position keeps extending endlessly. In normal games time deadline makes the search to stop sooner or later, but in fixed seacrch we just hang possibly for a very long time. This is not acceptable because 'go depth 13' shall not be a surprise for any position. This patch reverts commit 76f1807baa90eb69f66001d25df2a28533f9406f. and fixes the issue https://github.com/official-stockfish/Stockfish/issues/2091 Bench: 3243738 --- src/search.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 7fffae26..645b1f9c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -607,15 +607,6 @@ namespace { : ttHit ? tte->move() : MOVE_NONE; ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY); - // if position has been searched at higher depths and we are shuffling, return value_draw - if (pos.rule50_count() > 36 - && ss->ply > 36 - && depth < 3 * ONE_PLY - && ttHit - && tte->depth() > depth - && pos.count() > 0) - return VALUE_DRAW; - // At non-PV nodes we check for an early TT cutoff if ( !PvNode && ttHit @@ -934,10 +925,6 @@ moves_loop: // When in check, search starts from here && (pos.blockers_for_king(~us) & from_sq(move) || pos.see_ge(move))) extension = ONE_PLY; - // Shuffle extension - else if(pos.rule50_count() > 14 && ss->ply > 14 && depth < 3 * ONE_PLY && PvNode) - extension = ONE_PLY; - // Castling extension else if (type_of(move) == CASTLING) extension = ONE_PLY; From a2cdb6e5d2b33deedfe09baa43708151c45c802a Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 11 Apr 2019 08:38:53 -0600 Subject: [PATCH 21/35] Simplify Connected Pawn Scoring #2090 This is a functional simplification that simplifies connected scoring of pawns. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 37472 W: 8318 L: 8228 D: 20926 http://tests.stockfishchess.org/tests/view/5cae74ef0ebc5925cf00f8a5 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 43035 W: 7366 L: 7281 D: 28388 http://tests.stockfishchess.org/tests/view/5caea3b50ebc5925cf00fe1e Bench: 3470173 --- src/pawns.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7edaa6e1..b034f478 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -36,7 +36,7 @@ namespace { constexpr Score Isolated = S( 5, 15); // Connected pawn bonus - constexpr int Connected[RANK_NB] = { 0, 13, 24, 18, 65, 100, 175, 330 }; + constexpr int Connected[RANK_NB] = { 0, 13, 17, 24, 59, 96, 171 }; // Strength of pawn shelter for our king by [distance from edge][rank]. // RANK_1 = 0 is used for files where we have no pawn, or pawn is behind our king. @@ -89,6 +89,7 @@ namespace { assert(pos.piece_on(s) == make_piece(Us, PAWN)); File f = file_of(s); + Rank r = relative_rank(Us, s); e->semiopenFiles[Us] &= ~(1 << f); e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); @@ -117,8 +118,7 @@ namespace { && popcount(phalanx) >= popcount(leverPush)) e->passedPawns[Us] |= s; - else if ( stoppers == square_bb(s + Up) - && relative_rank(Us, s) >= RANK_5) + else if (stoppers == square_bb(s + Up) && r >= RANK_5) { b = shift(support) & ~theirPawns; while (b) @@ -129,8 +129,7 @@ namespace { // Score this pawn if (support | phalanx) { - int r = relative_rank(Us, s); - int v = phalanx ? Connected[r] + Connected[r + 1] : 2 * Connected[r]; + int v = (phalanx ? 3 : 2) * Connected[r]; v = 17 * popcount(support) + (v >> (opposed + 1)); score += make_score(v, v * (r - 2) / 4); } From 42d271f23c255a87133d33392e3b2c66991e3960 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 9 Apr 2019 16:51:39 +0200 Subject: [PATCH 22/35] Give penalty for all early quiets of prev. ply passed STC: LLR: 2.94 (-2.94,2.94) [-3.00,1.00] Total: 32884 W: 7283 L: 7184 D: 18417 http://tests.stockfishchess.org/tests/view/5cacb1b20ebc5925cf00ce97 passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 22869 W: 3920 L: 3803 D: 15146 http://tests.stockfishchess.org/tests/view/5cacbd760ebc5925cf00cfce Bench: 3723099 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 645b1f9c..cb6c5d44 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -623,9 +623,8 @@ namespace { if (!pos.capture_or_promotion(ttMove)) update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); - // 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()) + // 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)); } // Penalty for a quiet ttMove that fails low From 1594d15922e39bfbec749815349c812ca16d8a53 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 13 Apr 2019 17:17:47 +0200 Subject: [PATCH 23/35] Remove two useless assignments (#2093) These variables are initialized before their use in the movepicker loop. passed STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 138732 W: 30727 L: 30838 D: 77167 http://tests.stockfishchess.org/tests/view/5cb07af40ebc5925cf012c32 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 cb6c5d44..15e88ca4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1226,8 +1226,7 @@ moves_loop: // When in check, search starts from here Thread* thisThread = pos.this_thread(); (ss+1)->ply = ss->ply + 1; - ss->currentMove = bestMove = MOVE_NONE; - ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; + bestMove = MOVE_NONE; inCheck = pos.checkers(); moveCount = 0; From eb07775583c39893bc6eb65a40b5f62a7799deee Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 16 Apr 2019 08:09:36 -0600 Subject: [PATCH 24/35] Remove semiopenFiles in pawns and simplify space #2102 This is a functional simplification. 1. semiopenFiles is removed in pawns and uses the piece arrays in position instead. 2. popcount is removed in space calculations and uses pawn piece count instead. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 33327 W: 7423 L: 7324 D: 18580 http://tests.stockfishchess.org/tests/view/5cb4be090ebc5925cf018511 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 10173 W: 1774 L: 1636 D: 6763 http://tests.stockfishchess.org/tests/view/5cb4c5920ebc5925cf018696 bench 3402947 --- src/evaluate.cpp | 6 +++--- src/pawns.cpp | 2 -- src/pawns.h | 5 ----- src/position.h | 5 +++++ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 7408a77c..fbe768bb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -358,8 +358,8 @@ namespace { score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); // Bonus for rook on an open or semi-open file - if (pe->semiopen_file(Us, file_of(s))) - score += RookOnFile[bool(pe->semiopen_file(Them, file_of(s)))]; + if (pos.semiopen_file(Us, file_of(s))) + score += RookOnFile[bool(pos.semiopen_file(Them, file_of(s)))]; // Penalty when trapped by the king, even more if the king cannot castle else if (mob <= 3) @@ -720,7 +720,7 @@ namespace { int bonus = popcount(safe) + popcount(behind & safe); int weight = pos.count(Us) - - 2 * popcount(pe->semiopenFiles[WHITE] & pe->semiopenFiles[BLACK]); + - (16 - pos.count()) / 4; Score score = make_score(bonus * weight * weight / 16, 0); diff --git a/src/pawns.cpp b/src/pawns.cpp index b034f478..7e29f506 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -77,7 +77,6 @@ namespace { Bitboard theirPawns = pos.pieces(Them, PAWN); e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0; - e->semiopenFiles[Us] = 0xFF; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); @@ -91,7 +90,6 @@ namespace { File f = file_of(s); Rank r = relative_rank(Us, s); - e->semiopenFiles[Us] &= ~(1 << f); e->pawnAttacksSpan[Us] |= pawn_attack_span(Us, s); // Flag the pawn diff --git a/src/pawns.h b/src/pawns.h index 71d18ee8..5f5411f6 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -40,10 +40,6 @@ struct Entry { int weak_unopposed(Color c) const { return weakUnopposed[c]; } int passed_count() const { return passedCount; } - int semiopen_file(Color c, File f) const { - return semiopenFiles[c] & (1 << f); - } - int pawns_on_same_color_squares(Color c, Square s) const { return pawnsOnSquares[c][bool(DarkSquares & s)]; } @@ -69,7 +65,6 @@ struct Entry { Score kingSafety[COLOR_NB]; int weakUnopposed[COLOR_NB]; int castlingRights[COLOR_NB]; - int semiopenFiles[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] int passedCount; }; diff --git a/src/position.h b/src/position.h index 03c00148..1351d0d1 100644 --- a/src/position.h +++ b/src/position.h @@ -95,6 +95,7 @@ public: template int count() const; template const Square* squares(Color c) const; template Square square(Color c) const; + int semiopen_file(Color c, File f) const; // Castling int castling_rights(Color c) const; @@ -260,6 +261,10 @@ inline Square Position::ep_square() const { return st->epSquare; } +inline int Position::semiopen_file(Color c, File f) const { + return !(pieces(c, PAWN) & file_bb(f)); +} + inline bool Position::can_castle(CastlingRight cr) const { return st->castlingRights & cr; } From 76777b663a5f5a2dcfaafa19c15d02d11c401bdf Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 16 Apr 2019 08:12:47 -0600 Subject: [PATCH 25/35] Calculate passedCount real-time #2099 This is a non-functional simplification which removes the passedCount variable in pawns. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 27982 W: 6227 L: 6118 D: 15637 http://tests.stockfishchess.org/tests/view/5cb3cdd30ebc5925cf017025 Combo STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 17368 W: 3925 L: 3795 D: 9648 http://tests.stockfishchess.org/tests/view/5cb3d3510ebc5925cf01709a Non functional test. --- src/pawns.cpp | 1 - src/pawns.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pawns.cpp b/src/pawns.cpp index 7e29f506..4c2ff391 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -164,7 +164,6 @@ Entry* probe(const Position& pos) { e->key = key; e->scores[WHITE] = evaluate(pos, e); e->scores[BLACK] = evaluate(pos, e); - e->passedCount= popcount(e->passedPawns[WHITE] | e->passedPawns[BLACK]); return e; } diff --git a/src/pawns.h b/src/pawns.h index 5f5411f6..96ed4149 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 weak_unopposed(Color c) const { return weakUnopposed[c]; } - int passed_count() const { return passedCount; } + int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); }; int pawns_on_same_color_squares(Color c, Square s) const { return pawnsOnSquares[c][bool(DarkSquares & s)]; @@ -66,7 +66,6 @@ struct Entry { int weakUnopposed[COLOR_NB]; int castlingRights[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] - int passedCount; }; typedef HashTable Table; From 3b46df546dd8b17963abae887acff6e91e2b945e Mon Sep 17 00:00:00 2001 From: protonspring Date: Tue, 16 Apr 2019 15:10:53 -0600 Subject: [PATCH 26/35] Move pawnsOnSquares to Position (#2100) We can remove the values in Pawns if we just use the piece arrays in Position. This reduces the size of a pawn entry. This simplification passed individually, and in concert with ps_passedcount100 (removes passedCount storage in pawns.). STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 19957 W: 4529 L: 4404 D: 11024 http://tests.stockfishchess.org/tests/view/5cb3c2d00ebc5925cf016f0d Combo STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 17368 W: 3925 L: 3795 D: 9648 http://tests.stockfishchess.org/tests/view/5cb3d3510ebc5925cf01709a This is a non-functional simplification. --- src/evaluate.cpp | 2 +- src/pawns.cpp | 2 -- src/pawns.h | 4 ---- src/position.h | 5 +++++ 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fbe768bb..566eba6d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -328,7 +328,7 @@ namespace { // bishop, bigger when the center files are blocked with pawns. Bitboard blocked = pos.pieces(Us, PAWN) & shift(pos.pieces()); - score -= BishopPawns * pe->pawns_on_same_color_squares(Us, s) + score -= BishopPawns * pos.pawns_on_same_color_squares(Us, s) * (1 + popcount(blocked & CenterFiles)); // Bonus for bishop on a long diagonal which can "see" both center squares diff --git a/src/pawns.cpp b/src/pawns.cpp index 4c2ff391..e2b26344 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -79,8 +79,6 @@ namespace { e->passedPawns[Us] = e->pawnAttacksSpan[Us] = e->weakUnopposed[Us] = 0; e->kingSquares[Us] = SQ_NONE; e->pawnAttacks[Us] = pawn_attacks_bb(ourPawns); - e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares); - e->pawnsOnSquares[Us][WHITE] = pos.count(Us) - e->pawnsOnSquares[Us][BLACK]; // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) diff --git a/src/pawns.h b/src/pawns.h index 96ed4149..88b55545 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -40,10 +40,6 @@ struct Entry { int weak_unopposed(Color c) const { return weakUnopposed[c]; } int passed_count() const { return popcount(passedPawns[WHITE] | passedPawns[BLACK]); }; - int pawns_on_same_color_squares(Color c, Square s) const { - return pawnsOnSquares[c][bool(DarkSquares & s)]; - } - template Score king_safety(const Position& pos) { return kingSquares[Us] == pos.square(Us) && castlingRights[Us] == pos.castling_rights(Us) diff --git a/src/position.h b/src/position.h index 1351d0d1..1078e03e 100644 --- a/src/position.h +++ b/src/position.h @@ -129,6 +129,7 @@ public: // Piece specific bool pawn_passed(Color c, Square s) const; bool opposite_bishops() const; + int pawns_on_same_color_squares(Color c, Square s) const; // Doing and undoing moves void do_move(Move m, StateInfo& newSt); @@ -323,6 +324,10 @@ inline bool Position::advanced_pawn_push(Move m) const { && relative_rank(sideToMove, from_sq(m)) > RANK_4; } +inline int Position::pawns_on_same_color_squares(Color c, Square s) const { + return popcount(pieces(c, PAWN) & ((DarkSquares & s) ? DarkSquares : ~DarkSquares)); +} + inline Key Position::key() const { return st->key; } From c4fc00ec49d748f1ec1cd2fa2affa73bfdc86f8f Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 17 Apr 2019 13:13:39 -0600 Subject: [PATCH 27/35] Remove Movepick::move (#2085) The "move" class variable is Movepick is removed (removes some abstraction) which saves a few assignment operations, and the effects of "filter" is limited to the current move (movePtr). The resulting code is a bit more verbose, but it is also more clear what is going on. This version is NOT tested, but is substantially similar to: STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 29191 W: 6474 L: 6367 D: 16350 http://tests.stockfishchess.org/tests/view/5ca7aab50ebc5925cf006e50 This is a non-functional simplification. --- src/movepick.cpp | 36 ++++++++++++++++++------------------ src/movepick.h | 1 - 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 86eb98aa..a70785e7 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -139,12 +139,12 @@ Move MovePicker::select(Pred filter) { if (T == Best) std::swap(*cur, *std::max_element(cur, endMoves)); - move = *cur++; + if (*cur != ttMove && filter()) + return *cur++; - if (move != ttMove && filter()) - return move; + cur++; } - return move = MOVE_NONE; + return MOVE_NONE; } /// MovePicker::next_move() is the most important method of the MovePicker class. It @@ -174,10 +174,10 @@ top: case GOOD_CAPTURE: if (select([&](){ - return pos.see_ge(move, Value(-55 * (cur-1)->value / 1024)) ? + return pos.see_ge(*cur, Value(-55 * cur->value / 1024)) ? // Move losing capture to endBadCaptures to be tried later - true : (*endBadCaptures++ = move, false); })) - return move; + true : (*endBadCaptures++ = *cur, false); })) + return *(cur - 1); // Prepare the pointers to loop over the refutations array cur = std::begin(refutations); @@ -192,10 +192,10 @@ top: /* fallthrough */ case REFUTATION: - if (select([&](){ return move != MOVE_NONE - && !pos.capture(move) - && pos.pseudo_legal(move); })) - return move; + if (select([&](){ return *cur != MOVE_NONE + && !pos.capture(*cur) + && pos.pseudo_legal(*cur); })) + return *(cur - 1); ++stage; /* fallthrough */ @@ -210,10 +210,10 @@ top: case QUIET: if ( !skipQuiets - && select([&](){return move != refutations[0] - && move != refutations[1] - && move != refutations[2];})) - return move; + && select([&](){return *cur != refutations[0].move + && *cur != refutations[1].move + && *cur != refutations[2].move;})) + return *(cur - 1); // Prepare the pointers to loop over the bad captures cur = moves; @@ -237,12 +237,12 @@ top: return select([](){ return true; }); case PROBCUT: - return select([&](){ return pos.see_ge(move, threshold); }); + return select([&](){ return pos.see_ge(*cur, threshold); }); case QCAPTURE: if (select([&](){ return depth > DEPTH_QS_RECAPTURES - || to_sq(move) == recaptureSquare; })) - return move; + || to_sq(*cur) == recaptureSquare; })) + return *(cur - 1); // If we did not find any move and we do not try checks, we have finished if (depth != DEPTH_QS_CHECKS) diff --git a/src/movepick.h b/src/movepick.h index d9ecba99..e916514d 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -142,7 +142,6 @@ private: Move ttMove; ExtMove refutations[3], *cur, *endMoves, *endBadCaptures; int stage; - Move move; Square recaptureSquare; Value threshold; Depth depth; From f21b50398231b4846c364e23bfeeab314c7731ea Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 18 Apr 2019 16:53:52 +0200 Subject: [PATCH 28/35] Simplify distance (#2109) Only called with Squares as argument, so remove unused variants. As this is just syntax changes, only verified bench at high depth. No functional change. --- src/bitboard.h | 10 ++++------ src/endgame.cpp | 4 +--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index b1d961f4..6f99ef19 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -237,15 +237,13 @@ inline bool aligned(Square s1, Square s2, Square s3) { /// distance() functions return the distance between x and y, defined as the -/// number of steps for a king in x to reach y. Works with squares, ranks, files. +/// number of steps for a king in x to reach y. -template inline int distance(T x, T y) { return std::abs(x - y); } +template inline int distance(Square x, Square y); +template<> inline int distance(Square x, Square y) { return std::abs(file_of(x) - file_of(y)); } +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 inline int distance(T2 x, T2 y); -template<> inline int distance(Square x, Square y) { return distance(file_of(x), file_of(y)); } -template<> inline int distance(Square x, Square y) { return distance(rank_of(x), rank_of(y)); } - template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { return v < lo ? lo : v > hi ? hi : v; } diff --git a/src/endgame.cpp b/src/endgame.cpp index efc41a98..5958e633 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -635,8 +635,6 @@ ScaleFactor Endgame::operator()(const Position& pos) const { Square ksq = pos.square(weakSide); Square psq1 = pos.squares(strongSide)[0]; Square psq2 = pos.squares(strongSide)[1]; - Rank r1 = rank_of(psq1); - Rank r2 = rank_of(psq2); Square blockSq1, blockSq2; if (relative_rank(strongSide, psq1) > relative_rank(strongSide, psq2)) @@ -670,7 +668,7 @@ ScaleFactor Endgame::operator()(const Position& pos) const { && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 || (pos.attacks_from(blockSq2) & pos.pieces(weakSide, BISHOP)) - || distance(r1, r2) >= 2)) + || distance(psq1, psq2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 From bdeb01dec09fd6e5ea77a1cb6f6f7fe51a81b7dd Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 19 Apr 2019 17:33:26 +0200 Subject: [PATCH 29/35] Remove capping in reduction (#2110) Saves two std::min. Bench is unchanged to high depth, but in principle this is a functional change so tested both STC and LTC. passed STC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 78193 W: 17220 L: 17210 D: 43763 http://tests.stockfishchess.org/tests/view/5cb789540ebc5925cf01b90b passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 93846 W: 15964 L: 15962 D: 61920 http://tests.stockfishchess.org/tests/view/5cb8066d0ebc5925cf01c72b Bench: 3402947 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 15e88ca4..5911e983 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -67,10 +67,10 @@ namespace { } // Reductions lookup table, initialized at startup - int Reductions[64]; // [depth or moveNumber] + int Reductions[MAX_MOVES]; // [depth or moveNumber] template Depth reduction(bool i, Depth d, int mn) { - int r = Reductions[std::min(d / ONE_PLY, 63)] * Reductions[std::min(mn, 63)] / 1024; + int r = Reductions[d / ONE_PLY] * Reductions[mn] / 1024; return ((r + 512) / 1024 + (!i && r > 1024) - PvNode) * ONE_PLY; } @@ -147,7 +147,7 @@ namespace { void Search::init() { - for (int i = 1; i < 64; ++i) + for (int i = 1; i < MAX_MOVES; ++i) Reductions[i] = int(1024 * std::log(i) / std::sqrt(1.95)); } From a858b5a84e8702390adee4388034c57570e65fee Mon Sep 17 00:00:00 2001 From: protonspring Date: Wed, 17 Apr 2019 12:38:38 -0600 Subject: [PATCH 30/35] Remove DistanceRing #2107 Remove the DistanceRing array. This reduces the memory footprint by about 4kb. http://tests.stockfishchess.org/tests/view/5cba35350ebc5925cf020d7f LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 101421 W: 22491 L: 22528 D: 56402 No functional change. --- src/bitboard.cpp | 4 ---- src/bitboard.h | 1 - src/pawns.cpp | 12 ++++++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 94dfa70f..0ab244c7 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -28,7 +28,6 @@ uint8_t PopCnt16[1 << 16]; uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -Bitboard DistanceRingBB[SQUARE_NB][8]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; @@ -83,10 +82,7 @@ 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)); - DistanceRingBB[s1][SquareDistance[s1][s2]] |= s2; - } int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } }; diff --git a/src/bitboard.h b/src/bitboard.h index 6f99ef19..53e96f44 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -69,7 +69,6 @@ extern uint8_t PopCnt16[1 << 16]; extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -extern Bitboard DistanceRingBB[SQUARE_NB][8]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; extern Bitboard KingFlank[FILE_NB]; diff --git a/src/pawns.cpp b/src/pawns.cpp index e2b26344..095126d4 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -212,11 +212,15 @@ Score Entry::do_king_safety(const Position& pos) { Square ksq = pos.square(Us); kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); - int minKingPawnDistance = 0; Bitboard pawns = pos.pieces(Us, PAWN); - if (pawns) - while (!(DistanceRingBB[ksq][++minKingPawnDistance] & pawns)) {} + int minPawnDist = pawns ? 8 : 0; + + if (pawns & PseudoAttacks[KING][ksq]) + minPawnDist = 1; + + else while (pawns) + minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); Value bonus = evaluate_shelter(pos, ksq); @@ -227,7 +231,7 @@ Score Entry::do_king_safety(const Position& pos) { if (pos.can_castle(Us | QUEEN_SIDE)) bonus = std::max(bonus, evaluate_shelter(pos, relative_square(Us, SQ_C1))); - return make_score(bonus, -16 * minKingPawnDistance); + return make_score(bonus, -16 * minPawnDist); } // Explicit template instantiation From 6373fd56e90bc6114230a70cacad804248d955e2 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 24 Apr 2019 19:51:57 +0200 Subject: [PATCH 31/35] Remove useless initializations (#2115) Removes two unneeded inits, they are always set before their use later on. 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 5911e983..f9fdc261 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -584,8 +584,7 @@ namespace { assert(0 <= ss->ply && ss->ply < MAX_PLY); (ss+1)->ply = ss->ply + 1; - ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; - ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; + (ss+1)->excludedMove = bestMove = MOVE_NONE; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; Square prevSq = to_sq((ss-1)->currentMove); From e89bc30fdc93f739869d0d4b285a2cfc3e7a74ee Mon Sep 17 00:00:00 2001 From: MJZ1977 <37274752+MJZ1977@users.noreply.github.com> Date: Wed, 10 Apr 2019 12:56:05 +0200 Subject: [PATCH 32/35] Shuffle detection #2108 Bench: 3402947 --- src/search.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index f9fdc261..517499b5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -606,6 +606,15 @@ namespace { : ttHit ? tte->move() : MOVE_NONE; ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY); + // If position has been searched at higher depths and we are shuffling, + // return value_draw. + if ( pos.rule50_count() > 36 - 6 * (pos.count() > 14) + && ss->ply > 36 - 6 * (pos.count() > 14) + && ttHit + && tte->depth() > depth + && pos.count() > 0) + return VALUE_DRAW; + // At non-PV nodes we check for an early TT cutoff if ( !PvNode && ttHit @@ -927,6 +936,14 @@ moves_loop: // When in check, search starts from here else if (type_of(move) == CASTLING) extension = ONE_PLY; + // Shuffle extension + else if ( PvNode + && pos.rule50_count() > 18 + && ss->ply > 18 + && depth < 3 * ONE_PLY + && ss->ply < 3 * thisThread->rootDepth / ONE_PLY) // To avoid infinite loops + extension = ONE_PLY; + // Passed pawn extension else if ( move == ss->killers[0] && pos.advanced_pawn_push(move) From 9a11a291942a8a7b1ebb36282c666ca8d1be1892 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 27 Apr 2019 12:31:55 +0300 Subject: [PATCH 33/35] Include bishop protection in king Danger evaluation. #2118 Same idea as fisherman's knight protection. passed STC LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 17133 W: 3952 L: 3701 D: 9480 http://tests.stockfishchess.org/tests/view/5cc3550b0ebc5925cf02dada passed LTC LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 37316 W: 6470 L: 6188 D: 24658 http://tests.stockfishchess.org/tests/view/5cc3721d0ebc5925cf02dc90 Looking at this 2 ideas being recent clean elo gainers I have a feeling that we can add also rook and queen protection bonuses or overall move this stuff in pieces loop in the same way as we do pieces attacking bonuses on their kingring... :) Thx fisherman for original idea. Bench 3429173 --- src/evaluate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 566eba6d..7e6260c8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -467,12 +467,13 @@ namespace { + 69 * kingAttacksCount[Them] + 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) - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) + 5 * kingFlankAttacks * kingFlankAttacks / 16 - - 15; + - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 100) From 7ede1ed0716744270544dcb1ee71ca907c6d9c23 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 27 Apr 2019 20:47:06 +0200 Subject: [PATCH 35/35] Allow for address sanitizer. (#2119) Properly allow for sanitize=address (-fsanitize=address) as an argument to the Makefile. No functional change --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 8b9b16e4..2d6042e2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -481,7 +481,7 @@ config-sanity: @echo "Testing config sanity. If this fails, try 'make help' ..." @echo "" @test "$(debug)" = "yes" || test "$(debug)" = "no" - @test "$(sanitize)" = "undefined" || test "$(sanitize)" = "thread" || test "$(sanitize)" = "no" + @test "$(sanitize)" = "undefined" || test "$(sanitize)" = "thread" || test "$(sanitize)" = "address" || test "$(sanitize)" = "no" @test "$(optimize)" = "yes" || test "$(optimize)" = "no" @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7"