LCOV - code coverage report
Current view: top level - Source - extendedPosition.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 0.0 % 176 0
Test Date: 2026-03-02 16:42:41 Functions: 0.0 % 15 0

            Line data    Source code
       1              : #include "extendedPosition.hpp"
       2              : 
       3              : #if defined(WITH_TEST_SUITE) || defined(WITH_PGN_PARSER) || defined(WITH_EVAL_TUNING)
       4              : 
       5              : #include <algorithm>
       6              : #include <cctype>
       7              : #include <functional>
       8              : #include <locale>
       9              : #include <numeric>
      10              : 
      11              : #include "com.hpp"
      12              : #include "dynamicConfig.hpp"
      13              : #include "logging.hpp"
      14              : #include "moveGen.hpp"
      15              : #include "positionTools.hpp"
      16              : #include "searcher.hpp"
      17              : #include "tools.hpp"
      18              : 
      19            0 : void split(std::vector<std::string> &v, const std::string &str, const std::string &sep) {
      20              :    size_t start = 0;
      21              :    size_t end = 0;
      22            0 :    while (end != std::string::npos) {
      23              :       end = str.find(sep, start);
      24            0 :       v.push_back(str.substr(start, (end == std::string::npos) ? std::string::npos : end - start));
      25            0 :       start = ((end > (std::string::npos - sep.size())) ? std::string::npos : end + sep.size());
      26              :    }
      27            0 : }
      28              : 
      29            0 : std::vector<std::string> split2(const std::string &line, char sep, char delim) {
      30            0 :    std::vector<std::string> v;
      31              :    const char * c = line.c_str(); // prepare to parse the line
      32              :    bool inSep {false};
      33            0 :    for (const char *p = c; *p; ++p) { // iterate through the string
      34            0 :       if (*p == delim) {              // toggle flag if we're btw delim
      35            0 :          inSep = !inSep;
      36              :       }
      37            0 :       else if (*p == sep && !inSep) { // if sep OUTSIDE delim
      38            0 :          std::string str(c, p - c);
      39            0 :          str.erase(std::remove(str.begin(), str.end(), ':'), str.end());
      40            0 :          v.push_back(str); // keep the field
      41            0 :          c = p + 1;        // and start parsing next one
      42              :       }
      43              :    }
      44            0 :    v.push_back(std::string(c)); // last field delimited by end of line instead of sep
      45            0 :    return v;
      46            0 : }
      47              : 
      48            0 : inline std::string ltrim(std::string &s) {
      49            0 :    s.erase(s.begin(), std::ranges::find_if(s, [](int ch) { return !std::isspace(ch); }));
      50            0 :    return s;
      51              : }
      52              : 
      53            0 : ExtendedPosition::ExtendedPosition(const std::string &extFEN, bool withMoveCount): RootPosition(extFEN, withMoveCount) {
      54            0 :    if (!withMoveCount) {
      55            0 :       halfmoves = 0;
      56            0 :       moves     = 1;
      57            0 :       fifty     = 0;
      58              :    }
      59              :    //Logging::LogIt(Logging::logInfo) << ToString(*this);
      60            0 :    std::vector<std::string> strList;
      61            0 :    std::stringstream        iss(extFEN);
      62            0 :    std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), back_inserter(strList));
      63            0 :    if (strList.size() < (withMoveCount ? 7u : 5u)) Logging::LogIt(Logging::logFatal) << "Not an extended position";
      64            0 :    std::vector<std::string>(strList.begin() + (withMoveCount ? 6 : 4), strList.end()).swap(strList);
      65              :    const std::string extendedParamsStr =
      66            0 :        std::accumulate(strList.begin(), strList.end(), std::string(""), [](const std::string &a, const std::string &b) { return a + ' ' + b; });
      67              :    //Logging::LogIt(Logging::logInfo) << "extended parameters : " << extendedParamsStr;
      68            0 :    std::vector<std::string> strParamList;
      69            0 :    split(strParamList, extendedParamsStr, ";");
      70            0 :    for (auto e : strParamList) {
      71              :       //Logging::LogIt(Logging::logInfo) << "extended parameters : " << k << " " << e;
      72            0 :       e = ltrim(e);
      73            0 :       if (e.empty()) continue;
      74            0 :       std::vector<std::string> pair;
      75            0 :       split(pair, e, " ");
      76            0 :       if (pair.size() < 2) Logging::LogIt(Logging::logFatal) << "Not un extended parameter pair";
      77            0 :       std::vector<std::string> values = pair;
      78              :       values.erase(values.begin());
      79            0 :       _extendedParams[pair[0]] = values;
      80              :       //Logging::LogIt(Logging::logInfo) << "extended parameters pair : " << pair[0] << " => " << values[0];
      81            0 :    }
      82            0 : }
      83              : 
      84            0 : bool ExtendedPosition::shallFindBest() { return _extendedParams.contains("bm"); }
      85              : 
      86            0 : bool ExtendedPosition::shallAvoidBad() { return _extendedParams.contains("am"); }
      87              : 
      88            0 : std::vector<std::string> ExtendedPosition::bestMoves() { return _extendedParams["bm"]; }
      89              : 
      90            0 : std::vector<std::string> ExtendedPosition::badMoves() { return _extendedParams["am"]; }
      91              : 
      92            0 : std::vector<std::string> ExtendedPosition::comment0() { return _extendedParams["c0"]; }
      93              : 
      94            0 : std::string ExtendedPosition::id() {
      95            0 :    if (_extendedParams.contains("id")) 
      96            0 :       return _extendedParams["id"][0];
      97              :    else
      98            0 :       return "";
      99              : }
     100              : 
     101              : template<typename T> std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
     102              :    for (auto it = v.begin(); it != v.end(); ++it) { os << *it << " "; }
     103              :    return os;
     104              : }
     105              : 
     106            0 : std::string ExtendedPosition::epdString() const {
     107            0 :    std::string epd = GetFENShort2(*this) + " ";
     108            0 :    for (const auto &p : _extendedParams) {
     109            0 :       epd += p.first + " ";
     110            0 :       for (const auto &cc : p.second) { epd += cc + " "; }
     111              :       epd += ";";
     112              :    }
     113            0 :    return epd;
     114              : }
     115              : 
     116            0 : void ExtendedPosition::test(const std::vector<std::string> &positions,
     117              :                             const std::vector<int> &        timeControls,
     118              :                             bool                            breakAtFirstSuccess,
     119              :                             bool                            multipleBest,
     120              :                             const std::vector<int> &        scores,
     121              :                             std::function<int(int)>         eloF,
     122              :                             bool                            withMoveCount) {
     123            0 :    struct Results {
     124              :       int                                      k = 0;
     125              :       int                                      t = 0;
     126              :       std::string                              name;
     127              :       std::vector<std::string>                 bm;
     128              :       std::vector<std::string>                 am;
     129              :       std::vector<std::pair<std::string, int>> mea;
     130              :       std::string                              computerMove;
     131              :       int                                      score = 0;
     132              :    };
     133              : 
     134            0 :    if (scores.size() != timeControls.size()) { Logging::LogIt(Logging::logFatal) << "Wrong timeControl versus score vector size"; }
     135              : 
     136            0 :    Results **results = new Results *[positions.size()];
     137              : 
     138            0 :    unsigned int threads = DynamicConfig::threads; //copy
     139              : 
     140            0 :    auto worker = [&](size_t begin, size_t end) {
     141              :       // run the test and fill results table
     142            0 :       for (size_t k = begin; k < end; ++k) {
     143            0 :          Logging::LogIt(Logging::logInfo) << "####################################################";
     144            0 :          Logging::LogIt(Logging::logInfo) << "Test #" << k << " " << positions[k];
     145            0 :          results[k] = new Results[timeControls.size()];
     146            0 :          for (size_t t = 0; t < timeControls.size(); ++t) {
     147            0 :             ExtendedPosition extP(positions[k], withMoveCount);
     148              : #ifdef WITH_NNUE
     149            0 :             NNUEEvaluator    evaluator;
     150              :             extP.associateEvaluator(evaluator);
     151            0 :             extP.resetNNUEEvaluator(extP.evaluator());
     152              : #endif
     153            0 :             Logging::LogIt(Logging::logInfo) << "Current test time control " << timeControls[t];
     154              : 
     155            0 :             TimeMan::isDynamic                   = false;
     156            0 :             TimeMan::nbMoveInTC                  = -1;
     157            0 :             TimeMan::msecPerMove                 = timeControls[t];
     158            0 :             TimeMan::msecInTC                    = -1;
     159            0 :             TimeMan::msecInc                     = -1;
     160            0 :             TimeMan::msecUntilNextTC             = -1;
     161            0 :             ThreadPool::instance().currentMoveMs = TimeMan::getNextMSecPerMove(extP);
     162              : 
     163              :             ///@todo support threading here by using ThinkAsync ?
     164              : 
     165            0 :             ThreadData d;
     166            0 :             d.p = extP; // assumed slicing
     167            0 :             ThreadPool::instance().distributeData(d);
     168            0 :             ThreadPool::instance().main().stopFlag = false;
     169              :             //COM::position = extP; // only need for display purpose
     170            0 :             ThreadPool::instance().main().searchDriver(false);
     171            0 :             d = ThreadPool::instance().main().getData();
     172            0 :             const Move bestMove = d.best;
     173              : 
     174            0 :             results[k][t].name = extP.id();
     175            0 :             results[k][t].k    = static_cast<int>(k);
     176            0 :             results[k][t].t    = timeControls[t];
     177              : 
     178            0 :             results[k][t].computerMove = showAlgAbr(bestMove, extP);
     179            0 :             Logging::LogIt(Logging::logInfo) << "Best move found is  " << results[k][t].computerMove;
     180              : 
     181            0 :             if (!multipleBest && extP.shallFindBest()) {
     182            0 :                Logging::LogIt(Logging::logInfo) << "Best move should be " << extP.bestMoves()[0];
     183            0 :                results[k][t].bm    = extP.bestMoves();
     184            0 :                results[k][t].score = 0;
     185              :                bool success        = false;
     186            0 :                for (size_t i = 0; i < results[k][t].bm.size(); ++i) {
     187            0 :                   if (results[k][t].computerMove == results[k][t].bm[i]) {
     188            0 :                      results[k][t].score = scores[t];
     189              :                      success             = true;
     190            0 :                      break;
     191              :                   }
     192              :                }
     193            0 :                if (breakAtFirstSuccess && success) break;
     194              :             }
     195            0 :             else if (!multipleBest && extP.shallAvoidBad()) {
     196            0 :                Logging::LogIt(Logging::logInfo) << "Bad move was " << extP.badMoves()[0];
     197            0 :                results[k][t].am    = extP.badMoves();
     198            0 :                results[k][t].score = scores[t];
     199              :                bool success        = true;
     200            0 :                for (size_t i = 0; i < results[k][t].am.size(); ++i) {
     201            0 :                   if (results[k][t].computerMove == results[k][t].am[i]) {
     202            0 :                      results[k][t].score = 0;
     203              :                      success             = false;
     204            0 :                      break;
     205              :                   }
     206              :                }
     207            0 :                if (breakAtFirstSuccess && success) break;
     208              :             }
     209              :             else { // look into c0 section ...
     210            0 :                Logging::LogIt(Logging::logInfo) << "Mea style " << extP.comment0()[0];
     211            0 :                std::vector<std::string> tokens = extP.comment0();
     212            0 :                for (size_t ms = 0; ms < tokens.size(); ++ms) {
     213              :                   std::string tmp = tokens[ms];
     214            0 :                   tmp.erase(std::remove(tmp.begin(), tmp.end(), '"'), tmp.end());
     215            0 :                   tmp.erase(std::remove(tmp.begin(), tmp.end(), ','), tmp.end());
     216              :                   //std::cout << tmp << std::endl;
     217            0 :                   std::vector<std::string> keyval;
     218            0 :                   tokenize(tmp, keyval, "=");
     219            0 :                   if (keyval.size() > 2) { // "=" prom sign inside ...
     220            0 :                      std::stringstream strTmp;
     221              :                      copy(keyval.begin(), keyval.begin() + 1, std::ostream_iterator<std::string>(strTmp, "="));
     222            0 :                      strTmp >> keyval[0];
     223              :                      keyval[1] = keyval.back();
     224            0 :                   }
     225              :                   std::cout << keyval[0] << " " << keyval[1] << std::endl;
     226            0 :                   results[k][t].mea.push_back(std::make_pair(keyval[0], std::stoi(keyval[1])));
     227            0 :                }
     228            0 :                results[k][t].score = 0;
     229              :                bool success = false;
     230            0 :                constexpr array1d<int, 23>   ms = {10,  20,  30,  40,  50,  60,  70,  80,  90,  100, 125,  150,
     231              :                                                  175, 200, 250, 300, 400, 500, 600, 700, 800, 900, 10000};
     232            0 :                constexpr array1d<double, 23> bonus = {3.0, 2.9, 2.8, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1, 2.0, 1.9,
     233              :                                                       1.8, 1.7, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1, 1.0, 1.0, 0.0};
     234            0 :                for (size_t i = 0; i < results[k][t].mea.size(); ++i) {
     235            0 :                   if (results[k][t].computerMove == results[k][t].mea[i].first) {
     236            0 :                      results[k][t].score     = results[k][t].mea[i].second;
     237              :                      const SearchData &datas = d.datas;
     238              :                      TimeType          msec  = 1000;
     239            0 :                      DepthType         dd    = d.depth;
     240            0 :                      for (; dd >= 0; --dd) {
     241            0 :                         if (sameMove(datas.moves[dd], bestMove)) { msec = datas.times[dd]; }
     242              :                         else
     243              :                            break;
     244              :                      }
     245              :                      size_t id = 0;
     246            0 :                      for (; id < 23 && ms[id] < msec; ++id) { ; }
     247              : 
     248            0 :                      Logging::LogIt(Logging::logInfo) << "Good " << i + 1 << " best move : " << results[k][t].mea[i].first;
     249            0 :                      Logging::LogIt(Logging::logInfo) << "Found at depth " << static_cast<int>(dd) << " in " << datas.times[dd] << " id " << id;
     250            0 :                      Logging::LogIt(Logging::logInfo) << "Bonus " << bonus[id] << " score " << results[k][t].mea[i].second;
     251              : 
     252            0 :                      results[k][t].score = static_cast<int>(results[k][t].score * bonus[id]);
     253              :                      success             = true;
     254              :                      break;
     255              :                   }
     256              :                }
     257            0 :                if (breakAtFirstSuccess && success) break;
     258            0 :             }
     259              :          }
     260              :       }
     261            0 :    };
     262              : 
     263            0 :    threadedWork(worker, threads, positions.size());
     264              : 
     265              :    // display results
     266              :    int totalScore = 0;
     267            0 :    std::cout << std::setw(25) << "Test" << std::setw(14) << "Move";
     268            0 :    for (size_t j = 0; j < timeControls.size(); ++j) { std::cout << std::setw(8) << timeControls[j]; }
     269              :    std::cout << std::setw(6) << "score" << std::endl;
     270            0 :    for (size_t k = 0; k < positions.size(); ++k) {
     271              :       int score = 0;
     272            0 :       for (size_t t = 0; t < timeControls.size(); ++t) { score += results[k][t].score; }
     273            0 :       totalScore += score;
     274            0 :       std::stringstream str;
     275            0 :       const std::vector<std::string> v = results[k][0].bm.empty() ? results[k][0].am : results[k][0].bm;
     276              :       std::ostream_iterator<std::string> strIt(str, " ");
     277            0 :       std::ranges::copy(v, strIt);
     278            0 :       std::cout << std::setw(25) << results[k][0].name << std::setw(14) << (results[k][0].bm.empty() ? std::string("!") + str.str() : str.str());
     279            0 :       for (size_t j = 0; j < timeControls.size(); ++j) { std::cout << std::setw(8) << results[k][j].computerMove; }
     280            0 :       std::cout << std::setw(6) << score << std::endl;
     281            0 :    }
     282              : 
     283            0 :    Logging::LogIt(Logging::logInfo) << "Total score " << totalScore << " => ELO " << eloF(totalScore);
     284              : 
     285              :    // clear results table
     286            0 :    for (size_t k = 0; k < positions.size(); ++k) { delete[] results[k]; }
     287            0 :    delete[] results;
     288            0 : }
     289              : 
     290            0 : void ExtendedPosition::testStatic(const std::vector<std::string> &positions, bool withMoveCount) {
     291            0 :    struct Results {
     292              :       int         k = 0;
     293              :       int         t = 0;
     294              :       ScoreType   score = 0;
     295              :       std::string name;
     296              :    };
     297              : 
     298            0 :    Results *results = new Results[positions.size()];
     299              : 
     300              :    // run the test and fill results table
     301            0 :    for (size_t k = 0; k < positions.size(); ++k) {
     302              :       std::cout << "Test #" << k << " " << positions[k] << std::endl;
     303            0 :       ExtendedPosition extP(positions[k], withMoveCount);
     304              :       //std::cout << " " << t << std::endl;
     305            0 :       EvalData  data;
     306            0 :       ScoreType ret = eval(extP, data, ThreadPool::instance().main(), true, true);
     307              : 
     308            0 :       results[k].name  = extP.id();
     309            0 :       results[k].k     = static_cast<int>(k);
     310            0 :       results[k].score = ret;
     311              : 
     312            0 :       std::cout << "score is  " << ret << std::endl;
     313              :    }
     314              : 
     315              :    // display results
     316              :    std::cout << std::setw(25) << "Test" << std::setw(14) << "score" << std::endl;
     317            0 :    for (size_t k = 0; k < positions.size() - 2; k += 4) {
     318            0 :       std::cout << std::setw(25) << results[k].name << std::setw(14) << results[k].score << std::endl;
     319              :       // only compare unsigned score ...
     320            0 :       if (Abs(Abs(results[k].score) - Abs(results[k + 2].score)) > 0) { Logging::LogIt(Logging::logWarn) << "Score differ !"; }
     321            0 :       std::cout << std::setw(25) << results[k + 1].name << std::setw(14) << results[k + 1].score << std::endl;
     322              :       // only compare unsigned score ...
     323            0 :       if (Abs(Abs(results[k + 1].score) - Abs(results[k + 3].score)) > 0) { Logging::LogIt(Logging::logWarn) << "Score differ !"; }
     324              :    }
     325              : 
     326              :    // clear results table
     327            0 :    delete[] results;
     328            0 : }
     329              : 
     330              : #endif
        

Generated by: LCOV version 2.0-1