From d07e782e22ca2ed0ec748ac38c33673baec28cc5 Mon Sep 17 00:00:00 2001 From: mstembera Date: Wed, 9 Jan 2019 07:27:47 -0800 Subject: [PATCH 01/22] Minor cleanup to recent 'Flag critical search tree in hash table' patch No functional change --- src/search.cpp | 6 +++--- src/tt.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b7e04fad..519782f8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -643,7 +643,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; - pvHit = ttHit ? tte->pv_hit() : false; + pvHit = ttHit && tte->pv_hit(); // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -881,7 +881,7 @@ namespace { tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; - pvHit = ttHit ? tte->pv_hit() : false; + pvHit = ttHit && tte->pv_hit(); } moves_loop: // When in check, search starts from here @@ -1292,7 +1292,7 @@ moves_loop: // When in check, search starts from here tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; - pvHit = ttHit ? tte->pv_hit() : false; + pvHit = ttHit && tte->pv_hit(); if ( !PvNode && ttHit diff --git a/src/tt.cpp b/src/tt.cpp index d05de916..aa57efb6 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -122,7 +122,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { for (int i = 0; i < ClusterSize; ++i) if (!tte[i].key16 || tte[i].key16 == key16) { - tte[i].genBound8 = uint8_t(generation8 | tte[i].pv_hit() << 2 | tte[i].bound()); // Refresh + tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & 0x7)); // Refresh return found = (bool)tte[i].key16, &tte[i]; } @@ -131,8 +131,8 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { TTEntry* replace = tte; for (int i = 1; i < ClusterSize; ++i) // Due to our packed storage format for generation and its cyclic - // nature we add 263 (263 is the modulus plus 7 to keep the lowest - // two bound bits from affecting the result) to calculate the entry + // nature we add 263 (256 is the modulus plus 7 to keep the unrelated + // lowest three bits from affecting the result) to calculate the entry // age correctly even after generation8 overflows into the next cycle. if ( replace->depth8 - ((263 + generation8 - replace->genBound8) & 0xF8) > tte[i].depth8 - ((263 + generation8 - tte[i].genBound8) & 0xF8)) @@ -150,7 +150,7 @@ int TranspositionTable::hashfull() const { int cnt = 0; for (int i = 0; i < 1000 / ClusterSize; ++i) for (int j = 0; j < ClusterSize; ++j) - cnt += (table[i].entry[j].genBound8 & 0xFC) == generation8; + cnt += (table[i].entry[j].genBound8 & 0xF8) == generation8; return cnt * 1000 / (ClusterSize * (1000 / ClusterSize)); } From 5446e6f408f2ed7fa281dbe0097c46674d193260 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 10 Jan 2019 07:43:17 +0100 Subject: [PATCH 02/22] Remove pvExact The variable pvExact now overlaps with the pvHit concept. So you simplify the logic with small code tweaks to have pvHit trigger where pvExact previously triggered. passed STC: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 20558 W: 4497 L: 4373 D: 11688 http://tests.stockfishchess.org/tests/view/5c36e9fd0ebc596a450c7885 passed LTC: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23482 W: 3888 L: 3772 D: 15822 http://tests.stockfishchess.org/tests/view/5c37072d0ebc596a450c7a52 Bench: 3739723 --- src/search.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 519782f8..ea565360 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -578,7 +578,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; bool ttHit, pvHit, inCheck, givesCheck, improving; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -677,7 +677,7 @@ namespace { return ttValue; } - if ( depth > 6 * ONE_PLY + if ( depth > 4 * ONE_PLY && !excludedMove && PvNode) pvHit = true; @@ -898,7 +898,6 @@ moves_loop: // When in check, search starts from here skipQuiets = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT; // Step 12. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. @@ -1043,7 +1042,7 @@ moves_loop: // When in check, search starts from here Depth r = reduction(improving, depth, moveCount); // Decrease reduction if position is or has been on the PV - if (pvHit && !PvNode) + if (pvHit) r -= ONE_PLY; // Decrease reduction if opponent's move count is high (~10 Elo) @@ -1052,10 +1051,6 @@ moves_loop: // When in check, search starts from here if (!captureOrPromotion) { - // Decrease reduction for exact PV nodes (~0 Elo) - if (pvExact) - r -= ONE_PLY; - // Increase reduction if ttMove is a capture (~0 Elo) if (ttCapture) r += ONE_PLY; From 230fb6e9ad5b153aa84032ef0c7e60ff0db08416 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 2 Jan 2019 11:09:50 +0100 Subject: [PATCH 03/22] Simplify time management a bit The new form is likely to trigger a bit more at LTC. Given that LTC appears to be an improvement, I think that is fine. The change is not very invasive: it does the same as before, use potentially less time for moves that are very stable. Most of the time, the full bonus was given if the bonus was given, so the gradual part {3, 4, 5} didn't matter much. Whereas previously 'stable' was expressed as the last 80% of iterations are the same, now I use a fixed depth (10 iterations). For TCEC style TC, it will presumably imply some more moves that are played quicker (and thus more time on the clock when it potentially matters). Note that 10 iterations of stability means we've been proposing that move for 99.9% of search time. passed STC http://tests.stockfishchess.org/tests/view/5c30d2290ebc596a450c055b LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 70921 W: 15403 L: 15378 D: 40140 passed LTC http://tests.stockfishchess.org/tests/view/5c31ae240ebc596a450c1881 LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 17422 W: 2968 L: 2842 D: 11612 No functional change. --- src/search.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ea565360..933cab87 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -503,10 +503,7 @@ void Thread::search() { fallingEval = std::max(0.5, std::min(1.5, fallingEval)); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = 1.0; - for (int i : {3, 4, 5}) - if (lastBestMoveDepth * i < completedDepth) - timeReduction *= 1.25; + timeReduction = lastBestMoveDepth + 10 * ONE_PLY < completedDepth ? 1.95 : 1.0; // Use part of the gained time from a previous stable move for the current move double bestMoveInstability = 1.0 + mainThread->bestMoveChanges; From 3732c55c18fd74981370dc55b7b46ec8a05ad5bf Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 14 Jan 2019 07:03:31 -0700 Subject: [PATCH 04/22] Simplify pawn moves (#1900) If we define dcCandidates with & pawnsNotOn7, we don't have to & it both times. This seems more clear to me as well. Tested for no regression. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 44042 W: 9663 L: 9585 D: 24794 http://tests.stockfishchess.org/tests/view/5c21d9120ebc5902ba12e84d No functional change. --- src/movegen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 5ed24893..2f7c55c8 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -93,10 +93,10 @@ namespace { // if the pawn is not on the same file as the enemy king, because we // don't generate captures. Note that a possible discovery check // promotion has been already generated amongst the captures. - Bitboard dcCandidates = pos.blockers_for_king(Them); - if (pawnsNotOn7 & dcCandidates) + Bitboard dcCandidateQuiets = pos.blockers_for_king(Them) & pawnsNotOn7; + if (dcCandidateQuiets) { - Bitboard dc1 = shift(pawnsNotOn7 & dcCandidates) & emptySquares & ~file_bb(ksq); + Bitboard dc1 = shift(dcCandidateQuiets) & emptySquares & ~file_bb(ksq); Bitboard dc2 = shift(dc1 & TRank3BB) & emptySquares; b1 |= dc1; From 3300517ecb75df265489d2a9841e4fce2414fd09 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 14 Jan 2019 22:53:43 -0700 Subject: [PATCH 05/22] Remove AdjacentFiles This is a non-functional simplification that removes the AdjacentFiles array. This array is simple enough to calculate that the pre-calculated array provides no benefit. Reduces the memory footprint. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 74839 W: 16390 L: 16373 D: 42076 http://tests.stockfishchess.org/tests/view/5c3d75920ebc596a450cfb67 No functionnal change --- src/bitboard.cpp | 6 +----- src/bitboard.h | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 8079b783..77f49ef6 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -29,7 +29,6 @@ int SquareDistance[SQUARE_NB][SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; Bitboard FileBB[FILE_NB]; Bitboard RankBB[RANK_NB]; -Bitboard AdjacentFilesBB[FILE_NB]; Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; @@ -97,9 +96,6 @@ void Bitboards::init() { for (Rank r = RANK_1; r <= RANK_8; ++r) RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB; - for (File f = FILE_A; f <= FILE_H; ++f) - AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0); - for (Rank r = RANK_1; r < RANK_8; ++r) ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | RankBB[r]); @@ -107,7 +103,7 @@ void Bitboards::init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) { ForwardFileBB [c][s] = ForwardRanksBB[c][rank_of(s)] & FileBB[file_of(s)]; - PawnAttackSpan[c][s] = ForwardRanksBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; + PawnAttackSpan[c][s] = ForwardRanksBB[c][rank_of(s)] & adjacent_files_bb(file_of(s)); PassedPawnMask[c][s] = ForwardFileBB [c][s] | PawnAttackSpan[c][s]; } diff --git a/src/bitboard.h b/src/bitboard.h index f8440a23..e1c31dd7 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -65,7 +65,6 @@ extern int SquareDistance[SQUARE_NB][SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB]; extern Bitboard FileBB[FILE_NB]; extern Bitboard RankBB[RANK_NB]; -extern Bitboard AdjacentFilesBB[FILE_NB]; extern Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; @@ -195,7 +194,7 @@ constexpr Bitboard double_pawn_attacks_bb(Bitboard b) { /// adjacent files of the given one. inline Bitboard adjacent_files_bb(File f) { - return AdjacentFilesBB[f]; + return shift(FileBB[f]) | shift(FileBB[f]); } From 3acacf8471efd018e33e4743cbbb2aed8d59e855 Mon Sep 17 00:00:00 2001 From: Jonathan D <38142170+SFisGOD@users.noreply.github.com> Date: Sun, 20 Jan 2019 19:20:21 +0800 Subject: [PATCH 06/22] Tweak initiative and Pawn PSQT (#1957) Small changes in initiative(). For Pawn PSQT, endgame values for d6-e6 and d7-e7 are now symmetric. The MG value of d2 is now smaller than e2 (d2=13, e2=21 now compared to d2=19, e2=16 before). The MG values of h5-h6-h7 also increased so this might encourage stockfish for more h-pawn pushes. STC LLR: -2.96 (-2.94,2.94) [0.00,4.00] Total: 81141 W: 17933 L: 17777 D: 45431 http://tests.stockfishchess.org/tests/view/5c4017350ebc5902bb5cf237 LTC LLR: 2.96 (-2.94,2.94) [0.00,4.00] Total: 83078 W: 13883 L: 13466 D: 55729 http://tests.stockfishchess.org/tests/view/5c40763f0ebc5902bb5cff09 Bench: 3266398 --- src/evaluate.cpp | 12 ++++++------ src/psqt.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 725ea49c..17c52e18 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 = 8 * pe->pawn_asymmetry() - + 12 * pos.count() - + 12 * outflanking - + 16 * pawnsOnBothFlanks - + 48 * !pos.non_pawn_material() - -118 ; + int complexity = 9 * pe->pawn_asymmetry() + + 11 * pos.count() + + 9 * outflanking + + 18 * pawnsOnBothFlanks + + 49 * !pos.non_pawn_material() + -121 ; // 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 diff --git a/src/psqt.cpp b/src/psqt.cpp index bc3e5392..26f14625 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,-11), S( -3,-4), S(13, -1), S( 19, -4), S(16, 17), S(13, 7), S( 4, 4), S( -4,-13) }, - { S(-16, -8), S(-12,-6), S(20, -3), S( 21, 0), S(25,-11), S(29, 3), S( 0, 0), S(-27, -1) }, - { S(-11, 3), S(-17, 6), S(11,-10), S( 21, 1), S(32, -6), S(19,-11), S( -5, 0), S(-14, -2) }, - { S( 4, 13), S( 6, 7), S(-8, 3), S( 3, -5), S( 8,-15), S(-2, -1), S(-19, 9), S( -5, 13) }, - { S( -5, 25), S(-19,20), S( 7, 16), S( 8, 12), S(-7, 21), S(-2, 3), S(-10, -4), S(-16, 15) }, - { S(-10, 6), S( 9,-5), S(-7, 16), S(-12, 27), S(-7, 15), S(-8, 11), S( 16, -7), S( -8, 4) } + { 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) } }; #undef S From 691a287bfe7a2afbfa1d2b3129f4a089b188b6e4 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sun, 20 Jan 2019 04:21:16 -0700 Subject: [PATCH 07/22] Clean-up some shifting in space calculation (#1955) No functional change. --- src/evaluate.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 17c52e18..5b914d87 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -701,7 +701,8 @@ namespace { if (pos.non_pawn_material() < SpaceThreshold) return SCORE_ZERO; - constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Color Them = (Us == WHITE ? BLACK : WHITE); + constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard SpaceMask = Us == WHITE ? CenterFiles & (Rank2BB | Rank3BB | Rank4BB) : CenterFiles & (Rank7BB | Rank6BB | Rank5BB); @@ -713,8 +714,8 @@ namespace { // Find all squares which are at most three squares behind some friendly pawn Bitboard behind = pos.pieces(Us, PAWN); - behind |= (Us == WHITE ? behind >> 8 : behind << 8); - behind |= (Us == WHITE ? behind >> 16 : behind << 16); + behind |= shift(behind); + behind |= shift(shift(behind)); int bonus = popcount(safe) + popcount(behind & safe); int weight = pos.count(Us) From 59b2486bc3d153b8946661c7a6a501f4410b4e66 Mon Sep 17 00:00:00 2001 From: marotear Date: Sun, 20 Jan 2019 03:24:03 -0800 Subject: [PATCH 08/22] Simplify pvHit (#1953) Removing unnecessary excludedMove condition (there is not excluded move for PvNodes) and re-ordering computation. Non functional change. --- src/search.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 933cab87..4a1a3523 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -640,7 +640,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; - pvHit = ttHit && tte->pv_hit(); + pvHit = (ttHit && tte->pv_hit()) || (PvNode && depth > 4 * ONE_PLY); // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -674,11 +674,6 @@ namespace { return ttValue; } - if ( depth > 4 * ONE_PLY - && !excludedMove - && PvNode) - pvHit = true; - // Step 5. Tablebases probe if (!rootNode && TB::Cardinality) { From 58d3ee61757215292b48e32caec9931d901c2940 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 20 Jan 2019 19:14:24 +0100 Subject: [PATCH 09/22] Simplify pondering time management (#1899) stopOnPonderhit is used to stop search quickly on a ponderhit. It is set by mainThread as part of its time management. However, master employs it as a signal between mainThread and the UCI thread. This is not necessary, it is sufficient for the UCI thread to signal that pondering finished, and mainThread should do its usual time-keeping job, and in this case stop immediately. This patch implements this, removing stopOnPonderHit as an atomic variable from the ThreadPool, and moving it as a normal variable to mainThread, reducing its scope. In MainThread::check_time() the search is stopped immediately if ponder switches to false, and the variable stopOnPonderHit is set. Furthermore, ponder has been moved to mainThread, as the variable is only used to exchange signals between the UCI thread and mainThread. The version has been tested locally (as fishtest doesn't support ponder): Score of ponderSimp vs master: 2616 - 2528 - 8630 [0.503] 13774 Elo difference: 2.22 +/- 3.54 which indicates no regression. No functional change. --- src/search.cpp | 17 ++++++++--------- src/thread.cpp | 4 ++-- src/thread.h | 4 +++- src/uci.cpp | 14 ++++++-------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4a1a3523..99985fde 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -227,10 +227,9 @@ void MainThread::search() { // Threads.stop. However, if we are pondering or in an infinite search, // the UCI protocol states that we shouldn't print the best move before the // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here - // until the GUI sends one of those commands (which also raises Threads.stop). - Threads.stopOnPonderhit = true; + // until the GUI sends one of those commands. - while (!Threads.stop && (Threads.ponder || Limits.infinite)) + while (!Threads.stop && (ponder || Limits.infinite)) {} // Busy wait for a stop or a ponder reset // Stop the threads if not already stopped (also raise the stop if @@ -448,7 +447,7 @@ void Thread::search() { { failedHighCnt = 0; failedLow = true; - Threads.stopOnPonderhit = false; + mainThread->stopOnPonderhit = false; } } else if (bestValue >= beta) @@ -497,7 +496,7 @@ void Thread::search() { // Do we have time for the next iteration? Can we stop searching now? if ( Limits.use_time_management() && !Threads.stop - && !Threads.stopOnPonderhit) + && !mainThread->stopOnPonderhit) { double fallingEval = (306 + 119 * failedLow + 6 * (mainThread->previousScore - bestValue)) / 581.0; fallingEval = std::max(0.5, std::min(1.5, fallingEval)); @@ -515,8 +514,8 @@ void Thread::search() { { // If we are allowed to ponder do not stop the search now but // keep pondering until the GUI sends "ponderhit" or "stop". - if (Threads.ponder) - Threads.stopOnPonderhit = true; + if (mainThread->ponder) + mainThread->stopOnPonderhit = true; else Threads.stop = true; } @@ -1595,10 +1594,10 @@ void MainThread::check_time() { } // We should not stop pondering until told so by the GUI - if (Threads.ponder) + if (ponder) return; - if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10) + if ( (Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit)) || (Limits.movetime && elapsed >= Limits.movetime) || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes)) Threads.stop = true; diff --git a/src/thread.cpp b/src/thread.cpp index f88e359b..6c1d7299 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -162,8 +162,8 @@ void ThreadPool::start_thinking(Position& pos, StateListPtr& states, main()->wait_for_search_finished(); - stopOnPonderhit = stop = false; - ponder = ponderMode; + main()->stopOnPonderhit = stop = false; + main()->ponder = ponderMode; Search::Limits = limits; Search::RootMoves rootMoves; diff --git a/src/thread.h b/src/thread.h index e377e992..686441cb 100644 --- a/src/thread.h +++ b/src/thread.h @@ -88,6 +88,8 @@ struct MainThread : public Thread { double bestMoveChanges, previousTimeReduction; Value previousScore; int callsCnt; + bool stopOnPonderhit; + std::atomic_bool ponder; }; @@ -105,7 +107,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, ponder, stopOnPonderhit; + std::atomic_bool stop; private: StateListPtr setupStates; diff --git a/src/uci.cpp b/src/uci.cpp index 36d359c6..739cf343 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -207,18 +207,16 @@ void UCI::loop(int argc, char* argv[]) { token.clear(); // Avoid a stale if getline() returns empty or blank line is >> skipws >> token; + if ( token == "quit" + || token == "stop") + Threads.stop = true; + // The GUI sends 'ponderhit' to tell us the user has played the expected move. // So 'ponderhit' will be sent if we were told to ponder on the same move the // user has played. We should continue searching but switch from pondering to - // normal search. In case Threads.stopOnPonderhit is set we are waiting for - // 'ponderhit' to stop the search, for instance if max search depth is reached. - if ( token == "quit" - || token == "stop" - || (token == "ponderhit" && Threads.stopOnPonderhit)) - Threads.stop = true; - + // normal search. else if (token == "ponderhit") - Threads.ponder = false; // Switch to normal search + Threads.main()->ponder = false; // Switch to normal search else if (token == "uci") sync_cout << "id name " << engine_info(true) From 2d0af36753a2f1acdf43b4e1d30d56ad8effc429 Mon Sep 17 00:00:00 2001 From: protonspring Date: Mon, 21 Jan 2019 11:55:51 -0700 Subject: [PATCH 10/22] Simplify TrappedRook Simplified TrappedRook to a single penalty removing the dependency on mobility. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 106718 W: 23530 L: 23577 D: 59611 http://tests.stockfishchess.org/tests/view/5c43f6bd0ebc5902bb5d4131 LTC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 54053 W: 8890 L: 8822 D: 36341 http://tests.stockfishchess.org/tests/view/5c44932a0ebc5902bb5d4d59 bench 3665090 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 5b914d87..6bacb4ed 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -168,7 +168,7 @@ namespace { constexpr Score ThreatByPawnPush = S( 48, 39); constexpr Score ThreatByRank = S( 13, 0); constexpr Score ThreatBySafePawn = S(173, 94); - constexpr Score TrappedRook = S( 96, 4); + constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); constexpr Score WeakUnopposedPawn = S( 12, 23); @@ -377,7 +377,7 @@ namespace { { File kf = file_of(pos.square(Us)); if ((kf < FILE_E) == (file_of(s) < kf)) - score -= (TrappedRook - make_score(mob * 22, 0)) * (1 + !pos.castling_rights(Us)); + score -= TrappedRook * (1 + !pos.castling_rights(Us)); } } From 8df1cd10df0869f05916d1eb19e33b66127fcb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 26 Jan 2019 09:16:17 -0800 Subject: [PATCH 11/22] Use int8_t instead of int for SquareDistance[] This patch saves (4-1) * 64 * 64 = 12KiB of cache. STC LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 176120 W: 38944 L: 38087 D: 99089 http://tests.stockfishchess.org/tests/view/5c4c9f840ebc593af5d4a7ce LTC As a pure speed up, I've been informed it should not require LTC. No functional change --- src/bitboard.cpp | 2 +- src/bitboard.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 77f49ef6..105d201f 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -24,7 +24,7 @@ #include "misc.h" uint8_t PopCnt16[1 << 16]; -int SquareDistance[SQUARE_NB][SQUARE_NB]; +int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; Bitboard FileBB[FILE_NB]; diff --git a/src/bitboard.h b/src/bitboard.h index e1c31dd7..b64c92e1 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -60,7 +60,7 @@ constexpr Bitboard Rank6BB = Rank1BB << (8 * 5); constexpr Bitboard Rank7BB = Rank1BB << (8 * 6); constexpr Bitboard Rank8BB = Rank1BB << (8 * 7); -extern int SquareDistance[SQUARE_NB][SQUARE_NB]; +extern int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB]; extern Bitboard FileBB[FILE_NB]; From 242c566c1a80c7f3d95774eac513935fcee0cf0d Mon Sep 17 00:00:00 2001 From: Miguel Lahoz Date: Fri, 25 Jan 2019 14:37:03 +0800 Subject: [PATCH 12/22] Change pinning logic in Static Exchange Evaluation (SEE) This changes 2 parts with regards to static exchange evaluation. Currently, we do not allow pinned pieces to recapture if *all* opponent pinners are still in their starting squares. This changes that to having a less strict requirement, checking if *any* pinners are still in their starting square. This makes our SEE give more respect to the pinning side with regards to exchanges, which makes sense because it helps our search explore more tactical options. Furthermore, we change the logic for saving pinners into our state variable when computing slider_blockers. We will include double pinners, where two sliders may be looking at the same blocker, a similar concept to our mobility calculation for sliders in our evaluation section. Interestingly, I think SEE is the only place where the pinners bitboard is actually used, so as far as I know there are no other side effects to this change. An example and some insights: White Bf2, Kg1 Black Qe3, Bc5 The move Qg3 will be given the correct value of 0. (Previously < 0) The move Qd4 will be incorrectly given a value of 0. (Previously < 0) It seems the tradeoff in search is worth it. Qd4 will likely be pruned soon by something like probcut anyway, while Qg3 could help us spot tactics at an earlier depth. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 62162 W: 13879 L: 13408 D: 34875 http://tests.stockfishchess.org/tests/view/5c4ba1a70ebc593af5d49c55 LTC: (Thanks to @alayant) LLR: 3.40 (-2.94,2.94) [0.00,3.50] Total: 140285 W: 23416 L: 22825 D: 94044 http://tests.stockfishchess.org/tests/view/5c4bcfba0ebc593af5d49ea8 Bench: 3937213 --- src/position.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 21eff88c..812eabca 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -498,14 +498,15 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners Bitboard blockers = 0; pinners = 0; - // Snipers are sliders that attack 's' when a piece is removed + // 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; while (snipers) { Square sniperSq = pop_lsb(&snipers); - Bitboard b = between_bb(s, sniperSq) & pieces(); + Bitboard b = between_bb(s, sniperSq) & occupancy; if (b && !more_than_one(b)) { @@ -1076,8 +1077,8 @@ bool Position::see_ge(Move m, Value threshold) const { stmAttackers = attackers & pieces(stm); // Don't allow pinned pieces to attack (except the king) as long as - // all pinners are on their original square. - if (!(st->pinners[~stm] & ~occupied)) + // any pinners are on their original square. + if (st->pinners[~stm] & occupied) stmAttackers &= ~st->blockersForKing[stm]; // If stm has no more attackers then give up: stm loses From 3302349662f8c0b01946cd9d62ac087685c0c816 Mon Sep 17 00:00:00 2001 From: DU-jdto Date: Wed, 23 Jan 2019 15:19:10 +1100 Subject: [PATCH 13/22] Don't update pvHit after IID This patch removes line 875 of search.cpp, which was updating pvHit after IID. Bench testing at depth 22 shows that line 875 of search.cpp never changes the value of pvHit at NonPV nodes, while at PV nodes it often changes the value from true to false (and never the reverse). This is because the definition of pvHit at line 642 is : ``` pvHit = (ttHit && tte->pv_hit()) || (PvNode && depth > 4 * ONE_PLY); ``` while the assignment after IID omits the ` (PvNode && depth > 4 * ONE_PLY) ` condition. As such, unlike the other two post-IID tte reads, this line of code does not make SF's state more consistent, but rather introduces an inconsistency in the definition of pvHit. Indeed, changing line 875 read ``` pvHit = (ttHit && tte->pv_hit()) || (PvNode && depth > 4 * ONE_PLY); ``` to match line 642 is functionally equivalent to removing the line entirely, as this patch does. STC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 62756 W: 13787 L: 13746 D: 35223 http://tests.stockfishchess.org/tests/view/5c446c850ebc5902bb5d4b75 LTC LLR: 3.19 (-2.94,2.94) [-3.00,1.00] Total: 61900 W: 10179 L: 10111 D: 41610 http://tests.stockfishchess.org/tests/view/5c45bf610ebc5902bb5d5d62 Bench: 3796134 --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 99985fde..cc8abc9e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -872,7 +872,6 @@ namespace { tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; - pvHit = ttHit && tte->pv_hit(); } moves_loop: // When in check, search starts from here From d1fd1a96bc62346b727dd3797df429f7e627f5ef Mon Sep 17 00:00:00 2001 From: protonspring Date: Thu, 31 Jan 2019 15:18:33 +0100 Subject: [PATCH 14/22] Simplify Stat Score bonus This is a functional simplification of this statScore bonus. There seems to be little risk of regression with this one. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 26829 W: 5892 L: 5781 D: 15156 http://tests.stockfishchess.org/tests/view/5c5086bb0ebc593af5d4db75 LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 28232 W: 4684 L: 4575 D: 18973 http://tests.stockfishchess.org/tests/view/5c50d7690ebc593af5d4dec9 Closes https://github.com/official-stockfish/Stockfish/pull/1979 Bench: 4001014 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cc8abc9e..de67560a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -747,9 +747,7 @@ namespace { { if ((ss-1)->currentMove != MOVE_NULL) { - int p = (ss-1)->statScore; - int bonus = p > 0 ? (-p - 2500) / 512 : - p < 0 ? (-p + 2500) / 512 : 0; + int bonus = -(ss-1)->statScore / 512; pureStaticEval = evaluate(pos); ss->staticEval = eval = pureStaticEval + bonus; From 3f7ec977cdae7a59c58342f3752bccb293d4e206 Mon Sep 17 00:00:00 2001 From: Vizvezdenec Date: Fri, 1 Feb 2019 09:21:23 +0300 Subject: [PATCH 15/22] More precise checks evaluation in king danger Remove overlapping safe checks from kingdanger: - rook and queen checks from the same square: rook check is preferred - bishop and queen checks form the same square: queen check is preferred Increase bishop and rook check values as a compensation. STC LLR: 2.95 (-2.94,2.94) [0.50,4.50] Total: 27480 W: 6111 L: 5813 D: 15556 http://tests.stockfishchess.org/tests/view/5c521d050ebc593af5d4e66a LTC LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 78500 W: 13145 L: 12752 D: 52603 http://tests.stockfishchess.org/tests/view/5c52b9460ebc592fc7baecc5 Closes https://github.com/official-stockfish/Stockfish/pull/1983 ------------------------------------------ I have quite a few ideas of how to improve this patch. - actually rethinking it now it will maybe be useful to discount queen/bishop checks if there is only one square that they can give check from and it's "occupied" by more valuable check. Right now count of this squares does not really matter. - maybe some small extra bonus can be given for overlapping checks. - some ideas about using popcount() on safechecks can be retried. - tune this safecheck values since they were more or less randomly handcrafted in this patch. Bench: 3216489 --- src/evaluate.cpp | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 6bacb4ed..da90eed9 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -93,8 +93,8 @@ namespace { // Penalties for enemy's safe checks constexpr int QueenSafeCheck = 780; - constexpr int RookSafeCheck = 880; - constexpr int BishopSafeCheck = 435; + constexpr int RookSafeCheck = 1080; + constexpr int BishopSafeCheck = 635; constexpr int KnightSafeCheck = 790; #define S(mg, eg) make_score(mg, eg) @@ -434,27 +434,42 @@ namespace { b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Enemy queen safe checks - if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN]) - kingDanger += QueenSafeCheck; - - b1 &= attackedBy[Them][ROOK]; - b2 &= attackedBy[Them][BISHOP]; - // Enemy rooks checks - if (b1 & safe) + Bitboard RookCheck = b1 + & safe + & attackedBy[Them][ROOK]; + + if (RookCheck) kingDanger += RookSafeCheck; else - unsafeChecks |= b1; + unsafeChecks |= b1 & attackedBy[Them][ROOK]; - // Enemy bishops checks - if (b2 & safe) + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. + Bitboard QueenCheck = (b1 | b2) + & attackedBy[Them][QUEEN] + & safe + & ~attackedBy[Us][QUEEN] + & ~RookCheck; + + if (QueenCheck) + kingDanger += 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. + Bitboard BishopCheck = b2 + & attackedBy[Them][BISHOP] + & safe + & ~QueenCheck; + + if (BishopCheck) kingDanger += BishopSafeCheck; else - unsafeChecks |= b2; + unsafeChecks |= b2 & attackedBy[Them][BISHOP]; // Enemy knights checks b = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + if (b & safe) kingDanger += KnightSafeCheck; else From ff97a9fdb936a73de774df062f35d454a4a9af00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicolet?= Date: Fri, 1 Feb 2019 13:09:17 +0100 Subject: [PATCH 16/22] Tweak tropism weight in king danger There was a simplification attempt last week for the tropism term in king danger, which passed STC but failed LTC. This was an indirect sign that maybe the tropism factor was sightly untuned in current master, so we tried to change it from 1/4 to 5/16. STC: LLR: 2.95 (-2.94,2.94) [0.00,4.00] Total: 28098 W: 6264 L: 5990 D: 15844 http://tests.stockfishchess.org/tests/view/5c518db60ebc593af5d4e306 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 103709 W: 17387 L: 16923 D: 69399 http://tests.stockfishchess.org/tests/view/5c52a5510ebc592fc7baea8b Bench: 4016000 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index da90eed9..9bdb2b99 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -483,7 +483,7 @@ namespace { + 69 * kingAttacksCount[Them] + 185 * popcount(kingRing[Us] & weak) + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) - + tropism * tropism / 4 + + 5 * tropism * tropism / 16 - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) From 9050eac59564fe96b3f24d2889bbef7336b28100 Mon Sep 17 00:00:00 2001 From: Miguel Lahoz Date: Tue, 29 Jan 2019 22:26:03 +0800 Subject: [PATCH 17/22] Extend discovered checks regardless of SEE A simple idea, but it makes sense: in current master the search is extended for checks that are considered somewhat safe, and for for this we use the static exchange evaluation which only considers the `to_sq` of a move. This is not reliable for discovered checks, where another piece is giving the check and is arguably a more dangerous type of check. Thus, if the check is a discovered check, the result of SEE is not relevant and can be ignored. STC: LLR: 2.96 (-2.94,2.94) [0.50,4.50] Total: 29370 W: 6583 L: 6274 D: 16513 http://tests.stockfishchess.org/tests/view/5c5062950ebc593af5d4d9b5 LTC: LLR: 2.95 (-2.94,2.94) [0.00,3.50] Total: 227341 W: 37972 L: 37165 D: 152204 http://tests.stockfishchess.org/tests/view/5c5094fb0ebc593af5d4dc2c Bench: 3611854 --- src/search.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index de67560a..651bd95b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -953,11 +953,13 @@ moves_loop: // When in check, search starts from here else if (cutNode && singularBeta > beta) return beta; } - else if ( givesCheck // Check extension (~2 Elo) - && pos.see_ge(move)) + + // Check extension (~2 Elo) + else if ( givesCheck + && (pos.blockers_for_king(~us) & from_sq(move) || pos.see_ge(move))) extension = ONE_PLY; - // Extension if castling + // Castling extension else if (type_of(move) == CASTLING) extension = ONE_PLY; From 651450023619ddea590f301f040286151004df66 Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 3 Feb 2019 05:16:34 -0800 Subject: [PATCH 18/22] Less king danger if we have a knight near by to defend it. (#1987) bench: 3653942 --- src/evaluate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9bdb2b99..617e33fb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -482,12 +482,13 @@ namespace { kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] + 69 * kingAttacksCount[Them] + 185 * popcount(kingRing[Us] & weak) + - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) + 5 * tropism * tropism / 16 - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) - - 30; + - 25; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 0) From dd4796fcd5559847d4b8aab7d21ffff9929799ce Mon Sep 17 00:00:00 2001 From: protonspring Date: Fri, 8 Feb 2019 01:54:38 -0700 Subject: [PATCH 19/22] Remove Some Bitboard Arrays (#1963) This is non-functional. These 5 arrays are simple enough to calculate real-time and maintaining an array for them does not help. Decreases the memory footprint. This seems a tiny bit slower on my machine, but passed STC well enough. Could someone verify speed? STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 44745 W: 9780 L: 9704 D: 25261 http://tests.stockfishchess.org/tests/view/5c47aa2d0ebc5902bca13fc4 The slowdown is minimal even in 32 bit case (thanks to @mstembera for testing): Compiled using make build ARCH=x86-32 CXX=i686-w64-mingw32-c++ and benched This patch only: ``` Results for 40 tests for each version: Base Test Diff Mean 1455204 1450033 5171 StDev 49452 34533 59621 p-value: 0.465 speedup: -0.004 ``` No functional change. --- src/bitboard.cpp | 21 +-------------------- src/bitboard.h | 24 ++++++++---------------- 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 105d201f..13735e3d 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -27,15 +27,10 @@ uint8_t PopCnt16[1 << 16]; int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; -Bitboard FileBB[FILE_NB]; -Bitboard RankBB[RANK_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 ForwardFileBB[COLOR_NB][SQUARE_NB]; -Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; -Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; @@ -90,22 +85,8 @@ void Bitboards::init() { for (Square s = SQ_A1; s <= SQ_H8; ++s) SquareBB[s] = (1ULL << s); - for (File f = FILE_A; f <= FILE_H; ++f) - FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB; - - for (Rank r = RANK_1; r <= RANK_8; ++r) - RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB; - for (Rank r = RANK_1; r < RANK_8; ++r) - ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | RankBB[r]); - - for (Color c = WHITE; c <= BLACK; ++c) - for (Square s = SQ_A1; s <= SQ_H8; ++s) - { - ForwardFileBB [c][s] = ForwardRanksBB[c][rank_of(s)] & FileBB[file_of(s)]; - PawnAttackSpan[c][s] = ForwardRanksBB[c][rank_of(s)] & adjacent_files_bb(file_of(s)); - PassedPawnMask[c][s] = ForwardFileBB [c][s] | PawnAttackSpan[c][s]; - } + ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | rank_bb(r)); for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) diff --git a/src/bitboard.h b/src/bitboard.h index b64c92e1..8fa77481 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -63,15 +63,10 @@ constexpr Bitboard Rank8BB = Rank1BB << (8 * 7); extern int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB]; -extern Bitboard FileBB[FILE_NB]; -extern Bitboard RankBB[RANK_NB]; extern Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; extern Bitboard DistanceRingBB[SQUARE_NB][8]; -extern Bitboard ForwardFileBB[COLOR_NB][SQUARE_NB]; -extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; -extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; @@ -142,19 +137,19 @@ inline bool opposite_colors(Square s1, Square s2) { /// the given file or rank. inline Bitboard rank_bb(Rank r) { - return RankBB[r]; + return Rank1BB << (8 * r); } inline Bitboard rank_bb(Square s) { - return RankBB[rank_of(s)]; + return rank_bb(rank_of(s)); } inline Bitboard file_bb(File f) { - return FileBB[f]; + return FileABB << f; } inline Bitboard file_bb(Square s) { - return FileBB[file_of(s)]; + return file_bb(file_of(s)); } @@ -194,10 +189,9 @@ constexpr Bitboard double_pawn_attacks_bb(Bitboard b) { /// adjacent files of the given one. inline Bitboard adjacent_files_bb(File f) { - return shift(FileBB[f]) | shift(FileBB[f]); + return shift(file_bb(f)) | shift(file_bb(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 @@ -222,26 +216,24 @@ inline Bitboard forward_ranks_bb(Color c, Square s) { /// ForwardFileBB[c][s] = forward_ranks_bb(c, s) & file_bb(s) inline Bitboard forward_file_bb(Color c, Square s) { - return ForwardFileBB[c][s]; + return ForwardRanksBB[c][rank_of(s)] & file_bb(s); } /// pawn_attack_span() returns a bitboard representing all the squares that can be /// attacked by a pawn of the given color when it moves along its file, starting /// from the given square: -/// PawnAttackSpan[c][s] = forward_ranks_bb(c, s) & adjacent_files_bb(file_of(s)); inline Bitboard pawn_attack_span(Color c, Square s) { - return PawnAttackSpan[c][s]; + return forward_ranks_bb(c, s) & adjacent_files_bb(file_of(s)); } /// passed_pawn_mask() returns a bitboard mask which can be used to test if a /// pawn of the given color and on the given square is a passed pawn: -/// PassedPawnMask[c][s] = pawn_attack_span(c, s) | forward_file_bb(c, s) inline Bitboard passed_pawn_mask(Color c, Square s) { - return PassedPawnMask[c][s]; + return pawn_attack_span(c, s) | forward_file_bb(c, s); } From 05f7d59a9a27d9f8bce8bde4e9fed7ecefeb03b9 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Tue, 1 Jan 2019 14:13:08 +0100 Subject: [PATCH 21/22] Assorted trivial cleanups 1/2019 To address #1862 No functional change. --- src/bitboard.h | 12 ++++---- src/evaluate.cpp | 65 +++++++++++++++++++++---------------------- src/movepick.cpp | 8 +++--- src/psqt.cpp | 52 +++++++++++++++++----------------- src/search.cpp | 32 ++++++++++----------- src/tt.cpp | 8 ++++-- src/tt.h | 6 ++-- src/types.h | 4 ++- tests/instrumented.sh | 2 +- 9 files changed, 94 insertions(+), 95 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index 8fa77481..cf52b39d 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -153,7 +153,7 @@ inline Bitboard file_bb(Square s) { } -/// shift() moves a bitboard one step along direction D (mainly for pawns) +/// shift() moves a bitboard one step along direction D template constexpr Bitboard shift(Bitboard b) { @@ -165,8 +165,8 @@ constexpr Bitboard shift(Bitboard b) { } -/// pawn_attacks_bb() returns the pawn attacks for the given color from the -/// squares in the given bitboard. +/// pawn_attacks_bb() returns the squares attacked by pawns of the given color +/// from the squares in the given bitboard. template constexpr Bitboard pawn_attacks_bb(Bitboard b) { @@ -175,11 +175,11 @@ constexpr Bitboard pawn_attacks_bb(Bitboard b) { } -/// double_pawn_attacks_bb() returns the pawn attacks for the given color -/// from the squares in the given bitboard. +/// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the +/// given color from the squares in the given bitboard. template -constexpr Bitboard double_pawn_attacks_bb(Bitboard b) { +constexpr Bitboard pawn_double_attacks_bb(Bitboard b) { return C == WHITE ? shift(b) & shift(b) : shift(b) & shift(b); } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 617e33fb..fce0835e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -153,8 +153,8 @@ namespace { // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); - constexpr Score CloseEnemies = S( 8, 0); 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); @@ -245,33 +245,37 @@ namespace { constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB: Rank7BB | Rank6BB); + const Square ksq = pos.square(Us); + // 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. + // 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)); - // Initialise attackedBy bitboards for kings and pawns - attackedBy[Us][KING] = pos.attacks_from(pos.square(Us)); + // Initialize attackedBy[] for king and pawns + 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]; // Init our king safety tables kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, pos.square(Us)) == RANK_1) + if (relative_rank(Us, ksq) == RANK_1) kingRing[Us] |= shift(kingRing[Us]); - if (file_of(pos.square(Us)) == FILE_H) + if (file_of(ksq) == FILE_H) kingRing[Us] |= shift(kingRing[Us]); - else if (file_of(pos.square(Us)) == FILE_A) + else if (file_of(ksq) == FILE_A) kingRing[Us] |= shift(kingRing[Us]); kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); - kingRing[Us] &= ~double_pawn_attacks_bb(pos.pieces(Us, PAWN)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; + + // Remove from kingRing[] the squares defended by two pawns + kingRing[Us] &= ~pawn_double_attacks_bb(pos.pieces(Us, PAWN)); } @@ -286,12 +290,11 @@ namespace { const Square* pl = pos.squares(Us); Bitboard b, bb; - Square s; Score score = SCORE_ZERO; attackedBy[Us][Pt] = 0; - while ((s = *pl++) != SQ_NONE) + for (Square s = *pl; s != SQ_NONE; s = *++pl) { // Find attacked squares, including x-ray attacks for bishops and rooks b = Pt == BISHOP ? attacks_bb(s, pos.pieces() ^ pos.pieces(QUEEN)) @@ -404,23 +407,12 @@ namespace { constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); - const Square ksq = pos.square(Us); - Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks; - - // King shelter and enemy pawns storm - Score score = pe->king_safety(pos); - - // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. - kingFlank = KingFlank[file_of(ksq)]; - b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; - b2 = b1 & attackedBy2[Them]; - - int tropism = popcount(b1) + popcount(b2); - - // Main king safety evaluation + Bitboard weak, b, b1, b2, safe, unsafeChecks = 0; int kingDanger = 0; - unsafeChecks = 0; + const Square ksq = pos.square(Us); + + // Init the score with king shelter and enemy pawns storm + Score score = pe->king_safety(pos); // Attacked squares defended at most once by our queen or king weak = attackedBy[Them][ALL_PIECES] @@ -457,7 +449,7 @@ namespace { // 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. - Bitboard BishopCheck = b2 + Bitboard BishopCheck = b2 & attackedBy[Them][BISHOP] & safe & ~QueenCheck; @@ -479,15 +471,22 @@ namespace { // 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; + b2 = b1 & attackedBy2[Them]; + + 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]) + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) - + 5 * tropism * tropism / 16 - 873 * !pos.count(Them) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) + + 5 * kingFlankAttacks * kingFlankAttacks / 16 - 25; // Transform the kingDanger units into a Score, and subtract it from the evaluation @@ -495,11 +494,11 @@ namespace { score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); // Penalty when our king is on a pawnless flank - if (!(pos.pieces(PAWN) & kingFlank)) + if (!(pos.pieces(PAWN) & KingFlank[file_of(ksq)])) score -= PawnlessFlank; - // King tropism bonus, to anticipate slow motion attacks on our king - score -= CloseEnemies * tropism; + // Penalty if king flank is under attack, potentially moving toward the king + score -= FlankAttacks * kingFlankAttacks; if (T) Trace::add(KING, Us, score); @@ -859,7 +858,7 @@ namespace { v = mg_value(score) * int(me->game_phase()) + eg_value(score) * int(PHASE_MIDGAME - me->game_phase()) * sf / SCALE_FACTOR_NORMAL; - v /= int(PHASE_MIDGAME); + v /= PHASE_MIDGAME; // In case of tracing add all remaining individual evaluation terms if (T) diff --git a/src/movepick.cpp b/src/movepick.cpp index d8ab68e7..87c3f6fa 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -76,9 +76,9 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist assert(d <= DEPTH_ZERO); stage = pos.checkers() ? EVASION_TT : QSEARCH_TT; - ttMove = ttm - && pos.pseudo_legal(ttm) - && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) ? ttm : MOVE_NONE; + ttMove = ttm + && (depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare) + && pos.pseudo_legal(ttm) ? ttm : MOVE_NONE; stage += (ttMove == MOVE_NONE); } @@ -91,8 +91,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePiece stage = PROBCUT_TT; ttMove = ttm - && pos.pseudo_legal(ttm) && pos.capture(ttm) + && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold) ? ttm : MOVE_NONE; stage += (ttMove == MOVE_NONE); } diff --git a/src/psqt.cpp b/src/psqt.cpp index 26f14625..cba6bb06 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -59,46 +59,46 @@ 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(-1,-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(-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(-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) } }, { // Queen - { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, - { S( -3,-55), S( 5,-31), S( 8,-22), S(12, -4) }, - { S( -3,-39), S( 6,-18), S(13, -9), S( 7, 3) }, - { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) }, - { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) }, - { S( -4,-38), S(10,-18), S( 6,-12), S( 8, 1) }, - { S( -5,-50), S( 6,-27), S(10,-24), S( 8, -8) }, - { S( -2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } + { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, + { S(-3,-55), S( 5,-31), S( 8,-22), S(12, -4) }, + { S(-3,-39), S( 6,-18), S(13, -9), S( 7, 3) }, + { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) }, + { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) }, + { S(-4,-38), S(10,-18), S( 6,-12), S( 8, 1) }, + { S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) }, + { 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(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) } } }; 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( 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) } }; #undef S diff --git a/src/search.cpp b/src/search.cpp index 651bd95b..c6b59b39 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -258,27 +258,23 @@ void MainThread::search() { // Find out minimum score and reset votes for moves which can be voted for (Thread* th: Threads) - { minScore = std::min(minScore, th->rootMoves[0].score); - votes[th->rootMoves[0].pv[0]] = 0; - } // Vote according to score and depth - auto square = [](int64_t x) { return x * x; }; - for (Thread* th : Threads) - votes[th->rootMoves[0].pv[0]] += 200 + (square(th->rootMoves[0].score - minScore + 1) - * int64_t(th->completedDepth)); - - // Select best thread - int64_t bestVote = votes[this->rootMoves[0].pv[0]]; for (Thread* th : Threads) { + int64_t s = th->rootMoves[0].score - minScore + 1; + votes[th->rootMoves[0].pv[0]] += 200 + s * s * int(th->completedDepth); + } + + // Select best thread + auto bestVote = votes[this->rootMoves[0].pv[0]]; + for (Thread* th : Threads) if (votes[th->rootMoves[0].pv[0]] > bestVote) { bestVote = votes[th->rootMoves[0].pv[0]]; bestThread = th; } - } } previousScore = bestThread->rootMoves[0].score; @@ -573,7 +569,7 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; - bool ttHit, pvHit, inCheck, givesCheck, improving; + bool ttHit, ttPv, inCheck, givesCheck, improving; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount; @@ -639,7 +635,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; - pvHit = (ttHit && tte->pv_hit()) || (PvNode && depth > 4 * ONE_PLY); + ttPv = (ttHit && tte->is_pv()) || (PvNode && depth > 4 * ONE_PLY); // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -706,7 +702,7 @@ namespace { if ( b == BOUND_EXACT || (b == BOUND_LOWER ? value >= beta : value <= alpha)) { - tte->save(posKey, value_to_tt(value, ss->ply), pvHit, b, + tte->save(posKey, value_to_tt(value, ss->ply), ttPv, b, std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), MOVE_NONE, VALUE_NONE); @@ -755,7 +751,7 @@ namespace { else ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo; - tte->save(posKey, VALUE_NONE, pvHit, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); + tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); } // Step 7. Razoring (~2 Elo) @@ -1032,7 +1028,7 @@ moves_loop: // When in check, search starts from here Depth r = reduction(improving, depth, moveCount); // Decrease reduction if position is or has been on the PV - if (pvHit) + if (ttPv) r -= ONE_PLY; // Decrease reduction if opponent's move count is high (~10 Elo) @@ -1213,7 +1209,7 @@ moves_loop: // When in check, search starts from here bestValue = std::min(bestValue, maxValue); if (!excludedMove) - tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, + tte->save(posKey, value_to_tt(bestValue, ss->ply), ttPv, bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, depth, bestMove, pureStaticEval); @@ -1277,7 +1273,7 @@ moves_loop: // When in check, search starts from here tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; - pvHit = ttHit && tte->pv_hit(); + pvHit = ttHit && tte->is_pv(); if ( !PvNode && ttHit diff --git a/src/tt.cpp b/src/tt.cpp index aa57efb6..33768ca4 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -30,8 +30,10 @@ TranspositionTable TT; // Our global transposition table -/// TTEntry::save saves a TTEntry -void TTEntry::save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value ev) { +/// TTEntry::save populates the TTEntry with a new node's data, possibly +/// overwriting an old position. Update is not atomic and can be racy. + +void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) { assert(d / ONE_PLY * ONE_PLY == d); @@ -47,7 +49,7 @@ void TTEntry::save(Key k, Value v, bool PvNode, Bound b, Depth d, Move m, Value key16 = (uint16_t)(k >> 48); value16 = (int16_t)v; eval16 = (int16_t)ev; - genBound8 = (uint8_t)(TT.generation8 | PvNode << 2 | b); + genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b); depth8 = (int8_t)(d / ONE_PLY); } } diff --git a/src/tt.h b/src/tt.h index 8b98dbd5..fefc8e2c 100644 --- a/src/tt.h +++ b/src/tt.h @@ -31,7 +31,7 @@ /// value 16 bit /// eval value 16 bit /// generation 5 bit -/// PvNode 1 bit +/// pv node 1 bit /// bound type 2 bit /// depth 8 bit @@ -41,9 +41,9 @@ struct TTEntry { Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)); } - bool pv_hit() 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 PvNode, Bound b, Depth d, Move m, Value ev); + void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); private: friend class TranspositionTable; diff --git a/src/types.h b/src/types.h index 8e27606c..a7415519 100644 --- a/src/types.h +++ b/src/types.h @@ -141,9 +141,11 @@ enum CastlingRight { 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, - ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING, + ANY_CASTLING = WHITE_CASTLING | BLACK_CASTLING, + CASTLING_RIGHT_NB = 16 }; diff --git a/tests/instrumented.sh b/tests/instrumented.sh index 5156e02f..ae6d5c4b 100755 --- a/tests/instrumented.sh +++ b/tests/instrumented.sh @@ -45,7 +45,7 @@ race:TTEntry::bound race:TTEntry::save race:TTEntry::value race:TTEntry::eval -race:TTEntry::pv_hit +race:TTEntry::is_pv race:TranspositionTable::probe race:TranspositionTable::hashfull From 3c92f849ab940fd9ac70e838e6d941827fc69cb6 Mon Sep 17 00:00:00 2001 From: protonspring Date: Sat, 12 Jan 2019 19:30:56 -0700 Subject: [PATCH 22/22] Change outposts to single value #1946 This is a functional simplification of the Outposts array moving it to a single value. This is a duplicate PR because I couldn't figure out how to fix the original one. The idea is from @31m059 with formatting recommendations by @snicolet. See #1940 for additional information. STC LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 23933 W: 5279 L: 5162 D: 13492 http://tests.stockfishchess.org/tests/view/5c3575800ebc596a450c5ecb LTC LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 41718 W: 6919 L: 6831 D: 27968 http://tests.stockfishchess.org/tests/view/5c358c440ebc596a450c6117 bench 3783543 --- src/evaluate.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fce0835e..98082c4c 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -117,14 +117,6 @@ namespace { S(106,184), S(109,191), S(113,206), S(116,212) } }; - // Outpost[knight/bishop][supported by pawn] contains bonuses for minor - // pieces if they occupy or can reach an outpost square, bigger if that - // square is supported by a pawn. - constexpr Score Outpost[][2] = { - { S(22, 6), S(36,12) }, // Knight - { S( 9, 2), S(15, 5) } // Bishop - }; - // 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) }; @@ -171,6 +163,7 @@ namespace { constexpr Score TrappedRook = S( 47, 4); constexpr Score WeakQueen = S( 49, 15); constexpr Score WeakUnopposedPawn = S( 12, 23); + constexpr Score Outpost = S( 9, 3); #undef S @@ -324,10 +317,12 @@ namespace { // Bonus if piece is on an outpost square or can reach one bb = OutpostRanks & ~pe->pawn_attacks_span(Them); if (bb & s) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & s)] * 2; + score += Outpost * (Pt == KNIGHT ? 4 : 2) + * (1 + bool(attackedBy[Us][PAWN] & s)); else if (bb &= b & ~pos.pieces(Us)) - score += Outpost[Pt == BISHOP][bool(attackedBy[Us][PAWN] & bb)]; + score += Outpost * (Pt == KNIGHT ? 2 : 1) + * (1 + bool(attackedBy[Us][PAWN] & bb)); // Knight and Bishop bonus for being right behind a pawn if (shift(pos.pieces(PAWN)) & s)