From d39bc2efa197ba2fd55b68eced1c60bcfe2facc1 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 2 May 2019 19:36:25 +0200 Subject: [PATCH 1/1] Assorted trivial cleanups 5/2019 No functional change. bench: 4178282 --- Readme.md | 28 ++++++++++++++-------------- src/endgame.cpp | 37 +++++++++++++++++++------------------ src/endgame.h | 8 ++++---- src/evaluate.cpp | 8 +++----- src/main.cpp | 2 +- src/pawns.h | 1 - src/position.cpp | 12 ++++++------ src/search.cpp | 45 ++++++++++++++++++--------------------------- src/search.h | 2 +- src/tt.cpp | 7 ++++--- src/tt.h | 2 +- src/types.h | 5 +++-- 12 files changed, 74 insertions(+), 83 deletions(-) diff --git a/Readme.md b/Readme.md index bc058dbc..be324763 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ ## Overview [![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?branch=master&svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish/branch/master) [Stockfish](https://stockfishchess.org) is a free, powerful UCI chess engine derived from Glaurung 2.1. It is not a complete chess program and requires a @@ -34,11 +34,11 @@ Currently, Stockfish has the following UCI options: A positive value for contempt favors middle game positions and avoids draws. * #### Analysis Contempt - By default, contempt is set to prefer the side to move. Set this option to "White" + By default, contempt is set to prefer the side to move. Set this option to "White" or "Black" to analyse with contempt for that side, or "Off" to disable contempt. * #### Threads - The number of CPU threads used for searching a position. For best performance, set + The number of CPU threads used for searching a position. For best performance, set this equal to the number of CPU cores available. * #### Hash @@ -58,18 +58,18 @@ Currently, Stockfish has the following UCI options: Lower the Skill Level in order to make Stockfish play weaker. * #### Move Overhead - Assume a time delay of x ms due to network and GUI overheads. This is useful to + Assume a time delay of x ms due to network and GUI overheads. This is useful to avoid losses on time in those cases. * #### Minimum Thinking Time - Search for at least x ms per move. + Search for at least x ms per move. * #### Slow Mover - Lower values will make Stockfish take less time in games, higher values will + Lower values will make Stockfish take less time in games, higher values will make it think longer. * #### nodestime - Tells the engine to use nodes searched instead of wall time to account for + Tells the engine to use nodes searched instead of wall time to account for elapsed time. Useful for engine testing. * #### UCI_Chess960 @@ -79,13 +79,13 @@ Currently, Stockfish has the following UCI options: An option handled by your GUI. * #### SyzygyPath - Path to the folders/directories storing the Syzygy tablebase files. Multiple - directories are to be separated by ";" on Windows and by ":" on Unix-based + Path to the folders/directories storing the Syzygy tablebase files. Multiple + directories are to be separated by ";" on Windows and by ":" on Unix-based operating systems. Do not use spaces around the ";" or ":". - + Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6` - - It is recommended to store .rtbw files on an SSD. There is no loss in storing + + It is recommended to store .rtbw files on an SSD. There is no loss in storing the .rtbz files on a regular HD. It is recommended to verify all md5 checksums of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will lead to engine crashes. @@ -153,7 +153,7 @@ community effort. There are a few ways to help contribute to its growth. ### Donating hardware Improving Stockfish requires a massive amount of testing. You can donate -your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker) +your hardware resources by installing the [Fishtest Worker](https://github.com/glinscott/fishtest/wiki/Running-the-worker) and view the current tests on [Fishtest](http://tests.stockfishchess.org/tests). ### Improving the code @@ -169,7 +169,7 @@ generic rather than being focused on Stockfish's precise implementation. Nevertheless, a helpful resource. * The latest source can always be found on [GitHub](https://github.com/official-stockfish/Stockfish). -Discussions about Stockfish take place in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) +Discussions about Stockfish take place in the [FishCooking](https://groups.google.com/forum/#!forum/fishcooking) group and engine testing is done on [Fishtest](http://tests.stockfishchess.org/tests). If you want to help improve Stockfish, please read this [guideline](https://github.com/glinscott/fishtest/wiki/Creating-my-first-test) first, where the basics of Stockfish development are explained. diff --git a/src/endgame.cpp b/src/endgame.cpp index 7c4efa3c..4f8c2279 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -88,27 +88,28 @@ namespace Endgames { void init() { - add("KPK"); - add("KNNK"); - add("KBNK"); - add("KRKP"); - add("KRKB"); - add("KRKN"); - add("KQKP"); - add("KQKR"); - add("KNNKP"); - - add("KNPK"); - add("KNPKB"); - add("KRPKR"); - add("KRPKB"); - add("KBPKB"); - add("KBPKN"); - add("KBPPKB"); - add("KRPPKRP"); + add("KPK"); + add("KNNK"); + add("KBNK"); + add("KRKP"); + add("KRKB"); + add("KRKN"); + add("KQKP"); + add("KQKR"); + add("KNNKP"); + + add("KNPK"); + add("KNPKB"); + add("KRPKR"); + add("KRPKB"); + add("KBPKB"); + add("KBPKN"); + add("KBPPKB"); + add("KRPPKRP"); } } + /// Mate with KX vs K. This function is used to evaluate positions with /// king and plenty of material vs a lone king. It simply gives the /// attacking side a bonus for driving the defending king towards the edge diff --git a/src/endgame.h b/src/endgame.h index 81afb2e5..d0a5a97e 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -91,7 +91,7 @@ struct Endgame : public EndgameBase { }; -/// The Endgames class stores the pointers to endgame evaluation and scaling +/// The Endgames namespace handles the pointers to endgame evaluation and scaling /// base objects in two std::map. We use polymorphism to invoke the actual /// endgame function by calling its virtual operator(). @@ -99,9 +99,11 @@ namespace Endgames { template using Ptr = std::unique_ptr>; template using Map = std::map>; - + extern std::pair, Map> maps; + void init(); + template Map& map() { return std::get::value>(maps); @@ -119,8 +121,6 @@ namespace Endgames { const EndgameBase* probe(Key key) { return map().count(key) ? map()[key].get() : nullptr; } - - void init(); } #endif // #ifndef ENDGAME_H_INCLUDED diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 0da6ba4d..3ff1460b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -190,10 +190,8 @@ namespace { // color, including x-rays. But diagonal x-rays through pawns are not computed. Bitboard attackedBy2[COLOR_NB]; - // kingRing[color] are the squares adjacent to the king, plus (only for a - // king on its first rank) the squares two ranks in front. For instance, - // if black's king is on g8, kingRing[BLACK] is f8, h8, f7, g7, h7, f6, g6 - // and h6. + // kingRing[color] are the squares adjacent to the king plus some other + // very near squares, depending on king position. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color @@ -802,7 +800,7 @@ namespace { // Early exit if score is high Value v = (mg_value(score) + eg_value(score)) / 2; - if (abs(v) > (LazyThreshold + pos.non_pawn_material() / 64)) + if (abs(v) > LazyThreshold + pos.non_pawn_material() / 64) return pos.side_to_move() == WHITE ? v : -v; // Main evaluation begins here diff --git a/src/main.cpp b/src/main.cpp index 57656f62..f94a322c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,8 +42,8 @@ int main(int argc, char* argv[]) { Bitboards::init(); Position::init(); Bitbases::init(); - Search::init(); Endgames::init(); + Search::init(); Threads.set(Options["Threads"]); Search::clear(); // After threads are up diff --git a/src/pawns.h b/src/pawns.h index ef4b83f8..a34e5e69 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -59,7 +59,6 @@ struct Entry { Square kingSquares[COLOR_NB]; Score kingSafety[COLOR_NB]; int castlingRights[COLOR_NB]; - int pawnsOnSquares[COLOR_NB][COLOR_NB]; // [color][light/dark squares] }; typedef HashTable Table; diff --git a/src/position.cpp b/src/position.cpp index edb40499..14121d47 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -387,7 +387,7 @@ void Position::set_state(StateInfo* si) const { if (type_of(pc) == PAWN) si->pawnKey ^= Zobrist::psq[pc][s]; - else if (type_of(pc) != PAWN && type_of(pc) != KING) + else if (type_of(pc) != KING) si->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc]; } @@ -491,7 +491,7 @@ Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners // Snipers are sliders that attack 's' when a piece and other snipers are removed Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; - Bitboard occupancy = pieces() & ~snipers; + Bitboard occupancy = pieces() ^ snipers; while (snipers) { @@ -1192,10 +1192,10 @@ bool Position::has_game_cycle(int ply) const { if (ply > i) return true; - // For nodes before or at the root, check that the move is a repetition one - // rather than a move to the current position. - // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in the same - // location, so we have to select which square to check. + // For nodes before or at the root, check that the move is a + // repetition rather than a move to the current position. + // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in + // the same location, so we have to select which square to check. if (color_of(piece_on(empty(s1) ? s2 : s1)) != side_to_move()) continue; diff --git a/src/search.cpp b/src/search.cpp index df777b3b..0e10f44f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -149,7 +149,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int(22.9 * std::log(i)); + Reductions[i] = int(22.9 * std::log(i)); } @@ -240,17 +240,13 @@ void MainThread::search() { minScore = std::min(minScore, th->rootMoves[0].score); // Vote according to score and depth, and select the best thread - int64_t bestVote = 0; for (Thread* th : Threads) { votes[th->rootMoves[0].pv[0]] += - (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); + (th->rootMoves[0].score - minScore + 14) * int(th->completedDepth); - if (votes[th->rootMoves[0].pv[0]] > bestVote) - { - bestVote = votes[th->rootMoves[0].pv[0]]; + if (votes[th->rootMoves[0].pv[0]] > votes[bestThread->rootMoves[0].pv[0]]) bestThread = th; - } } } @@ -538,13 +534,13 @@ namespace { bool ttHit, ttPv, inCheck, givesCheck, improving; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; - int moveCount, captureCount, quietCount; + int moveCount, captureCount, quietCount, singularLMR; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); inCheck = pos.checkers(); Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = ss->moveCount = 0; + moveCount = captureCount = quietCount = singularLMR = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; @@ -589,10 +585,10 @@ namespace { // starts with statScore = 0. Later grandchildren start with the last calculated // statScore of the previous grandchild. This influences the reduction rules in // LMR which are based on the statScore of parent position. - if (rootNode) - (ss + 4)->statScore = 0; - else - (ss + 2)->statScore = 0; + if (rootNode) + (ss + 4)->statScore = 0; + else + (ss + 2)->statScore = 0; // Step 4. Transposition table lookup. We don't want the score of a partial // search to overwrite a previous full search TT value, so we use a different @@ -850,7 +846,6 @@ moves_loop: // When in check, search starts from here value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); - int singularExtensionLMRmultiplier = 0; // Step 12. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. @@ -907,12 +902,13 @@ moves_loop: // When in check, search starts from here ss->excludedMove = MOVE_NONE; if (value < singularBeta) - { + { extension = ONE_PLY; - singularExtensionLMRmultiplier++; + singularLMR++; + if (value < singularBeta - std::min(3 * depth / ONE_PLY, 39)) - singularExtensionLMRmultiplier++; - } + singularLMR++; + } // Multi-cut pruning // Our ttMove is assumed to fail high, and now we failed high also on a reduced @@ -1023,8 +1019,9 @@ moves_loop: // When in check, search starts from here // Decrease reduction if opponent's move count is high (~10 Elo) if ((ss-1)->moveCount > 15) r -= ONE_PLY; + // Decrease reduction if move has been singularly extended - r -= singularExtensionLMRmultiplier * ONE_PLY; + r -= singularLMR * ONE_PLY; if (!captureOrPromotion) { @@ -1060,7 +1057,7 @@ moves_loop: // When in check, search starts from here r -= ss->statScore / 20000 * ONE_PLY; } - Depth d = std::max(newDepth - std::max(r, DEPTH_ZERO), ONE_PLY); + Depth d = clamp(newDepth - r, ONE_PLY, newDepth); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); @@ -1476,7 +1473,7 @@ moves_loop: // When in check, search starts from here void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus) { - CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; + CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; Piece moved_piece = pos.moved_piece(move); PieceType captured = type_of(pos.piece_on(to_sq(move))); @@ -1715,10 +1712,4 @@ void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW) Cardinality = 0; } - else - { - // Assign the same rank to all moves - for (auto& m : rootMoves) - m.tbRank = 0; - } } diff --git a/src/search.h b/src/search.h index 92e124fc..24c58d30 100644 --- a/src/search.h +++ b/src/search.h @@ -69,7 +69,7 @@ struct RootMove { Value score = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE; int selDepth = 0; - int tbRank; + int tbRank = 0; Value tbScore; std::vector pv; }; diff --git a/src/tt.cpp b/src/tt.cpp index b8fe7567..6121b3ad 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -43,15 +43,16 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) // Overwrite less valuable entries if ( (k >> 48) != key16 - || d / ONE_PLY + 10 > depth8 + ||(d - DEPTH_OFFSET) / ONE_PLY > depth8 - 4 || b == BOUND_EXACT) { + assert((d - DEPTH_OFFSET) / ONE_PLY >= 0); + key16 = (uint16_t)(k >> 48); value16 = (int16_t)v; eval16 = (int16_t)ev; genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b); - assert((d - DEPTH_NONE) / ONE_PLY >= 0); - depth8 = (uint8_t)((d - DEPTH_NONE) / ONE_PLY); + depth8 = (uint8_t)((d - DEPTH_OFFSET) / ONE_PLY); } } diff --git a/src/tt.h b/src/tt.h index 3608b77c..3a5ba5da 100644 --- a/src/tt.h +++ b/src/tt.h @@ -40,7 +40,7 @@ struct TTEntry { Move move() const { return (Move )move16; } Value value() const { return (Value)value16; } Value eval() const { return (Value)eval16; } - Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_NONE; } + Depth depth() const { return (Depth)(depth8 * int(ONE_PLY)) + DEPTH_OFFSET; } bool is_pv() const { return (bool)(genBound8 & 0x4); } Bound bound() const { return (Bound)(genBound8 & 0x3); } void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev); diff --git a/src/types.h b/src/types.h index b0758f43..bee6538f 100644 --- a/src/types.h +++ b/src/types.h @@ -213,8 +213,9 @@ enum Depth : int { DEPTH_QS_NO_CHECKS = -1 * ONE_PLY, DEPTH_QS_RECAPTURES = -5 * ONE_PLY, - DEPTH_NONE = -6 * ONE_PLY, - DEPTH_MAX = MAX_PLY * ONE_PLY + DEPTH_NONE = -6 * ONE_PLY, + DEPTH_OFFSET = DEPTH_NONE, + DEPTH_MAX = MAX_PLY * ONE_PLY }; static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); -- 2.39.2