- /* 
-     Texel - A UCI chess engine. 
-     Copyright (C) 2012-2014  Peter Ă–sterlund, peterosterlund2@gmail.com 
-   
-     This program is free software: you can redistribute it and/or modify 
-     it under the terms of the GNU General Public License as published by 
-     the Free Software Foundation, either version 3 of the License, or 
-     (at your option) any later version. 
-   
-     This program is distributed in the hope that it will be useful, 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
-     GNU General Public License for more details. 
-   
-     You should have received a copy of the GNU General Public License 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
- */ 
-   
- /* 
-  * search.hpp 
-  * 
-  *  Created on: Feb 25, 2012 
-  *      Author: petero 
-  */ 
-   
- #ifndef SEARCH_HPP_ 
- #define SEARCH_HPP_ 
-   
- #include "constants.hpp" 
- #include "position.hpp" 
- #include "killerTable.hpp" 
- #include "history.hpp" 
- #include "transpositionTable.hpp" 
- #include "evaluate.hpp" 
- #include "treeLogger.hpp" 
- #include "moveGen.hpp" 
- #include "searchUtil.hpp" 
- #include "parallel.hpp" 
- #include "util/histogram.hpp" 
-   
- #include <limits> 
- #include <memory> 
-   
-   
- class SearchTest; 
- class ChessTool; 
- class PosGenerator; 
-   
- /** Implements the nega-scout search algorithm. */ 
- class Search { 
-     friend class SearchTest; 
-     friend class ChessTool; 
-     friend class PosGenerator; 
- public: 
-     /** Help tables used by the search. */ 
-     struct SearchTables { 
-         SearchTables(TranspositionTable& tt0, KillerTable& kt0, History& ht0, 
-                      Evaluate::EvalHashTables& et0); 
-         TranspositionTable& tt; 
-         KillerTable& kt; 
-         History& ht; 
-         Evaluate::EvalHashTables& et; 
-     }; 
-   
-     /** Constructor. */ 
-     Search(const Position& pos, const std::vector<U64>& posHashList, 
-            int posHashListSize, SearchTables& st, 
-            ParallelData& pd, const std::shared_ptr<SplitPoint>& rootSp, 
-            TreeLogger& logFile); 
-   
-     Search(const Search& other) = delete; 
-     Search& operator=(const Search& other) = delete; 
-   
-     /** Interface for reporting search information during search. */ 
-     class Listener { 
-     public: 
-         virtual void notifyDepth(int depth) = 0; 
-         virtual void notifyCurrMove(const Move& m, int moveNr) = 0; 
-         virtual void notifyPV(int depth, int score, int time, U64 nodes, int nps, 
-                               bool isMate, bool upperBound, bool lowerBound, 
-                               const std::vector<Move>& pv, int multiPVIndex, 
-                               U64 tbHits) = 0; 
-         virtual void notifyStats(U64 nodes, int nps, U64 tbHits, int time) = 0; 
-     }; 
-   
-     void setListener(const std::shared_ptr<Listener>& listener); 
-   
-     /** Exception thrown to stop the search. */ 
-     class StopSearch : public std::exception { 
-     }; 
-   
-     class StopHandler { 
-     public: 
-         virtual bool shouldStop() = 0; 
-     }; 
-   
-     void setStopHandler(const std::shared_ptr<StopHandler>& stopHandler); 
-   
-     /** Set which thread is owning this Search object. */ 
-     void setThreadNo(int tNo); 
-   
-     void timeLimit(int minTimeLimit, int maxTimeLimit); 
-   
-     void setStrength(int strength, U64 randomSeed); 
-   
-     /** Set minimum depth for TB probes. */ 
-     void setMinProbeDepth(int depth); 
-   
-     Move iterativeDeepening(const MoveList& scMovesIn, 
-                             int maxDepth, U64 initialMaxNodes, bool verbose, 
-                             int maxPV = 1, bool onlyExact = false, 
-                             int minProbeDepth = 0); 
-   
-     /** 
-      * Main recursive search algorithm. 
-      * @return Score for the side to make a move, in position given by "pos". 
-      */ 
-     template <bool smp, bool tb> 
-     int negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare, 
-                   const bool inCheck); 
-     int negaScout(bool smp, bool tb, 
-                   int alpha, int beta, int ply, int depth, int recaptureSquare, 
-                   const bool inCheck); 
-     int negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare, 
-                   const bool inCheck); 
-   
-     /** Compute extension depth for a move. */ 
-     int getMoveExtend(const Move& m, int recaptureSquare); 
-   
-     static bool canClaimDraw50(const Position& pos); 
-   
-     static bool canClaimDrawRep(const Position& pos, const std::vector<U64>& posHashList, 
-                                 int posHashListSize, int posHashFirstNew); 
-   
-     /** 
-      * Compute scores for each move in a move list, using SEE, killer and history information. 
-      * @param moves  List of moves to score. 
-      */ 
-     void scoreMoveList(MoveList& moves, int ply, int startIdx = 0); 
-   
-     /** Set search tree information for a given ply. */ 
-     void setSearchTreeInfo(int ply, const SearchTreeInfo& sti, 
-                            const Move& currMove, int currMoveNo, int lmr, 
-                            U64 rootNodeIdx); 
-   
-     /** Get total number of nodes searched by this thread. */ 
-     S64 getTotalNodesThisThread() const; 
-   
-     /** Get number of TB hits for this thread. */ 
-     S64 getTbHitsThisThread() const; 
-   
- private: 
-     void init(const Position& pos0, const std::vector<U64>& posHashList0, 
-               int posHashListSize0); 
-   
-     /** Information used for move ordering at root and for PV reporting. */ 
-     struct MoveInfo { 
-         Move move; 
-         U64 nodes; 
-         int depth, alpha, beta; 
-         std::vector<Move> pv; 
-         MoveInfo(const Move& m, int n) 
-             : move(m), nodes(n), depth(0), alpha(0), beta(0) {} 
-   
-         int score() const { return move.score(); } 
-   
-         struct SortByScore { 
-             bool operator()(const MoveInfo& mi1, const MoveInfo& mi2) const { 
-                 return mi1.move.score() > mi2.move.score(); 
-             } 
-         }; 
-         struct SortByNodes { 
-             bool operator()(const MoveInfo& mi1, const MoveInfo& mi2) { 
-                 return mi1.nodes > mi2.nodes; 
-             } 
-         }; 
-     }; 
-   
-     /** Store depth, alpha, beta, score and pv in scMoves[mi]. */ 
-     void storeSearchResult(std::vector<MoveInfo>& scMoves, int mi, int depth, 
-                            int alpha, int beta, int score); 
-   
-     /** Report PV information to listener. */ 
-     void notifyPV(const std::vector<MoveInfo>& moveInfo, int mi, int maxPV); 
-     void notifyPV(const MoveInfo& info, int multiPVIndex); 
-   
-     /** Report search statistics to listener. */ 
-     void notifyStats(); 
-   
-     /** Get total number of nodes searched by all threads. */ 
-     S64 getTotalNodes() const; 
-   
-     /** Get total number of TB hits for all threads. */ 
-     S64 getTbHits() const; 
-   
-     /** Determine which root moves to search, taking low strength and 
-      *  missing TB files into account. */ 
-     void getRootMoves(const MoveList& rootMovesIn, 
-                       std::vector<MoveInfo>& rootMovesOut, 
-                       int maxDepth); 
-   
-     /** Return true if move should be skipped in order to make engine play weaker. */ 
-     bool weakPlaySkipMove(const Position& pos, const Move& m, int ply) const; 
-   
-     static bool passedPawnPush(const Position& pos, const Move& m); 
-   
-     /** Quiescence search. Only non-losing captures are searched. */ 
-     int quiesce(int alpha, int beta, int ply, int depth, const bool inCheck); 
-   
-     /** 
-      * Static exchange evaluation function. 
-      * @return SEE score for m. Positive value is good for the side that makes the first move. 
-      */ 
-     int SEE(const Move& m); 
-   
-     /** Return >0, 0, <0, depending on the sign of SEE(m). */ 
-     int signSEE(const Move& m); 
-   
-     /** Return true if SEE(m) < 0. */ 
-     bool negSEE(const Move& m); 
-   
-     /** Score move list according to most valuable victim / least valuable attacker. */ 
-     void scoreMoveListMvvLva(MoveList& moves) const; 
-   
-     /** Find move with highest score and move it to the front of the list. */ 
-     static void selectBest(MoveList& moves, int startIdx); 
-   
-     /** If hashMove exists in the move list, move the hash move to the front of the list. */ 
-     static bool selectHashMove(MoveList& moves, const Move& hashMove); 
-   
-     void initNodeStats(); 
-   
-     class DefaultStopHandler : public StopHandler { 
-     public: 
-         DefaultStopHandler(Search& sc0) : sc(sc0) { } 
-         bool shouldStop() { return sc.shouldStop(); } 
-     private: 
-         Search& sc; 
-     }; 
-   
-     /** Return true if the search should be stopped immediately. */ 
-     bool shouldStop(); 
-   
-   
-   
-     Position pos; 
-     Evaluate eval; 
-     KillerTable& kt; 
-     History& ht; 
-     std::vector<U64> posHashList; // List of hashes for previous positions up to the last "zeroing" move. 
-     int posHashListSize;          // Number of used entries in posHashList 
-     int posHashFirstNew;          // First entry in posHashList that has not been played OTB. 
-     TranspositionTable& tt; 
-     ParallelData& pd; 
-     std::vector<std::shared_ptr<SplitPoint>> spVec; 
-     std::vector<std::shared_ptr<SplitPoint>> pending; 
-     int threadNo; 
-     bool mainNumaNode; // True if this thread runs on the NUMA node holding the transposition table 
-     TreeLogger& logFile; 
-   
-     std::shared_ptr<Listener> listener; 
-     std::shared_ptr<StopHandler> stopHandler; 
-     Move emptyMove; 
-   
-     static const int MAX_SEARCH_DEPTH = 100; 
-     SearchTreeInfo searchTreeInfo[MAX_SEARCH_DEPTH * 2]; 
-   
-     // Time management 
-     S64 tStart;                // Time when search started 
-     RelaxedShared<S64> minTimeMillis; // Minimum recommended thinking time 
-     RelaxedShared<S64> maxTimeMillis; // Maximum allowed thinking time 
-     bool searchNeedMoreTime;   // True if negaScout should use up to maxTimeMillis time. 
-     S64 maxNodes;              // Maximum number of nodes to search (approximately) 
-     int minProbeDepth;         // Minimum depth to probe endgame tablebases. 
-     int nodesToGo;             // Number of nodes until next time check 
-     RelaxedShared<int> nodesBetweenTimeCheck; // How often to check remaining time 
-   
-     // Reduced strength variables 
-     int strength;              // Strength (0-1000) 
-     bool weak;                 // True if strength < 1000 
-     U64 randomSeed; 
-   
-     // Search statistics stuff 
-     Histogram<0,20> nodesByPly, nodesByDepth; 
-     S64 totalNodes; 
-     S64 tbHits; 
-     S64 tLastStats;        // Time when notifyStats was last called 
-     bool verbose; 
-   
-     int q0Eval; // Static eval score at first level of quiescence search 
- }; 
-   
- inline 
- Search::SearchTables::SearchTables(TranspositionTable& tt0, KillerTable& kt0, History& ht0, 
-                                    Evaluate::EvalHashTables& et0) 
-     : tt(tt0), kt(kt0), ht(ht0), et(et0) { 
- } 
-   
- inline void 
- Search::setListener(const std::shared_ptr<Listener>& listener) { 
-     this->listener = listener; 
- } 
-   
- inline void 
- Search::setStopHandler(const std::shared_ptr<StopHandler>& stopHandler) { 
-     this->stopHandler = stopHandler; 
- } 
-   
- inline bool 
- Search::canClaimDrawRep(const Position& pos, const std::vector<U64>& posHashList, 
-                        int posHashListSize, int posHashFirstNew) { 
-     int reps = 0; 
-     int stop = std::max(0, posHashListSize - pos.getHalfMoveClock()); 
-     for (int i = posHashListSize - 4; i >= stop; i -= 2) { 
-         if (pos.zobristHash() == posHashList[i]) { 
-             reps++; 
-             if ((i >= posHashFirstNew) || (reps >= 2)) 
-                 return true; 
-         } 
-     } 
-     return false; 
- } 
-   
- inline bool 
- Search::passedPawnPush(const Position& pos, const Move& m) { 
-     int p = pos.getPiece(m.from()); 
-     if (pos.isWhiteMove()) { 
-         if (p != Piece::WPAWN) 
-             return false; 
-         if ((BitBoard::wPawnBlockerMask[m.to()] & pos.pieceTypeBB(Piece::BPAWN)) != 0) 
-             return false; 
-         return m.to() >= 40; 
-     } else { 
-         if (p != Piece::BPAWN) 
-             return false; 
-         if ((BitBoard::bPawnBlockerMask[m.to()] & pos.pieceTypeBB(Piece::WPAWN)) != 0) 
-             return false; 
-         return m.to() <= 23; 
-     } 
- } 
-   
- inline int 
- Search::signSEE(const Move& m) { 
-     int p0 = ::pieceValue[pos.getPiece(m.from())]; 
-     int p1 = ::pieceValue[pos.getPiece(m.to())]; 
-     if (p0 < p1) 
-         return 1; 
-     return SEE(m); 
- } 
-   
- inline bool 
- Search::negSEE(const Move& m) { 
-     int p0 = ::pieceValue[pos.getPiece(m.from())]; 
-     int p1 = ::pieceValue[pos.getPiece(m.to())]; 
-     if (p1 >= p0) 
-         return false; 
-     return SEE(m) < 0; 
- } 
-   
- inline void 
- Search::scoreMoveListMvvLva(MoveList& moves) const { 
-     for (int i = 0; i < moves.size; i++) { 
-         Move& m = moves[i]; 
-         int v = pos.getPiece(m.to()); 
-         int a = pos.getPiece(m.from()); 
-         m.setScore(Evaluate::pieceValueOrder[v] * 8 - Evaluate::pieceValueOrder[a]); 
-     } 
- } 
-   
- inline void 
- Search::selectBest(MoveList& moves, int startIdx) { 
-     int bestIdx = startIdx; 
-     int bestScore = moves[bestIdx].score(); 
-     for (int i = startIdx + 1; i < moves.size; i++) { 
-         int sc = moves[i].score(); 
-         if (sc > bestScore) { 
-             bestIdx = i; 
-             bestScore = sc; 
-         } 
-     } 
-     std::swap(moves[bestIdx], moves[startIdx]); 
- } 
-   
- inline void 
- Search::setSearchTreeInfo(int ply, const SearchTreeInfo& sti, const Move& currMove, 
-                           int currMoveNo, int lmr, U64 rootNodeIdx) { 
-     searchTreeInfo[ply] = sti; 
-     searchTreeInfo[ply].currentMove = currMove; 
-     searchTreeInfo[ply].currentMoveNo = currMoveNo; 
-     searchTreeInfo[ply].lmr = lmr; 
-     searchTreeInfo[ply].nodeIdx = rootNodeIdx; 
- } 
-   
- inline int 
- Search::negaScout(bool smp, bool tb, 
-                   int alpha, int beta, int ply, int depth, int recaptureSquare, 
-                   const bool inCheck) { 
-     using namespace SearchConst; 
-     int minDepth = pd.wq.getMinSplitDepth() * plyScale; 
-     if (threadNo == 0) 
-         minDepth = (minDepth + MIN_SMP_DEPTH * plyScale) / 2; 
-     if (smp && (depth >= minDepth) && 
-                ((int)spVec.size() < MAX_SP_PER_THREAD)) { 
-         bool tb2 = tb && depth >= minProbeDepth; 
-         if (tb2) 
-             return negaScout<true,true>(alpha, beta, ply, depth, recaptureSquare, inCheck); 
-         else 
-             return negaScout<true,false>(alpha, beta, ply, depth, recaptureSquare, inCheck); 
-     } else { 
-         bool tb2 = tb && depth >= minProbeDepth; 
-         if (tb2) 
-             return negaScout<false,true>(alpha, beta, ply, depth, recaptureSquare, inCheck); 
-         else 
-             return negaScout<false,false>(alpha, beta, ply, depth, recaptureSquare, inCheck); 
-     } 
- } 
-   
- inline int 
- Search::negaScout(int alpha, int beta, int ply, int depth, int recaptureSquare, 
-                   const bool inCheck) { 
-     return negaScout<false,false>(alpha, beta, ply, depth, recaptureSquare, inCheck); 
- } 
-   
- inline bool 
- Search::canClaimDraw50(const Position& pos) { 
-     return (pos.getHalfMoveClock() >= 100); 
- } 
-   
- inline S64 
- Search::getTotalNodes() const { 
-     return totalNodes + pd.getNumSearchedNodes(); 
- } 
-   
- inline S64 
- Search::getTotalNodesThisThread() const { 
-     return totalNodes; 
- } 
-   
- inline S64 
- Search::getTbHits() const { 
-     return tbHits + pd.getTbHits(); 
- } 
-   
- inline S64 
- Search::getTbHitsThisThread() const { 
-     return tbHits; 
- } 
-   
- inline void 
- Search::setMinProbeDepth(int depth) { 
-     minProbeDepth = depth * SearchConst::plyScale; 
- } 
-   
- #endif /* SEARCH_HPP_ */ 
-