LCOV - code coverage report
Current view: top level - Source - cli.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 64.2 % 288 185
Test Date: 2026-03-02 16:42:41 Functions: 66.7 % 6 4

            Line data    Source code
       1              : #include "cli.hpp"
       2              : 
       3              : #include "com.hpp"
       4              : #include "dynamicConfig.hpp"
       5              : #include "evalDef.hpp"
       6              : #include "logging.hpp"
       7              : #include "material.hpp"
       8              : #include "moveApply.hpp"
       9              : #include "moveGen.hpp"
      10              : #include "option.hpp"
      11              : #include "position.hpp"
      12              : #include "searcher.hpp"
      13              : #include "tables.hpp"
      14              : #include "timeMan.hpp"
      15              : #include "tools.hpp"
      16              : #include "transposition.hpp"
      17              : #include "uci.hpp"
      18              : #include "xboard.hpp"
      19              : 
      20              : // see cli_perft.cpp
      21              : [[nodiscard]] bool perft_test(const std::string& fen, DepthType d, uint64_t expected);
      22              : Counter perft(const Position& p, DepthType depth, PerftAccumulator& acc);
      23              : 
      24              : // see cli_selfplay.cpp
      25              : void selfPlay(DepthType depth, uint64_t & nbPos);
      26              : 
      27              : // see cli_SEETest.cpp
      28              : bool TestSEE();
      29              : 
      30          201 : void analyze(const Position& p, DepthType depth, bool openBenchOutput = false) {
      31              :    static double  benchms    = 0;
      32              :    static Counter benchNodes = 0;
      33              : 
      34          201 :    const int oldOutLvl = DynamicConfig::minOutputLevel;
      35          201 :    if (openBenchOutput) { DynamicConfig::minOutputLevel = Logging::logOff; }
      36              : 
      37          201 :    TimeMan::isDynamic                   = false;
      38          201 :    TimeMan::nbMoveInTC                  = -1;
      39          201 :    TimeMan::msecPerMove                 = INFINITETIME;
      40          201 :    TimeMan::msecInTC                    = -1;
      41          201 :    TimeMan::msecInc                     = -1;
      42          201 :    TimeMan::msecUntilNextTC             = -1;
      43          201 :    ThreadPool::instance().currentMoveMs = TimeMan::getNextMSecPerMove(p);
      44              : 
      45          201 :    ThreadData d;
      46              : #ifdef WITH_ASYNC_ANALYZE
      47          201 :    COM::depth = depth;
      48          201 :    const std::string fen = GetFEN(p);
      49          201 :    const bool b = readFEN(fen, COM::position, true, true);
      50          201 :    if (!b) Logging::LogIt(Logging::logFatal) << "Illegal FEN " << fen;
      51          201 :    COM::thinkAsync(COM::st_searching);
      52         4046 :    while(ThreadPool::instance().main().searching()){
      53              :       using namespace std::chrono_literals;
      54         3845 :       std::this_thread::sleep_for(10ms);
      55              :    }
      56              : #else
      57              :    d.p     = p;
      58              :    d.depth = depth;
      59              :    ThreadPool::instance().distributeData(d);
      60              :    ThreadPool::instance().main().stopFlag = false;
      61              :    ThreadPool::instance().main().searchDriver(false);
      62              : #endif
      63          201 :    d = ThreadPool::instance().main().getData();
      64          804 :    Logging::LogIt(Logging::logInfo) << "Best move is " << ToString(d.best) << " " << static_cast<int>(d.depth) << " " << d.score << " pv : " << ToString(d.pv);
      65              : 
      66          201 :    if (openBenchOutput) {
      67            5 :       Logging::LogIt(Logging::logInfo) << "Next two lines are for OpenBench";
      68            5 :       const TimeType ms = getTimeDiff(ThreadPool::instance().main().startTime);
      69              :       const Counter nodeCount =
      70            5 :           ThreadPool::instance().main().stats.counters[Stats::sid_nodes] + ThreadPool::instance().main().stats.counters[Stats::sid_qnodes];
      71            5 :       benchNodes += nodeCount;
      72            5 :       benchms += static_cast<decltype(benchms)>(ms) / 1000.;
      73            5 :       DynamicConfig::minOutputLevel = oldOutLvl;
      74            5 :       std::cerr << "NODES " << benchNodes << std::endl;
      75            5 :       std::cerr << "NPS " << static_cast<int>(static_cast<decltype(benchms)>(benchNodes) / benchms) << std::endl;
      76              :    }
      77          201 : }
      78              : 
      79              : // This struct is dedicated to display beta cut statistics in benchmark
      80              : struct BetaCutStat{
      81              :    Counter betaCuts   = 0ull;
      82              :    Counter betaCutsTT = 0ull;
      83              :    Counter betaCutsGC = 0ull;
      84              :    Counter betaCutsP  = 0ull;
      85              :    Counter betaCutsK1 = 0ull;
      86              :    Counter betaCutsK2 = 0ull;
      87              :    Counter betaCutsK3 = 0ull;
      88              :    Counter betaCutsK4 = 0ull;
      89              :    Counter betaCutsC  = 0ull;
      90              :    Counter betaCutsQ  = 0ull;
      91              :    Counter betaCutsBC = 0ull;
      92              : 
      93            5 :    void update(const Stats& stats){
      94            5 :       betaCuts   += stats.counters[Stats::sid_beta] + stats.counters[Stats::sid_ttbeta];
      95            5 :       betaCutsTT += stats.counters[Stats::sid_ttbeta];
      96            5 :       betaCutsGC += stats.counters[Stats::sid_beta_gc];
      97            5 :       betaCutsP  += stats.counters[Stats::sid_beta_p];
      98            5 :       betaCutsK1 += stats.counters[Stats::sid_beta_k1];
      99            5 :       betaCutsK2 += stats.counters[Stats::sid_beta_k2];
     100            5 :       betaCutsK3 += stats.counters[Stats::sid_beta_k3];
     101            5 :       betaCutsK4 += stats.counters[Stats::sid_beta_k4];
     102            5 :       betaCutsC  += stats.counters[Stats::sid_beta_c];
     103            5 :       betaCutsQ  += stats.counters[Stats::sid_beta_q];
     104            5 :       betaCutsBC += stats.counters[Stats::sid_beta_bc];
     105            5 :    }
     106              : 
     107              :    float percent(const Counter c) const { return c*100.f/betaCuts; }
     108              :    
     109              :    void show() const {
     110              : #ifdef WITH_BETACUTSTATS
     111              :       Logging::LogIt(Logging::logInfo) << "betaCuts   " << betaCuts;
     112              :       Logging::LogIt(Logging::logInfo) << "betaCutsTT " << betaCutsTT << " (" << percent(betaCutsTT) << "%)";
     113              :       Logging::LogIt(Logging::logInfo) << "betaCutsGC " << betaCutsGC << " (" << percent(betaCutsGC) << "%)";
     114              :       Logging::LogIt(Logging::logInfo) << "betaCutsP  " << betaCutsP  << " (" << percent(betaCutsP)  << "%)";
     115              :       Logging::LogIt(Logging::logInfo) << "betaCutsK1 " << betaCutsK1 << " (" << percent(betaCutsK1) << "%)";
     116              :       Logging::LogIt(Logging::logInfo) << "betaCutsK2 " << betaCutsK2 << " (" << percent(betaCutsK2) << "%)";
     117              :       Logging::LogIt(Logging::logInfo) << "betaCutsK3 " << betaCutsK3 << " (" << percent(betaCutsK3) << "%)";
     118              :       Logging::LogIt(Logging::logInfo) << "betaCutsK4 " << betaCutsK4 << " (" << percent(betaCutsK4) << "%)";
     119              :       Logging::LogIt(Logging::logInfo) << "betaCutsC  " << betaCutsC  << " (" << percent(betaCutsC)  << "%)";
     120              :       Logging::LogIt(Logging::logInfo) << "betaCutsQ  " << betaCutsQ  << " (" << percent(betaCutsQ)  << "%)";
     121              :       Logging::LogIt(Logging::logInfo) << "betaCutsBC " << betaCutsBC << " (" << percent(betaCutsBC) << "%)";
     122              : #endif
     123              :    }
     124              : };
     125              : 
     126            1 : bool bench(DepthType depth) {
     127            1 :    RootPosition p;
     128              : #ifdef WITH_NNUE
     129            1 :    NNUEEvaluator evaluator;
     130              :    p.associateEvaluator(evaluator);
     131              : #endif
     132              : 
     133            1 :    BetaCutStat betaStats;
     134              : 
     135            1 :    auto pos = {startPosition, fine70, shirov, shirov2, mate4};
     136              : 
     137            6 :    for(const auto & fen : pos){
     138            5 :       readFEN(std::string{fen}, p);
     139            5 :       analyze(p, depth, true);
     140            5 :       betaStats.update(ThreadPool::instance().main().stats);
     141              :    }
     142              : 
     143              :    betaStats.show();
     144              :    
     145            1 :    return true;
     146            1 : }
     147              : 
     148            0 : bool spsaInputs(){
     149            1 :    Options::displayOptionsSPSA();
     150            0 :    return true;
     151              : }
     152              : 
     153            0 : bool benchBig(DepthType depth){
     154              :    // use here same postitions set as Ethereal or Berserk
     155              :    static const std::vector<std::string> positions = {
     156              :       "r3k2r/2pb1ppp/2pp1q2/p7/1nP1B3/1P2P3/P2N1PPP/R2QK2R w KQkq a6 0 14",
     157              :       "4rrk1/2p1b1p1/p1p3q1/4p3/2P2n1p/1P1NR2P/PB3PP1/3R1QK1 b - - 2 24",
     158              :       "r3qbrk/6p1/2b2pPp/p3pP1Q/PpPpP2P/3P1B2/2PB3K/R5R1 w - - 16 42",
     159              :       "6k1/1R3p2/6p1/2Bp3p/3P2q1/P7/1P2rQ1K/5R2 b - - 4 44",
     160              :       "8/8/1p2k1p1/3p3p/1p1P1P1P/1P2PK2/8/8 w - - 3 54",
     161              :       "7r/2p3k1/1p1p1qp1/1P1Bp3/p1P2r1P/P7/4R3/Q4RK1 w - - 0 36",
     162              :       "r1bq1rk1/pp2b1pp/n1pp1n2/3P1p2/2P1p3/2N1P2N/PP2BPPP/R1BQ1RK1 b - - 2 10",
     163              :       "3r3k/2r4p/1p1b3q/p4P2/P2Pp3/1B2P3/3BQ1RP/6K1 w - - 3 87",
     164              :       "2r4r/1p4k1/1Pnp4/3Qb1pq/8/4BpPp/5P2/2RR1BK1 w - - 0 42",
     165              :       "4q1bk/6b1/7p/p1p4p/PNPpP2P/KN4P1/3Q4/4R3 b - - 0 37",
     166              :       "2q3r1/1r2pk2/pp3pp1/2pP3p/P1Pb1BbP/1P4Q1/R3NPP1/4R1K1 w - - 2 34",
     167              :       "1r2r2k/1b4q1/pp5p/2pPp1p1/P3Pn2/1P1B1Q1P/2R3P1/4BR1K b - - 1 37",
     168              :       "r3kbbr/pp1n1p1P/3ppnp1/q5N1/1P1pP3/P1N1B3/2P1QP2/R3KB1R b KQkq b3 0 17",
     169              :       "8/6pk/2b1Rp2/3r4/1R1B2PP/P5K1/8/2r5 b - - 16 42",
     170              :       "1r4k1/4ppb1/2n1b1qp/pB4p1/1n1BP1P1/7P/2PNQPK1/3RN3 w - - 8 29",
     171              :       "8/p2B4/PkP5/4p1pK/4Pb1p/5P2/8/8 w - - 29 68",
     172              :       "3r4/ppq1ppkp/4bnp1/2pN4/2P1P3/1P4P1/PQ3PBP/R4K2 b - - 2 20",
     173              :       "5rr1/4n2k/4q2P/P1P2n2/3B1p2/4pP2/2N1P3/1RR1K2Q w - - 1 49",
     174              :       "1r5k/2pq2p1/3p3p/p1pP4/4QP2/PP1R3P/6PK/8 w - - 1 51",
     175              :       "q5k1/5ppp/1r3bn1/1B6/P1N2P2/BQ2P1P1/5K1P/8 b - - 2 34",
     176              :       "r1b2k1r/5n2/p4q2/1ppn1Pp1/3pp1p1/NP2P3/P1PPBK2/1RQN2R1 w - - 0 22",
     177              :       "r1bqk2r/pppp1ppp/5n2/4b3/4P3/P1N5/1PP2PPP/R1BQKB1R w KQkq - 0 5",
     178              :       "r1bqr1k1/pp1p1ppp/2p5/8/3N1Q2/P2BB3/1PP2PPP/R3K2n b Q - 1 12",
     179              :       "r1bq2k1/p4r1p/1pp2pp1/3p4/1P1B3Q/P2B1N2/2P3PP/4R1K1 b - - 2 19",
     180              :       "r4qk1/6r1/1p4p1/2ppBbN1/1p5Q/P7/2P3PP/5RK1 w - - 2 25",
     181              :       "r7/6k1/1p6/2pp1p2/7Q/8/p1P2K1P/8 w - - 0 32",
     182              :       "r3k2r/ppp1pp1p/2nqb1pn/3p4/4P3/2PP4/PP1NBPPP/R2QK1NR w KQkq - 1 5",
     183              :       "3r1rk1/1pp1pn1p/p1n1q1p1/3p4/Q3P3/2P5/PP1NBPPP/4RRK1 w - - 0 12",
     184              :       "5rk1/1pp1pn1p/p3Brp1/8/1n6/5N2/PP3PPP/2R2RK1 w - - 2 20",
     185              :       "8/1p2pk1p/p1p1r1p1/3n4/8/5R2/PP3PPP/4R1K1 b - - 3 27",
     186              :       "8/4pk2/1p1r2p1/p1p4p/Pn5P/3R4/1P3PP1/4RK2 w - - 1 33",
     187              :       "8/5k2/1pnrp1p1/p1p4p/P6P/4R1PK/1P3P2/4R3 b - - 1 38",
     188              :       "8/8/1p1kp1p1/p1pr1n1p/P6P/1R4P1/1P3PK1/1R6 b - - 15 45",
     189              :       "8/8/1p1k2p1/p1prp2p/P2n3P/6P1/1P1R1PK1/4R3 b - - 5 49",
     190              :       "8/8/1p4p1/p1p2k1p/P2npP1P/4K1P1/1P6/3R4 w - - 6 54",
     191              :       "8/8/1p4p1/p1p2k1p/P2n1P1P/4K1P1/1P6/6R1 b - - 6 59",
     192              :       "8/5k2/1p4p1/p1pK3p/P2n1P1P/6P1/1P6/4R3 b - - 14 63",
     193              :       "8/1R6/1p1K1kp1/p6p/P1p2P1P/6P1/1Pn5/8 w - - 0 67",
     194              :       "1rb1rn1k/p3q1bp/2p3p1/2p1p3/2P1P2N/PP1RQNP1/1B3P2/4R1K1 b - - 4 23",
     195              :       "4rrk1/pp1n1pp1/q5p1/P1pP4/2n3P1/7P/1P3PB1/R1BQ1RK1 w - - 3 22",
     196              :       "r2qr1k1/pb1nbppp/1pn1p3/2ppP3/3P4/2PB1NN1/PP3PPP/R1BQR1K1 w - - 4 12",
     197              :       "2r2k2/8/4P1R1/1p6/8/P4K1N/7b/2B5 b - - 0 55",
     198              :       "6k1/5pp1/8/2bKP2P/2P5/p4PNb/B7/8 b - - 1 44",
     199              :       "2rqr1k1/1p3p1p/p2p2p1/P1nPb3/2B1P3/5P2/1PQ2NPP/R1R4K w - - 3 25",
     200              :       "r1b2rk1/p1q1ppbp/6p1/2Q5/8/4BP2/PPP3PP/2KR1B1R b - - 2 14",
     201              :       "6r1/5k2/p1b1r2p/1pB1p1p1/1Pp3PP/2P1R1K1/2P2P2/3R4 w - - 1 36",
     202              :       "rnbqkb1r/pppppppp/5n2/8/2PP4/8/PP2PPPP/RNBQKBNR b KQkq c3 0 2",
     203              :       "2rr2k1/1p4bp/p1q1p1p1/4Pp1n/2PB4/1PN3P1/P3Q2P/2RR2K1 w - f6 0 20",
     204              :       "3br1k1/p1pn3p/1p3n2/5pNq/2P1p3/1PN3PP/P2Q1PB1/4R1K1 w - - 0 23",
     205              :       "2r2b2/5p2/5k2/p1r1pP2/P2pB3/1P3P2/K1P3R1/7R w - - 23 93"      
     206            0 :    };
     207              : 
     208            0 :    RootPosition p;
     209              : #ifdef WITH_NNUE
     210            0 :    NNUEEvaluator evaluator;
     211              :    p.associateEvaluator(evaluator);
     212              : #endif
     213              : 
     214            0 :    BetaCutStat betaStats;
     215              : 
     216            0 :    for( const auto & fen : positions){
     217            0 :       readFEN(fen, p);
     218            0 :       analyze(p, depth, true);
     219            0 :       betaStats.update(ThreadPool::instance().main().stats);
     220              :    }
     221              : 
     222              :    betaStats.show();
     223              :    
     224            0 :    return true;
     225            0 : }
     226              : 
     227           21 : bool cliManagement(const std::string & firstArg, int argc, char** argv) {
     228              :    
     229              :    // first we will look for options that do not need extra parameters
     230              : 
     231              : #ifdef WITH_UCI
     232           21 :    if (firstArg == "-uci") {
     233            1 :       UCI::init();
     234            1 :       TimeMan::init();
     235            1 :       UCI::uci();
     236            1 :       return true;
     237              :    }
     238           20 :    Logging::LogIt(Logging::logInfo) << "You can use -uci command line option to enter uci mode";
     239              : #endif
     240              : #ifdef WITH_XBOARD
     241           20 :    if (firstArg == "-xboard") {
     242            1 :       XBoard::init();
     243            1 :       TimeMan::init();
     244            1 :       XBoard::xboard();
     245            1 :       return true;
     246              :    }
     247           19 :    Logging::LogIt(Logging::logInfo) << "You can use -xboard command line option to enter xboard mode";
     248              : #endif
     249              : 
     250              : #ifdef WITH_FMTLIB   
     251              :    // let's switch to "pretty mode"
     252              :    Pretty::init();
     253              : #endif
     254              : 
     255              :    const auto args {std::span(argv, size_t(argc))};
     256              : 
     257           19 :    if (firstArg == "-selfplay") {
     258              :       DepthType d = 15; // this is "search depth", not genFenDepth !
     259            1 :       if (argc > 2) d = clampDepth(atoi(args[2]));
     260              :       int64_t n = 1;
     261            1 :       if (argc > 3) n = atoll(args[3]);
     262            1 :       Logging::LogIt(Logging::logInfo) << "Let's go for " << n << " selfplay games ...";
     263            1 :       const auto startTime = Clock::now();
     264              :       uint64_t nbGames = 0;
     265              :       uint64_t nbPos = 0;
     266            2 :       while (n-- > 0) {
     267            2 :          if (n % 1000 == 0) Logging::LogIt(Logging::logInfo) << "Remaining games " << n;
     268            1 :          uint64_t nbPosLoc = 0;
     269            1 :          selfPlay(d, nbPosLoc);
     270            1 :          nbPos += nbPosLoc;
     271              :          const auto ms = getTimeDiff(startTime);
     272            1 :          ++nbGames;
     273            1 :          Logging::LogIt(Logging::logError) << "Nb games : " << nbGames << ", Nb Pos : " << nbPos << ", elapsed s : " << ms/1000;
     274            2 :          Logging::LogIt(Logging::logError) << "Game speed : " << static_cast<double>(nbGames) / (static_cast<double>(ms) / 1000 / 60) << " games/min";
     275            2 :          Logging::LogIt(Logging::logError) << "Pos speed : " << static_cast<double>(nbPos) / (static_cast<double>(ms) / 1000) << " pos/s";         
     276              :       }
     277              :       return true;
     278              :    }
     279              : 
     280           18 :    if (firstArg == "-perft_test") {
     281              :       bool ok = true;
     282            1 :       ok |= perft_test(std::string(startPosition), 5, 4865609);
     283            1 :       ok |= perft_test("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - ", 4, 4085603);
     284            1 :       ok |= perft_test("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - ", 6, 11030083);
     285            1 :       ok |= perft_test("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5, 15833292);
     286            1 :       return ok;
     287              :    }
     288              : 
     289           17 :    if (firstArg == "-perft_test_long_fischer") {
     290              :       bool ok = true;
     291            0 :       DynamicConfig::FRC = true;
     292            0 :       std::ifstream infile("Book_and_Test/TestSuite/fischer.txt");
     293              :       std::string   line;
     294            0 :       while (std::getline(infile, line)) {
     295              :          std::size_t       found = line.find_first_of(",");
     296            0 :          const std::string fen   = line.substr(0, found);
     297            0 :          while (found != std::string::npos) {
     298            0 :             const std::size_t start = found + 1;
     299              :             found                   = line.find_first_of(',', found + 1);
     300            0 :             const uint64_t ull      = std::stoull(line.substr(start, found - start));
     301            0 :             ok |= perft_test(fen, 6, ull);
     302              :          }
     303              :       }
     304              :       return ok;
     305            0 :    }
     306              : 
     307           17 :    if (firstArg == "-perft_test_long") {
     308              :       bool ok = true;
     309            0 :       std::ifstream infile("Book_and_Test/TestSuite/perft.txt");
     310              :       std::string   line;
     311            0 :       while (std::getline(infile, line)) {
     312              :          std::size_t       found = line.find_first_of(",");
     313            0 :          const std::string fen   = line.substr(0, found);
     314              :          DepthType         i     = 0;
     315            0 :          while (found != std::string::npos) {
     316            0 :             const std::size_t start = found + 1;
     317              :             found                   = line.find_first_of(',', found + 1);
     318            0 :             const uint64_t ull      = std::stoull(line.substr(start, found - start));
     319            0 :             ok |= perft_test(fen, ++i, ull);
     320              :          }
     321              :       }
     322              :       return ok;
     323            0 :    }
     324              : 
     325           17 :    if (firstArg == "-see_test") {
     326            1 :       return TestSEE();
     327              :    }
     328              : 
     329           16 :    if (firstArg == "bench" || firstArg == "-bench") {
     330              :       DepthType d = 16;
     331            2 :       if (argc > 2) d = clampDepth(atoi(args[2]));
     332            1 :       return bench(d);
     333              :    }
     334              : 
     335           15 :    if (firstArg == "spsa" || firstArg == "-spsa") {
     336              :       return spsaInputs();
     337              :    }
     338              : 
     339           14 :    if (firstArg == "benchBig" || firstArg == "-benchBig") {
     340              :       DepthType d = 16;
     341            0 :       if (argc > 2) d = clampDepth(atoi(args[2]));
     342            0 :       return benchBig(d);
     343              :    }
     344              : 
     345           14 :    if (firstArg == "-evalSpeed") {
     346            0 :       DynamicConfig::disableTT = true;
     347            0 :       std::string filename     = "Book_and_Test/TestSuite/evalSpeed.epd";
     348            0 :       if (argc > 2) filename = args[2];
     349            0 :       std::vector<RootPosition> data;
     350            0 :       Logging::LogIt(Logging::logInfo) << "Running eval speed with file (including NNUE evaluator reset)" << filename;
     351            0 :       std::vector<std::string> positions;
     352            0 :       DISCARD                  readEPDFile(filename, positions);
     353            0 :       for (size_t k = 0; k < positions.size(); ++k) {
     354            0 :          data.emplace_back(positions[k], false);
     355            0 :          if (k % 50000 == 0) Logging::LogIt(Logging::logInfo) << k << " position read";
     356              :       }
     357            0 :       Logging::LogIt(Logging::logInfo) << "Data size : " << data.size();
     358              : 
     359            0 :       std::chrono::time_point<Clock> startTime = Clock::now();
     360              :       const int loops = 10;
     361            0 :       for (int k = 0; k < loops; ++k)
     362            0 :          for (auto& p : data) {
     363              : #ifdef WITH_NNUE
     364            0 :             NNUEEvaluator evaluator;
     365              :             p.associateEvaluator(evaluator);
     366            0 :             p.resetNNUEEvaluator(evaluator);
     367              : #endif
     368            0 :             EvalData d;
     369            0 :             DISCARD eval(p, d, ThreadPool::instance().main(), true);
     370              :          }
     371              :       auto ms = getTimeDiff(startTime);
     372            0 :       Logging::LogIt(Logging::logInfo) << "Eval speed (with EG material hash): " << static_cast<double>(data.size()) * loops / (static_cast<double>(ms) * 1000) << " Meval/s";
     373              : 
     374            0 :       startTime = Clock::now();
     375            0 :       for (int k = 0; k < loops; ++k)
     376            0 :          for (auto& p : data) {
     377              : #ifdef WITH_NNUE
     378            0 :             NNUEEvaluator evaluator;
     379              :             p.associateEvaluator(evaluator);
     380            0 :             p.resetNNUEEvaluator(evaluator);
     381              : #endif
     382            0 :             EvalData d;
     383            0 :             DISCARD eval(p, d, ThreadPool::instance().main(), false);
     384              :          }
     385              :       ms = getTimeDiff(startTime);
     386            0 :       Logging::LogIt(Logging::logInfo) << "Eval speed : " << static_cast<double>(data.size()) * loops / (static_cast<double>(ms) * 1000) << " Meval/s";
     387              : 
     388            0 :       ThreadPool::instance().displayStats();
     389              :       return true;
     390            0 :    }
     391              : 
     392           14 :    if (firstArg == "-timeTest") {
     393              :       TimeMan::TCType tcType      = TimeMan::TC_suddendeath;
     394              :       TimeType        initialTime = 50000;
     395              :       TimeType        increment   = 0;
     396              :       int             movesInTC   = -1;
     397              :       TimeType        guiLag      = 0;
     398            1 :       if (argc > 2) initialTime = atoi(args[2]);
     399            1 :       if (argc > 3) increment   = atoi(args[3]);
     400            1 :       if (argc > 4) movesInTC   = atoi(args[4]);
     401            1 :       if (argc > 5) guiLag      = atoi(args[5]);
     402            1 :       TimeMan::simulate(tcType, initialTime, increment, movesInTC, guiLag);
     403            1 :       return true;
     404              :    }
     405              : 
     406              :    // in all other cases, args[2] is always the fen string
     407           13 :    if(argc < 3){
     408            0 :       Logging::LogIt(Logging::logError) << "your command is either wrong or needs a fen string";
     409            0 :       return true;
     410              :    }
     411           13 :    std::string fen = args[2];
     412              : 
     413              :    // some "short cuts" !
     414           13 :    if (fen == "start") fen = startPosition;
     415           13 :    if (fen == "fine70") fen = fine70;
     416           13 :    if (fen == "shirov") fen = shirov;
     417           13 :    if (fen == "shirov2") fen = shirov2;
     418           13 :    if (fen == "mate4") fen = mate4;
     419              : 
     420              :    // validate the supposed fen string ...
     421              :    const std::regex lookLikeFen(
     422              :     "^"
     423              :     "([rnbqkpRNBQKP1-8]+\\/){7}([rnbqkpRNBQKP1-8]+)\\s"
     424              :     "[bw]\\s"
     425              :     "((-|(K|[A-H])?(Q|[A-H])?(k|[a-h])?(q|[a-h])?)\\s)"
     426              :     "((-|[a-h][36])\\s)"
     427              :     "((\\d+)\\s(\\d+)\\s?|(\\d+)\\s?)?"
     428              :     "$"
     429           13 :    );
     430           13 :    if( ! std::regex_match(fen, lookLikeFen)){
     431            1 :       Logging::LogIt(Logging::logError) << "fen does not look good... : " << fen;
     432            1 :       return true;
     433              :    }
     434              : 
     435              :    // instantiate the position
     436           12 :    RootPosition p;
     437              : #ifdef WITH_NNUE
     438           12 :    NNUEEvaluator evaluator;
     439              :    p.associateEvaluator(evaluator);
     440              : #endif
     441           12 :    if (!readFEN(fen, p, false, true)) {
     442            0 :       Logging::LogIt(Logging::logError) << "when reading fen";
     443            0 :       return true;
     444              :    }
     445              : 
     446           24 :    Logging::LogIt(Logging::logInfo) << ToString(p);
     447              : 
     448           12 :    if (firstArg == "-qsearch") {
     449            1 :       DepthType seldepth = 0;
     450            1 :       ScoreType s        = ThreadPool::instance().main().qsearchNoPruning(-10000, 10000, p, 1, seldepth);
     451            1 :       Logging::LogIt(Logging::logInfo) << "QScore " << s;
     452              :       return true;
     453              :    }
     454              : 
     455              : #ifdef WITH_SYZYGY
     456           11 :    if (firstArg == "-probe"){
     457            0 :       Logging::LogIt(Logging::logInfo) << "Probing TB";
     458            0 :       if ((BB::countBit(p.allPieces[Co_White] | p.allPieces[Co_Black])) <= SyzygyTb::MAX_TB_MEN) {
     459            0 :          ScoreType tbScore = 0;
     460            0 :          Logging::LogIt(Logging::logInfo) << "Probing root";
     461            0 :          if (MoveList movesTB; SyzygyTb::probe_root(ThreadPool::instance().main(), p, tbScore, movesTB) >= 0) { // only good moves if TB success
     462            0 :             for (auto m : movesTB ){
     463            0 :                Logging::LogIt(Logging::logInfo) << "TB move " << ToString(m);
     464              :             }
     465            0 :             Logging::LogIt(Logging::logInfo) << "Score " << tbScore;
     466              :          }
     467              :          else {
     468            0 :             Logging::LogIt(Logging::logInfo) << "TB failed";
     469              :          }
     470            0 :          Logging::LogIt(Logging::logInfo) << "Probing wdl";
     471            0 :          if (SyzygyTb::probe_wdl(p, tbScore, false) > 0) {
     472            0 :             Logging::LogIt(Logging::logInfo) << "Score " << tbScore;
     473              :          }
     474              :          else {
     475            0 :             Logging::LogIt(Logging::logInfo) << "TB failed";
     476              :          }
     477              :       }
     478              :       else {
     479            0 :          Logging::LogIt(Logging::logInfo) << "No TB hit";
     480              :       }
     481            0 :       return true;
     482              :    }
     483              : #endif
     484              : 
     485           11 :    if ( firstArg == "-kpk"){
     486            1 :       Logging::LogIt(Logging::logInfo) << "Probing KPK";
     487            1 :       const Color winningSide = p.pieces_const<P_wp>(Co_White) == emptyBitBoard ? Co_Black : Co_White;
     488            1 :       std::cout << "KPK score : " << MaterialHash::helperKPK(p, winningSide, 0, 1) << std::endl;
     489              :       return true;
     490              :    }
     491              : 
     492           10 :    if (firstArg == "-see") {
     493            1 :       Square from  = INVALIDSQUARE;
     494            1 :       Square to    = INVALIDSQUARE;
     495            1 :       MType  mtype = T_std;
     496            1 :       const std::string move  = argc > 3 ? args[3] : "e2e4";
     497            1 :       readMove(p, move, from, to, mtype);
     498            1 :       Move      m = ToMove(from, to, mtype);
     499            1 :       ScoreType t = clampInt<ScoreType>(atoi(args[4]));
     500            1 :       bool      b = Searcher::SEE_GE(p, m, t);
     501            2 :       Logging::LogIt(Logging::logInfo) << "SEE ? " << (b ? "ok" : "not");
     502              :       return true;
     503              :    }
     504              : 
     505            9 :    if (firstArg == "-attacked") {
     506              :       Square k = Sq_e4;
     507            2 :       if (argc > 3) k = clampIntU<Square>(atoi(args[3]));
     508            1 :       Logging::LogIt(Logging::logInfo) << SquareNames[k];
     509            2 :       Logging::LogIt(Logging::logInfo) << ToString(BBTools::allAttackedBB(p, k, p.c));
     510            1 :       return true;
     511              :    }
     512              : 
     513            8 :    if (firstArg == "-cov") {
     514              :       Square k = Sq_e4;
     515            2 :       if (argc > 3) k = clampIntU<Square>(atoi(args[3]));
     516            1 :       switch (p.board_const(k)) {
     517            2 :          case P_wp: Logging::LogIt(Logging::logInfo) << ToString((BBTools::coverage<P_wp>(k, p.occupancy(), p.c) + BBTools::mask[k].push[p.c]) &~p.allPieces[Co_White]); break;
     518            0 :          case P_wn: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wn>(k, p.occupancy(), p.c) & ~p.allPieces[Co_White]); break;
     519            0 :          case P_wb: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wb>(k, p.occupancy(), p.c) & ~p.allPieces[Co_White]); break;
     520            0 :          case P_wr: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wr>(k, p.occupancy(), p.c) & ~p.allPieces[Co_White]); break;
     521            0 :          case P_wq: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wq>(k, p.occupancy(), p.c) & ~p.allPieces[Co_White]); break;
     522            0 :          case P_wk: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wk>(k, p.occupancy(), p.c) & ~p.allPieces[Co_White]); break;
     523            0 :          case P_bk: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wk>(k, p.occupancy(), p.c) & ~p.allPieces[Co_Black]); break;
     524            0 :          case P_bq: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wq>(k, p.occupancy(), p.c) & ~p.allPieces[Co_Black]); break;
     525            0 :          case P_br: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wr>(k, p.occupancy(), p.c) & ~p.allPieces[Co_Black]); break;
     526            0 :          case P_bb: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wb>(k, p.occupancy(), p.c) & ~p.allPieces[Co_Black]); break;
     527            0 :          case P_bn: Logging::LogIt(Logging::logInfo) << ToString(BBTools::coverage<P_wn>(k, p.occupancy(), p.c) & ~p.allPieces[Co_Black]); break;
     528              :          case P_bp:
     529            0 :             Logging::LogIt(Logging::logInfo) << ToString((BBTools::coverage<P_wp>(k, p.occupancy(), p.c) + BBTools::mask[k].push[p.c]) &
     530            0 :                                                          ~p.allPieces[Co_Black]);
     531            0 :             break;
     532            0 :          default: Logging::LogIt(Logging::logInfo) << ToString(emptyBitBoard);
     533              :       }
     534            1 :       return true;
     535              :    }
     536              : 
     537            7 :    if (firstArg == "-eval") {
     538            1 :       EvalData data;
     539            1 :       if (DynamicConfig::useNNUE) DynamicConfig::forceNNUE = true;
     540            1 :       const ScoreType score = eval(p, data, ThreadPool::instance().main(), true, true);
     541            1 :       Logging::LogIt(Logging::logInfo) << "eval " << score << " phase " << data.gp;
     542              :       return true;
     543              :    }
     544              : 
     545            6 :    if (firstArg == "-evalHCE") {
     546            1 :       EvalData data;
     547            1 :       if (DynamicConfig::useNNUE) DynamicConfig::useNNUE = false;
     548            1 :       const ScoreType score = eval(p, data, ThreadPool::instance().main(), true, true);
     549            1 :       Logging::LogIt(Logging::logInfo) << "eval " << score << " phase " << data.gp;
     550              :       return true;
     551              :    }
     552              : 
     553            5 :    if (firstArg == "-gen") {
     554            1 :       MoveList moves;
     555            1 :       MoveGen::generate<MoveGen::GP_all>(p, moves);
     556            1 :       CMHPtrArray cmhPtr = {nullptr};
     557            1 :       MoveSorter::scoreAndSort(ThreadPool::instance().main(), moves, p, 0.f, 0, cmhPtr);
     558            1 :       Logging::LogIt(Logging::logInfo) << "nb moves : " << moves.size();
     559           41 :       for (const auto & it : moves) { Logging::LogIt(Logging::logInfo) << ToString(it, true); }
     560              :       return true;
     561              :    }
     562              : 
     563            4 :    if (firstArg == "-testmove") {
     564              :       ///@todo
     565              :       constexpr Move m  = ToMove(8, 16, T_std);
     566            1 :       Position p2 = p;
     567              : #if defined(WITH_NNUE) && defined(DEBUG_NNUE_UPDATE)
     568              :       p2.associateEvaluator(evaluator);
     569              :       p2.resetNNUEEvaluator(p2.evaluator());
     570              : #endif
     571            1 :       if (const MoveInfo moveInfo(p2, m); !applyMove(p2, moveInfo)) { 
     572            0 :          Logging::LogIt(Logging::logError) << "Cannot apply this move";
     573              :       }
     574            2 :       Logging::LogIt(Logging::logInfo) << ToString(p2);
     575              :       return true;
     576            1 :    }
     577              : 
     578            3 :    if (firstArg == "-perft") {
     579              :       DepthType d = 5;
     580            2 :       if (argc > 3) d = clampIntU<DepthType>(atoi(args[3]));
     581            1 :       PerftAccumulator acc;
     582            1 :       auto start = Clock::now();
     583            1 :       perft(p, d, acc);
     584              :       auto elapsed = getTimeDiff(start);
     585            1 :       Logging::LogIt(Logging::logInfo) << "Perft done in " << elapsed << "ms";
     586            1 :       acc.Display();
     587            2 :       Logging::LogIt(Logging::logInfo) << "Speed " << static_cast<int>(acc.validNodes / elapsed) << "KNPS";
     588              :       return true;
     589              :    }
     590              : 
     591            2 :    if (firstArg == "-analyze") {
     592              :       DepthType depth = 15;
     593            4 :       if (argc > 3) depth = clampIntU<DepthType>(atoi(args[3]));
     594            2 :       auto start = Clock::now();
     595            2 :       analyze(p, depth);
     596              :       auto elapsed = getTimeDiff(start);
     597            2 :       Logging::LogIt(Logging::logInfo) << "Analysis done in " << elapsed << "ms";
     598              :       return true;
     599              :    }
     600              : 
     601            0 :    if (firstArg == "-mateFinder") {
     602            0 :       DynamicConfig::mateFinder = true;
     603              :       DepthType depth = 10;
     604            0 :       if (argc > 3) depth = clampIntU<DepthType>(atoi(args[3]));
     605            0 :       auto start = Clock::now();
     606            0 :       analyze(p, depth);
     607              :       auto elapsed = getTimeDiff(start);
     608            0 :       Logging::LogIt(Logging::logInfo) << "Analysis done in " << elapsed << "ms";
     609              :       return true;
     610              :    }
     611              : 
     612            0 :    Logging::LogIt(Logging::logError) << "unknown command line : " << firstArg;
     613            0 :    return false;
     614           13 : }
        

Generated by: LCOV version 2.0-1