Subversion Repositories Games.Chess Giants

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     Texel - A UCI chess engine.
  3.     Copyright (C) 2012-2013  Peter Ă–sterlund, peterosterlund2@gmail.com
  4.  
  5.     This program is free software: you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation, either version 3 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. /*
  20.  * treeLogger.cpp
  21.  *
  22.  *  Created on: Feb 25, 2012
  23.  *      Author: petero
  24.  */
  25.  
  26. #include "treeLogger.hpp"
  27. #include "transpositionTable.hpp"
  28. #include "textio.hpp"
  29. #include "position.hpp"
  30. #include "constants.hpp"
  31.  
  32. #include <iostream>
  33. #include <iomanip>
  34. #include <cassert>
  35.  
  36. void
  37. TreeLoggerWriter::open(const std::string& filename,
  38.                        ParallelData& pd0, int threadNo0) {
  39.     auto fn = filename + std::string(".") + num2Str(threadNo0);
  40.     os.open(fn.c_str(), std::ios_base::out |
  41.                         std::ios_base::binary |
  42.                         std::ios_base::trunc);
  43.     opened = true;
  44.  
  45.     pd = &pd0;
  46.     threadNo = threadNo0;
  47. }
  48.  
  49. void
  50. TreeLoggerWriter::close() {
  51.     if (opened) {
  52.         if (nInWriteCache > 0) {
  53.             os.write((const char*)writeCache, Entry::bufSize * nInWriteCache);
  54.             nInWriteCache = 0;
  55.         }
  56.         opened = false;
  57.         os.close();
  58.     }
  59. }
  60.  
  61. void
  62. TreeLoggerWriter::writePosition(const Position& pos, int owningThread, U64 parentIndex, int moveNo) {
  63.     Position::SerializeData data;
  64.     pos.serialize(data);
  65.  
  66.     entry.type = (nextIndex == 0) ? EntryType::POSITION_INCOMPLETE : EntryType::POSITION_PART0;
  67.     entry.p0.nextIndex = endMark;
  68.     entry.p0.word0 = data.v[0];
  69.     entry.p0.word1 = data.v[1];
  70.     appendEntry(entry);
  71.     nextIndex++;
  72.  
  73.     entry.type = EntryType::POSITION_PART1;
  74.     entry.p1.t0Index = pd->t0Index;
  75.     entry.p1.word2 = data.v[2];
  76.     entry.p1.word3 = data.v[3];
  77.     appendEntry(entry);
  78.     nextIndex++;
  79.  
  80.     entry.type = EntryType::POSITION_PART2;
  81.     entry.p2.word4 = data.v[4];
  82.     entry.p2.owningThread = owningThread;
  83.     entry.p2.parentIndex = (U32)parentIndex; // Pierre-Marie Baty -- added type cast
  84.     entry.p2.moveNo = moveNo;
  85.     appendEntry(entry);
  86.     nextIndex++;
  87. }
  88.  
  89. void
  90. TreeLoggerWriter::appendEntry(const Entry& entry) {
  91.     entry.serialize(entryBuffer);
  92.     memcpy(&writeCache[Entry::bufSize * nInWriteCache], entryBuffer, Entry::bufSize);
  93.     nInWriteCache++;
  94.     if (nInWriteCache == writeCacheSize) {
  95.         os.write((const char*)writeCache, Entry::bufSize * nInWriteCache);
  96.         nInWriteCache = 0;
  97.     }
  98. }
  99.  
  100.  
  101. TreeLoggerReader::TreeLoggerReader(const std::string& filename)
  102.     : fs(filename.c_str(), std::ios_base::out |
  103.                            std::ios_base::in |
  104.                            std::ios_base::binary),
  105.       filePos(-1), numEntries(0) {
  106.     fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  107.     fs.seekg(0, std::ios_base::end);
  108.     S64 fileLen = fs.tellg();
  109.     numEntries = fileLen / Entry::bufSize;
  110.     computeForwardPointers();
  111. }
  112.  
  113. void
  114. TreeLoggerReader::close() {
  115.     fs.close();
  116. }
  117.  
  118. void
  119. TreeLoggerReader::main(const std::string& filename) {
  120.     try {
  121.         TreeLoggerReader an(filename);
  122.         an.mainLoop();
  123.         an.close();
  124.     } catch (const std::exception& ex) {
  125.         std::cout << "Error: " << ex.what() << std::endl;
  126.     }
  127. }
  128.  
  129. void
  130. TreeLoggerReader::computeForwardPointers() {
  131.     readEntry(0, entry);
  132.     if (entry.type != EntryType::POSITION_INCOMPLETE)
  133.         return;
  134.  
  135.     std::cout << "Computing forward pointers..." << std::endl;
  136.     const size_t batchSize = 1000000;
  137.     std::vector<std::pair<U64,U64>> toWrite;
  138.     toWrite.reserve(batchSize);
  139.     U64 prevPosIdx = 0;
  140.     for (U64 i = 0; i < numEntries; i++) {
  141.         readEntry(i, entry);
  142.         if (entry.type == EntryType::NODE_END) {
  143.             U64 idx = entry.ee.startIndex;
  144.             toWrite.push_back(std::make_pair(idx, i));
  145.         } else if (entry.type == EntryType::POSITION_PART0) {
  146.             if (i > prevPosIdx)
  147.                 toWrite.push_back(std::make_pair(prevPosIdx, i));
  148.             prevPosIdx = i;
  149.         }
  150.         if (toWrite.size() >= batchSize) {
  151.             flushForwardPointerData(toWrite);
  152.             toWrite.clear();
  153.             toWrite.reserve(batchSize);
  154.         }
  155.     }
  156.     flushForwardPointerData(toWrite);
  157.  
  158.     readEntry(0, entry);
  159.     assert(entry.type == EntryType::POSITION_INCOMPLETE);
  160.     entry.type = EntryType::POSITION_PART0;
  161.     writeEntry(0, entry);
  162.  
  163.     fs.flush();
  164.     std::cout << "Computing forward pointers... done" << std::endl;
  165. }
  166.  
  167. void
  168. TreeLoggerReader::flushForwardPointerData(std::vector<std::pair<U64,U64>>& toWrite) {
  169.     if (toWrite.empty())
  170.         return;
  171.     std::sort(toWrite.begin(), toWrite.end());
  172.     const U64 eSize = Entry::bufSize;
  173.     const U64 cacheSize = 512;
  174.     U8 cacheBuf[eSize * cacheSize];
  175.     const U64 emptyMark = std::numeric_limits<U64>::max();
  176.     U64 cacheStart = emptyMark; // Index for first entry in cache
  177.  
  178.     for (auto p : toWrite) {
  179.         const U64 startIdx = p.first;
  180.         const U64 endIdx = p.second;
  181.  
  182.         if ((cacheStart != emptyMark) &&
  183.             ((startIdx < cacheStart) || (startIdx >= cacheStart + cacheSize))) { // flush
  184.             int nWrite = (int)std::min(cacheSize, numEntries - cacheStart); // Pierre-Marie Baty -- added type cast
  185.             fs.seekp(cacheStart * eSize, std::ios_base::beg);
  186.             fs.write((const char*)cacheBuf, nWrite * eSize);
  187.             cacheStart = emptyMark;
  188.         }
  189.         if (cacheStart == emptyMark) {
  190.             cacheStart = startIdx;
  191.             int nRead = (int)std::min(cacheSize, numEntries - cacheStart); // Pierre-Marie Baty -- added type cast
  192.             fs.seekg(cacheStart * eSize, std::ios_base::beg);
  193.             fs.read((char*)cacheBuf, nRead * eSize);
  194.         }
  195.  
  196.         U8* entAddr = &cacheBuf[(startIdx - cacheStart) * eSize];
  197.         entry.deSerialize(entAddr);
  198.         if (entry.type == EntryType::NODE_START) {
  199.             entry.se.endIndex = (U32)endIdx; // Pierre-Marie Baty -- added type cast
  200.         } else if ((entry.type == EntryType::POSITION_PART0) ||
  201.                    (entry.type == EntryType::POSITION_INCOMPLETE)) {
  202.             entry.p0.nextIndex = (U32)endIdx; // Pierre-Marie Baty -- added type cast
  203.         } else
  204.             assert(false);
  205.         entry.serialize(entAddr);
  206.     }
  207.     if (cacheStart != emptyMark) { // flush
  208.         int nWrite = (int)std::min(cacheSize, numEntries - cacheStart); // Pierre-Marie Baty -- added type cast
  209.         fs.seekp(cacheStart * eSize, std::ios_base::beg);
  210.         fs.write((const char*)cacheBuf, nWrite * eSize);
  211.     }
  212.     filePos = -1;
  213. }
  214.  
  215. void
  216. TreeLoggerReader::getRootNode(U64 index, Position& pos, int& owningThread,
  217.                               U64& parentIndex, int& moveNo, U64& t0Index) {
  218.     readEntry(index, entry);
  219.     if (entry.type == EntryType::POSITION_PART1) {
  220.         index--;
  221.         readEntry(index, entry);
  222.     } else if (entry.type == EntryType::POSITION_PART2) {
  223.         index -= 2;
  224.         readEntry(index, entry);
  225.     }
  226.     assert((entry.type == EntryType::POSITION_INCOMPLETE) ||
  227.            (entry.type == EntryType::POSITION_PART0));
  228.  
  229.     Position::SerializeData data;
  230.     data.v[0] = entry.p0.word0;
  231.     data.v[1] = entry.p0.word1;
  232.  
  233.     readEntry(index + 1, entry);
  234.     assert(entry.type == EntryType::POSITION_PART1);
  235.     t0Index = entry.p1.t0Index;
  236.     data.v[2] = entry.p1.word2;
  237.     data.v[3] = entry.p1.word3;
  238.  
  239.     readEntry(index + 2, entry);
  240.     assert(entry.type == EntryType::POSITION_PART2);
  241.     data.v[4] = entry.p2.word4;
  242.     owningThread = entry.p2.owningThread;
  243.     parentIndex = entry.p2.parentIndex;
  244.     moveNo = entry.p2.moveNo;
  245.  
  246.     pos.deSerialize(data);
  247. }
  248.  
  249. void
  250. TreeLoggerReader::readEntry(U64 index, Entry& entry) {
  251.     S64 offs = index * Entry::bufSize;
  252.     if (offs != filePos)
  253.         fs.seekg(offs, std::ios_base::beg);
  254.     fs.read((char*)entryBuffer, sizeof(entryBuffer));
  255.     filePos = offs + sizeof(entryBuffer);
  256.     entry.deSerialize(entryBuffer);
  257. }
  258.  
  259. void
  260. TreeLoggerReader::writeEntry(U64 index, const Entry& entry) {
  261.     entry.serialize(entryBuffer);
  262.     S64 offs = index * Entry::bufSize;
  263.     fs.seekp(offs, std::ios_base::beg);
  264.     fs.write((const char*)entryBuffer, sizeof(entryBuffer));
  265. }
  266.  
  267. static bool isNoMove(const Move& m) {
  268.     return (m.from() == 1) && (m.to() == 1);
  269. }
  270.  
  271. std::string moveToStr(const Move& m) {
  272.     if (m.isEmpty())
  273.         return "null";
  274.     else if (isNoMove(m))
  275.         return "----";
  276.     else
  277.         return TextIO::moveToUCIString(m);
  278. }
  279.  
  280. void
  281. TreeLoggerReader::mainLoop() {
  282.     S64 currIndex = -1;
  283.     std::string prevStr = "";
  284.  
  285.     bool doPrint = true;
  286.     while (true) {
  287.         if (doPrint) {
  288.             if (currIndex >= 0) {
  289.                 std::vector<Move> moves;
  290.                 U64 rootIdx = getMoveSequence(currIndex, moves);
  291.                 if (currIndex != (S64)rootIdx) {
  292.                     printNodeInfo(rootIdx);
  293.                     for (size_t i = 0; i < moves.size(); i++) {
  294.                         const Move& m = moves[i];
  295.                         std::cout << " " << moveToStr(m);
  296.                     }
  297.                     std::cout << std::endl;
  298.                 }
  299.                 printNodeInfo(currIndex);
  300.                 Position pos = getPosition(currIndex);
  301.                 std::cout << TextIO::asciiBoard(pos);
  302.                 std::cout << TextIO::toFEN(pos) << std::endl;
  303.                 std::cout << num2Hex(pos.historyHash()) << std::endl;
  304.                 if (currIndex != (S64)rootIdx) {
  305.                     std::vector<U64> children;
  306.                     findChildren(currIndex, children);
  307.                     for (size_t i = 0; i < children.size(); i++)
  308.                         printNodeInfo(children[i], i);
  309.                 }
  310.             } else {
  311.                 std::cout << std::setw(8) << currIndex << " entries:" << numEntries << std::endl;
  312.             }
  313.         }
  314.         doPrint = true;
  315.         std::cout << "Command:" << std::flush;
  316.         std::string cmdStr;
  317.         std::getline(std::cin, cmdStr);
  318.         if (!std::cin)
  319.             return;
  320.         if (cmdStr.length() == 0)
  321.             cmdStr = prevStr;
  322.         if (startsWith(cmdStr, "q")) {
  323.             return;
  324.         } else if (startsWith(cmdStr, "?")) {
  325.             printHelp();
  326.             doPrint = false;
  327.         } else if (isMove(cmdStr)) {
  328.             if (currIndex >= 0) {
  329.                 std::vector<U64> children;
  330.                 findChildren(currIndex, children);
  331.                 std::string m = cmdStr;
  332.                 StartEntry se {};
  333.                 EndEntry ee {};
  334.                 std::vector<U64> found;
  335.                 for (size_t i = 0; i < children.size(); i++) {
  336.                     readEntries((int)children[i], se, ee); // Pierre-Marie Baty -- added type cast
  337.                     if (moveToStr(se.getMove()) == m)
  338.                         found.push_back(children[i]);
  339.                 }
  340.                 if (found.empty()) {
  341.                     std::cout << "No such move" << std::endl;
  342.                     doPrint = false;
  343.                 } else if (found.size() > 1) {
  344.                     std::cout << "Ambiguous move" << std::endl;
  345.                     for (size_t i = 0; i < found.size(); i++)
  346.                         printNodeInfo(found[i]);
  347.                     doPrint = false;
  348.                 } else {
  349.                     currIndex = found[0];
  350.                 }
  351.             } else
  352.                 doPrint = false;
  353.         } else if (startsWith(cmdStr, "u")) {
  354.             int n = getArg(cmdStr, 1);
  355.             for (int i = 0; i < n; i++)
  356.                 currIndex = findParent(currIndex);
  357.         } else if (startsWith(cmdStr, "lp")) {
  358.             std::vector<int> args;
  359.             getArgs(cmdStr, 0, args);
  360.             if (args.size() == 2) {
  361.                 int th = args[0];
  362.                 U64 idx = args[1];
  363.                 std::vector<U64> positions;
  364.                 findChildren(-1, positions);
  365.                 for (size_t p = 0; p < positions.size(); p++) {
  366.                     U64 posIdx = positions[p];
  367.                     Position pos;
  368.                     int owningThread, moveNo;
  369.                     U64 parentIndex;
  370.                     U64 t0Index;
  371.                     getRootNode(posIdx, pos, owningThread, parentIndex, moveNo, t0Index);
  372.                     if ((owningThread == th) && (parentIndex == idx)) {
  373.                         printNodeInfo(posIdx, p);
  374.                         std::vector<U64> children;
  375.                         findChildren(posIdx, children);
  376.                         for (size_t c = 0; c < children.size(); c++)
  377.                             printNodeInfo(children[c], c);
  378.                     }
  379.                 }
  380.             }
  381.             doPrint = false;
  382.         } else if (startsWith(cmdStr, "l")) {
  383.             std::vector<U64> children;
  384.             findChildren(currIndex, children);
  385.             if (currIndex >= 0) {
  386.                 bool onlyBest = startsWith(cmdStr, "lb");
  387.                 std::string m = getArgStr(cmdStr, "");
  388.                 if (onlyBest) {
  389.                     int bestDepth = -1;
  390.                     int bestScore = std::numeric_limits<int>::min();
  391.                     for (size_t i = 0; i < children.size(); i++) {
  392.                         StartEntry se {};
  393.                         EndEntry ee {};
  394.                         bool haveEE = readEntries((int)children[i], se, ee); // Pierre-Marie Baty -- added type cast
  395.                         if (!haveEE || (ee.scoreType == TType::T_GE) || isNoMove(se.getMove()))
  396.                             continue;
  397.                         int d = se.depth;
  398.                         if ((ee.scoreType == TType::T_EXACT) && (ee.score > se.beta))
  399.                             continue;
  400.                         if ((d > bestDepth) || ((d == bestDepth) && (-ee.score > bestScore))) {
  401.                             bool falseFH = false;
  402.                             if (ee.scoreType == TType::T_LE) {
  403.                                 for (size_t ci = i+1; ci < children.size(); ci++) {
  404.                                     StartEntry se2 {};
  405.                                     EndEntry ee2 {};
  406.                                     bool haveEE2 = readEntries((int)children[ci], se2, ee2); // Pierre-Marie Baty -- added type cast
  407.                                     if (!haveEE2 || !(se2.move == se.move))
  408.                                         break;
  409.                                     if ((ee2.scoreType == TType::T_GE) ||
  410.                                         ((ee2.scoreType == TType::T_EXACT) && (ee2.score > ee.score))) {
  411.                                         falseFH = true;
  412.                                         break;
  413.                                     }
  414.                                     if (ee2.scoreType == TType::T_EXACT)
  415.                                         break;
  416.                                 }
  417.                             }
  418.                             if (!falseFH) {
  419.                                 printNodeInfo(children[i], i, m);
  420.                                 bestDepth = d;
  421.                                 bestScore = -ee.score;
  422.                             }
  423.                         }
  424.                     }
  425.                 } else {
  426.                     for (size_t i = 0; i < children.size(); i++)
  427.                         printNodeInfo(children[i], i, m);
  428.                 }
  429.             } else {
  430.                 for (size_t i = 0; i < children.size(); i++)
  431.                     printNodeInfo(children[i], i);
  432.             }
  433.             doPrint = false;
  434.         } else if (startsWith(cmdStr, "n")) {
  435.             if (currIndex >= 0) {
  436.                 std::vector<U64> nodes;
  437.                 getNodeSequence(currIndex, nodes);
  438.                 for (size_t i = 0; i < nodes.size(); i++)
  439.                     printNodeInfo(nodes[i]);
  440.             }
  441.             doPrint = false;
  442.         } else if (startsWith(cmdStr, "d")) {
  443.             std::vector<int> nVec;
  444.             getArgs(cmdStr, 0, nVec);
  445.             for (int n : nVec) {
  446.                 std::vector<U64> children;
  447.                 findChildren(currIndex, children);
  448.                 if ((n >= 0) && (n < (int)children.size())) {
  449.                     currIndex = children[n];
  450.                 } else
  451.                     break;
  452.             }
  453.         } else if (startsWith(cmdStr, "p")) {
  454.             if (currIndex >= 0) {
  455.                 std::vector<Move> moves;
  456.                 getMoveSequence(currIndex, moves);
  457.                 for (size_t i = 0; i < moves.size(); i++)
  458.                     std::cout << ' ' << moveToStr(moves[i]);
  459.                 std::cout << std::endl;
  460.             }
  461.             doPrint = false;
  462.         } else if (startsWith(cmdStr, "h")) {
  463.             bool onlyPrev = startsWith(cmdStr, "hp");
  464.             U64 hashKey = currIndex >= 0 ? getPosition(currIndex).historyHash() : (U64)-1;
  465.             hashKey = getHashKey(cmdStr, hashKey);
  466.             std::vector<U64> nodes;
  467.             getNodesForHashKey(hashKey, nodes, onlyPrev ? currIndex+1 : numEntries);
  468.             for (size_t i = 0; i < nodes.size(); i++)
  469.                 printNodeInfo(nodes[i]);
  470.             doPrint = false;
  471.         } else {
  472.             S64 i;
  473.             if (str2Num(cmdStr, i))
  474.                 if ((i >= -1) && (i < (S64)numEntries))
  475.                     currIndex = i;
  476.         }
  477.         prevStr = cmdStr;
  478.     }
  479. }
  480.  
  481. bool
  482. TreeLoggerReader::isMove(std::string cmdStr) const {
  483.     if (cmdStr.length() != 4)
  484.         return false;
  485.     cmdStr = toLowerCase(cmdStr);
  486.     for (int i = 0; i < 4; i++) {
  487.         int c = cmdStr[i];
  488.         if ((i == 0) || (i == 2)) {
  489.             if ((c < 'a') || (c > 'h'))
  490.                 return false;
  491.         } else {
  492.             if ((c < '1') || (c > '8'))
  493.                 return false;
  494.         }
  495.     }
  496.     return true;
  497. }
  498.  
  499. void
  500. TreeLoggerReader::getNodesForHashKey(U64 hashKey, std::vector<U64>& nodes, U64 maxEntry) {
  501.     Position pos;
  502.     for (U64 index = 0; index < maxEntry; index++) {
  503.         readEntry(index, entry);
  504.         if (entry.type == EntryType::NODE_END) {
  505.             if (entry.ee.hashKey == hashKey)
  506.                 nodes.push_back(entry.ee.startIndex);
  507.         } else if (entry.type == EntryType::POSITION_PART0) {
  508.             getRootNode(index, pos);
  509.             if (pos.historyHash() == hashKey)
  510.                 nodes.push_back(index);
  511.         }
  512.     }
  513.     std::sort(nodes.begin(), nodes.end());
  514. }
  515.  
  516. U64
  517. TreeLoggerReader::getHashKey(std::string& s, U64 defKey) const {
  518.     U64 key = defKey;
  519.     size_t idx = s.find_first_of(' ');
  520.     if (idx != s.npos) {
  521.         s = s.substr(idx + 1);
  522.         if (startsWith(s, "0x"))
  523.             s = s.substr(2);
  524.         hexStr2Num(s, key);
  525.     }
  526.     return key;
  527. }
  528.  
  529. int
  530. TreeLoggerReader::getArg(const std::string& s, int defVal) {
  531.     size_t idx = s.find_first_of(' ');
  532.     if (idx != s.npos) {
  533.         int tmp;
  534.         if (str2Num(s.substr(idx+1), tmp))
  535.             return tmp;
  536.     }
  537.     return defVal;
  538. }
  539.  
  540. void
  541. TreeLoggerReader::getArgs(const std::string& s, int defVal, std::vector<int>& args) {
  542.     std::vector<std::string> split;
  543.     splitString(s, split);
  544.     for (size_t i = 1; i < split.size(); i++) {
  545.         int tmp;
  546.         if (!str2Num(split[i], tmp)) {
  547.             args.clear();
  548.             break;
  549.         }
  550.         args.push_back(tmp);
  551.     }
  552.     if (args.empty())
  553.         args.push_back(defVal);
  554. }
  555.  
  556. std::string
  557. TreeLoggerReader::getArgStr(const std::string& s, const std::string& defVal) {
  558.     size_t idx = s.find_first_of(' ');
  559.     if (idx != s.npos)
  560.         return s.substr(idx+1);
  561.     return defVal;
  562. }
  563.  
  564. void
  565. TreeLoggerReader::printHelp() {
  566.     std::cout << "  p              - Print move sequence" << std::endl;
  567.     std::cout << "  n              - Print node info corresponding to move sequence" << std::endl;
  568.     std::cout << "  l [move]       - List child nodes, optionally only for one move" << std::endl;
  569.     std::cout << "  lb [move]      - List best child nodes, optionally only for one move" << std::endl;
  570.     std::cout << "  lp th idx      - List positions requested by thread th at index idx" << std::endl;
  571.     std::cout << "  d [n1 [n2...]] - Go to child \"n\"" << std::endl;
  572.     std::cout << "  move           - Go to child \"move\", if unique" << std::endl;
  573.     std::cout << "  u [levels]     - Move up" << std::endl;
  574.     std::cout << "  h [key]        - Find nodes with current or given hash key" << std::endl;
  575.     std::cout << "  hp [key]       - Find nodes with current or given hash key before current node" << std::endl;
  576.     std::cout << "  num            - Go to node \"num\"" << std::endl;
  577.     std::cout << "  q              - Quit" << std::endl;
  578.     std::cout << "  ?              - Print this help" << std::endl;
  579. }
  580.  
  581. bool
  582. TreeLoggerReader::readEntries(int index, StartEntry& se, EndEntry& ee) {
  583.     readEntry(index, entry);
  584.     if (entry.type == EntryType::NODE_START) {
  585.         se = entry.se;
  586.         U32 eIdx = se.endIndex;
  587.         if (eIdx == endMark)
  588.             return false;
  589.         readEntry(eIdx, entry);
  590.         assert(entry.type == EntryType::NODE_END);
  591.         ee = entry.ee;
  592.     } else {
  593.         assert(entry.type == EntryType::NODE_END);
  594.         ee = entry.ee;
  595.         readEntry(ee.startIndex, entry);
  596.         assert(entry.type == EntryType::NODE_START);
  597.         se = entry.se;
  598.     }
  599.     return true;
  600. }
  601.  
  602. S64
  603. TreeLoggerReader::findParent(S64 index) {
  604.     if (index < 0)
  605.         return -1;
  606.     readEntry(index, entry);
  607.     if (entry.type == EntryType::NODE_END) {
  608.         index = entry.ee.startIndex;
  609.         readEntry(index, entry);
  610.     }
  611.     if (entry.type == EntryType::NODE_START) {
  612.         return entry.se.parentIndex;
  613.     } else if ((entry.type == EntryType::POSITION_PART0) ||
  614.                (entry.type == EntryType::POSITION_PART1) ||
  615.                (entry.type == EntryType::POSITION_PART2)) {
  616.         return -1;
  617.     } else {
  618.         assert(false);
  619.         return -1;
  620.     }
  621. }
  622.  
  623. void
  624. TreeLoggerReader::findChildren(S64 index, std::vector<U64>& childs) {
  625.     if (index < 0) {
  626.         if (numEntries == 0)
  627.             return;
  628.         U64 child = 0;
  629.         while (child < numEntries - 1) {
  630.             readEntry(child, entry);
  631.             assert(entry.type == EntryType::POSITION_PART0);
  632.             childs.push_back(child);
  633.             child = entry.p0.nextIndex;
  634.         }
  635.     } else {
  636.         readEntry(index, entry);
  637.         U64 child;
  638.         switch (entry.type) {
  639.         case EntryType::NODE_END:
  640.             index = entry.ee.startIndex;
  641.             // Fall through
  642.         case EntryType::NODE_START:
  643.             child = index + 1;
  644.             break;
  645.         case EntryType::POSITION_PART2:
  646.             index--;
  647.             // Fall through
  648.         case EntryType::POSITION_PART1:
  649.             index--;
  650.             // Fall through
  651.         case EntryType::POSITION_PART0:
  652.             child = index + 3;
  653.             break;
  654.         default:
  655.             assert(false);
  656.         }
  657.         StartEntry se {};
  658.         EndEntry ee {};
  659.         while (child < numEntries) {
  660.             readEntry(child, entry);
  661.             if (entry.type != EntryType::NODE_START)
  662.                 break;
  663.             bool haveEE = readEntries((int)child, se, ee); // Pierre-Marie Baty -- added type cast
  664.             if (se.parentIndex == index)
  665.                 childs.push_back(child);
  666.             if (!haveEE)
  667.                 break;
  668.             if (se.endIndex == endMark)
  669.                 break;
  670.             child = se.endIndex + 1;
  671.         }
  672.     }
  673. }
  674.  
  675. int
  676. TreeLoggerReader::getChildNo(U64 index) {
  677.     readEntry(index, entry);
  678.     if (entry.type == EntryType::NODE_END) {
  679.         index = entry.ee.startIndex;
  680.         readEntry(index, entry);
  681.     } else if (entry.type == EntryType::POSITION_PART1) {
  682.         index--;
  683.         readEntry(index, entry);
  684.     } else if (entry.type == EntryType::POSITION_PART2) {
  685.         index -= 2;
  686.         readEntry(index, entry);
  687.     }
  688.     std::vector<U64> childs;
  689.     if (entry.type == EntryType::NODE_START) {
  690.         findChildren(entry.se.parentIndex, childs);
  691.     } else if (entry.type == EntryType::POSITION_PART0) {
  692.         findChildren(-1, childs);
  693.     } else
  694.         assert(false);
  695.  
  696.     for (int i = 0; i < (int)childs.size(); i++)
  697.         if (childs[i] == index)
  698.             return i;
  699.     return -1;
  700. }
  701.  
  702. void
  703. TreeLoggerReader::getNodeSequence(U64 index, std::vector<U64>& nodes) {
  704.     nodes.push_back(index);
  705.     while (true) {
  706.         readEntry(index, entry);
  707.         if (entry.type == EntryType::NODE_END) {
  708.             index = entry.ee.startIndex;
  709.             readEntry(index, entry);
  710.         }
  711.         if (entry.type == EntryType::NODE_START) {
  712.             index = entry.se.parentIndex;
  713.             nodes.push_back(index);
  714.         } else
  715.             break;
  716.     }
  717.     std::reverse(nodes.begin(), nodes.end());
  718. }
  719.  
  720. U64
  721. TreeLoggerReader::getMoveSequence(U64 index, std::vector<Move>& moves) {
  722.     StartEntry se {};
  723.     EndEntry ee {};
  724.     while (true) {
  725.         readEntry(index, entry);
  726.         if ((entry.type == EntryType::NODE_START) ||
  727.             (entry.type == EntryType::NODE_END)) {
  728.             readEntries((int)index, se, ee); // Pierre-Marie Baty -- added type cast
  729.             moves.push_back(se.getMove());
  730.             index = findParent(index);
  731.         } else
  732.             break;
  733.     }
  734.     std::reverse(moves.begin(), moves.end());
  735.     return index;
  736. }
  737.  
  738. Position
  739. TreeLoggerReader::getPosition(U64 index) {
  740.     std::vector<Move> moves;
  741.     U64 rootPosIdx = getMoveSequence(index, moves);
  742.     Position pos;
  743.     getRootNode(rootPosIdx, pos);
  744.     UndoInfo ui;
  745.     for (size_t i = 0; i < moves.size(); i++)
  746.         if (!isNoMove(moves[i]))
  747.             pos.makeMove(moves[i], ui);
  748.     return pos;
  749. }
  750.  
  751. void
  752. TreeLoggerReader::printNodeInfo(U64 index, int childNo, const std::string& filterMove) {
  753.     if (childNo == -1)
  754.         childNo = getChildNo(index);
  755.     readEntry(index, entry);
  756.     if ((entry.type == EntryType::NODE_START) ||
  757.         (entry.type == EntryType::NODE_END)) {
  758.         StartEntry se {};
  759.         EndEntry ee {};
  760.         bool haveEE = readEntries((int)index, se, ee); // Pierre-Marie Baty -- added type cast
  761.         std::string m = moveToStr(se.getMove());
  762.         if ((filterMove.length() > 0) && (m != filterMove))
  763.             return;
  764.         using SearchConst::plyScale;
  765.         std::cout << std::setw(3) << childNo
  766.                   << ' '   << std::setw(8) << index
  767.                   << ' '   << std::setw(8) << se.t0Index
  768.                   << ' '   << std::setw(8) << ee.t0Index
  769.                   << ' '   << m
  770.                   << " a:" << std::setw(6) << se.alpha
  771.                   << " b:" << std::setw(6) << se.beta
  772.                   << " p:" << std::setw(2) << (int)se.ply
  773.                   << " d:" << std::setw(2) << (int)se.depth/plyScale
  774.                            << '.' << ((int)se.depth % plyScale);
  775.         if (haveEE) {
  776.             int subTreeNodes = (se.endIndex - ee.startIndex - 1) / 2;
  777.             std::string type;
  778.             switch (ee.scoreType) {
  779.             case TType::T_EXACT: type = "= "; break;
  780.             case TType::T_GE   : type = ">="; break;
  781.             case TType::T_LE   : type = "<="; break;
  782.             default            : type = "  "; break;
  783.             }
  784.             std::cout << " s:" << type << std::setw(6) << ee.score
  785.                     << " e:" << std::setw(6) << ee.evalScore
  786.                     << " sub:" << subTreeNodes;
  787.         }
  788.         std::cout << std::endl;
  789.     } else if ((entry.type == EntryType::POSITION_PART0) ||
  790.                (entry.type == EntryType::POSITION_PART1) ||
  791.                (entry.type == EntryType::POSITION_PART2)) {
  792.         Position pos;
  793.         int owningThread, moveNo;
  794.         U64 parentIndex;
  795.         U64 t0Index;
  796.         getRootNode(index, pos, owningThread, parentIndex, moveNo, t0Index);
  797.         std::cout << std::setw(3) << childNo
  798.                   << ' ' << std::setw(8) << index
  799.                   << ' ' << owningThread
  800.                   << ' ' << std::setw(8) << parentIndex
  801.                   << ' ' << std::setw(2) << moveNo
  802.                   << ' ' << std::setw(8) << t0Index
  803.                   << ' ' << TextIO::toFEN(pos) << std::endl;
  804.     } else
  805.         assert(false);
  806. }
  807.