Subversion Repositories Games.Chess Giants

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 pmbaty 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
}