From 08b04b062b88cc0442225677e97cf1fb04df3270 Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 01:29:53 +0800 Subject: [PATCH 1/9] add problem solve analyze mode --- .vscode/settings.json | 5 ++++ cpp/command/gtp.cpp | 31 +++++++++++++++++++++---- cpp/search/asyncbot.cpp | 16 +++++++++++++ cpp/search/asyncbot.h | 3 +++ cpp/search/search.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ cpp/search/search.h | 7 ++++++ 6 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..1507357bc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "functional": "cpp" + } +} \ No newline at end of file diff --git a/cpp/command/gtp.cpp b/cpp/command/gtp.cpp index 996c4bf1a..66b49837e 100644 --- a/cpp/command/gtp.cpp +++ b/cpp/command/gtp.cpp @@ -585,7 +585,12 @@ struct GTPEngine { int minMoves = 0; int maxMoves = 10000000; bool showOwnership = false; + bool isProblemAnalyze = false; + Loc problemAnalyzeTopLeftCorner = Board::NULL_LOC; + Loc problemAnalyzeBottomRightCorner = Board::NULL_LOC; + double secondsPerReport = 1e30; + }; std::function getAnalyzeCallback(Player pla, AnalyzeArgs args) { @@ -1010,7 +1015,16 @@ struct GTPEngine { bot->setAlwaysIncludeOwnerMap(true); else bot->setAlwaysIncludeOwnerMap(false); - + if (args.isProblemAnalyze) { + bot->setProblemAnalyze(true); + bot->setProblemAnalyzeTopLeftCorner(args.problemAnalyzeTopLeftCorner); + bot->setProblemAnalyzeBottomRightCorner(args.problemAnalyzeBottomRightCorner); + } else { + bot->setProblemAnalyze(false); + bot->setProblemAnalyzeTopLeftCorner(Board::NULL_LOC); + bot->setProblemAnalyzeBottomRightCorner(Board::NULL_LOC); + } + double searchFactor = 1e40; //go basically forever bot->analyze(pla, searchFactor, args.secondsPerReport, callback); } @@ -1158,12 +1172,13 @@ static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const v int numArgsParsed = 0; bool isLZ = (command == "lz-analyze" || command == "lz-genmove_analyze"); - bool isKata = (command == "kata-analyze" || command == "kata-genmove_analyze"); + bool isKata = (command == "kata-analyze" || command == "kata-genmove_analyze" || command == "kata-problem_analyze"); double lzAnalyzeInterval = 1e30; int minMoves = 0; int maxMoves = 10000000; bool showOwnership = false; - + Loc problemAnalyzeTopLeftCorner = Board::NULL_LOC; + Loc problemAnalyzeBottomRightCorner = Board::NULL_LOC; parseFailed = false; //Format: @@ -1228,6 +1243,10 @@ static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const v } else if(isKata && key == "ownership" && Global::tryStringToBool(value,showOwnership)) { continue; + } else if(isKata && key == "topleft" && Location::tryOfString(value, bot->getRootBoard(), problemAnalyzeTopLeftCorner)) { + continue; + } else if(isKata && key == "bottomright" && Location::tryOfString(value, bot->getRootBoard(), problemAnalyzeBottomRightCorner)) { + continue; } parseFailed = true; @@ -1243,6 +1262,10 @@ static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const v args.minMoves = minMoves; args.maxMoves = maxMoves; args.showOwnership = showOwnership; + args.problemAnalyzeTopLeftCorner = problemAnalyzeTopLeftCorner; + args.problemAnalyzeBottomRightCorner = problemAnalyzeBottomRightCorner; + args.isProblemAnalyze = command == "kata-problem_analyze"; + return args; } @@ -2337,7 +2360,7 @@ int MainCmds::gtp(int argc, const char* const* argv) { } } - else if(command == "analyze" || command == "lz-analyze" || command == "kata-analyze") { + else if(command == "analyze" || command == "lz-analyze" || command == "kata-analyze" || command == "kata-problem_analyze") { Player pla = engine->bot->getRootPla(); bool parseFailed = false; GTPEngine::AnalyzeArgs args = parseAnalyzeCommand(command, pieces, pla, parseFailed); diff --git a/cpp/search/asyncbot.cpp b/cpp/search/asyncbot.cpp index f90481b67..09ee9b2a6 100644 --- a/cpp/search/asyncbot.cpp +++ b/cpp/search/asyncbot.cpp @@ -87,6 +87,22 @@ void AsyncBot::setAlwaysIncludeOwnerMap(bool b) { stopAndWait(); search->setAlwaysIncludeOwnerMap(b); } + +void AsyncBot::setProblemAnalyze(bool b) { + stopAndWait(); + search->setProblemAnalyze(b); +} + +void AsyncBot::setProblemAnalyzeTopLeft(Loc b) { + stopAndWait(); + search->setProblemAnalyzeTopLeft(b); +} + +void AsyncBot::setProblemAnalyzeBottomRightCorner(Loc b) { + stopAndWait(); + search->setProblemAnalyzeBottomRightCorner(b); +} + void AsyncBot::setParams(SearchParams params) { stopAndWait(); search->setParams(params); diff --git a/cpp/search/asyncbot.h b/cpp/search/asyncbot.h index fe7235a13..e5c9be76f 100644 --- a/cpp/search/asyncbot.h +++ b/cpp/search/asyncbot.h @@ -33,6 +33,9 @@ class AsyncBot { void setRootPassLegal(bool b); void setRootHintLoc(Loc loc); void setAlwaysIncludeOwnerMap(bool b); + void setProblemAnalyze(bool b); + void setProblemAnalyzeTopLeftCorner(Loc b); + void setProblemAnalyzeBottomRightCorner(Loc b); void setParams(SearchParams params); void setPlayerIfNew(Player movePla); void clearSearch(); diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index 5da8e416b..6b258d213 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -144,6 +144,9 @@ Search::Search(SearchParams params, NNEvaluator* nnEval, const string& rSeed) rootSafeArea(NULL), recentScoreCenter(0.0), alwaysIncludeOwnerMap(false), + isProblemAnalyze(false), + problemAnalyzeTopLeftCorner(Board::NULL_LOC), + problemAnalyzeBottomRightCorner(Board::NULL_LOC), searchParams(params),numSearchesBegun(0),searchNodeAge(0), plaThatSearchIsFor(C_EMPTY),plaThatSearchIsForLastSearch(C_EMPTY), lastSearchNumPlayouts(0), @@ -243,6 +246,24 @@ void Search::setAlwaysIncludeOwnerMap(bool b) { clearSearch(); alwaysIncludeOwnerMap = b; } +void Search::setProblemAnalyze(bool b) { + if(!isProblemAnalyze && b) + clearSearch(); + isProblemAnalyze = b; +} + +void Search::setProblemAnalyzeTopLeftCorner(Loc b) { + if (problemAnalyzeTopLeftCorner != b) + clearSearch(); + problemAnalyzeTopLeftCorner = b; +} + +void Search::setProblemAnalyzeBottomRightCorner(Loc b) { + if (problemAnalyzeBottomRightCorner != b) + clearSearch(); + problemAnalyzeBottomRightCorner = b; +} + void Search::setParams(SearchParams params) { clearSearch(); @@ -957,6 +978,33 @@ void Search::maybeAddPolicyNoiseAndTempAlreadyLocked(SearchThread& thread, Searc } } +bool search::isInProblemArea(Loc moveLoc) const { + assert(moveLoc == Board::PASS_LOC || rootBoard.isOnBoard(moveLoc)); + if (problemAnalyzeTopLeftCorner == Board::NULL_LOC || problemAnalyzeBottomRightCorner == Board::NULL_LOC) { + // not limit + return true; + } + int x = Location::getX(moveLoc); + int y = Location::getY(moveLoc); + int x1 = Location::getX(problemAnalyzeTopLeftCorner); + int x2 = Location::getX(problemAnalyzeBottomRightCorner); + int y1 = Location::getY(problemAnalyzeTopLeftCorner); + int y2 = Location::getY(problemAnalyzeBottomRightCorner); + if (x1 > x2) { + // swap + int tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y1 > y2) { + // swap + int tmp = y1; + y1 = y2; + y2 = tmp; + } + return x >= x1 && x <= x2 && y >= y1 && y <= y2; +} + bool Search::isAllowedRootMove(Loc moveLoc) const { assert(moveLoc == Board::PASS_LOC || rootBoard.isOnBoard(moveLoc)); @@ -1428,6 +1476,9 @@ void Search::selectBestChildToDescend( if(moveLoc == Board::NULL_LOC) continue; + if(isProblemAnalyze && !isInProblemArea(moveLoc)) + continue; + //Special logic for the root if(isRoot) { assert(thread.board.pos_hash == rootBoard.pos_hash); diff --git a/cpp/search/search.h b/cpp/search/search.h index 7c7adf4c6..f3e018b3d 100644 --- a/cpp/search/search.h +++ b/cpp/search/search.h @@ -147,6 +147,10 @@ struct Search { bool alwaysIncludeOwnerMap; + bool isProblemAnalyze; + Loc problemAnalyzeTopLeftCorner; + Loc problemAnalyzeBottomRightCorner; + SearchParams searchParams; int64_t numSearchesBegun; uint32_t searchNodeAge; @@ -201,6 +205,9 @@ struct Search { void setKomiIfNew(float newKomi); //Does not clear history, does clear search unless komi is equal. void setRootPassLegal(bool b); void setRootHintLoc(Loc hintLoc); + void setProblemAnalyze(bool b); + void setProblemAnalyzeTopLeftCorner(Loc b); + void setProblemAnalyzeBottomRightCorner(Loc b); void setAlwaysIncludeOwnerMap(bool b); void setParams(SearchParams params); void setParamsNoClearing(SearchParams params); //Does not clear search From 1f069f687b6282ae4b2ffcc0469f352cfb4acd22 Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 01:51:02 +0800 Subject: [PATCH 2/9] make compiled --- cpp/command/gtp.cpp | 13 ++++++++----- cpp/search/asyncbot.cpp | 4 ++-- cpp/search/search.cpp | 14 +++++++------- cpp/search/search.h | 3 ++- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/cpp/command/gtp.cpp b/cpp/command/gtp.cpp index 66b49837e..f22ca1e6a 100644 --- a/cpp/command/gtp.cpp +++ b/cpp/command/gtp.cpp @@ -1168,7 +1168,10 @@ struct GTPEngine { //User should pre-fill pla with a default value, as it will not get filled in if the parsed command doesn't specify -static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const vector& pieces, Player& pla, bool& parseFailed) { +static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const vector& pieces, GTPEngine* engine, bool& parseFailed) { + Player pla = engine->bot->getRootPla(); + Board board = engine->bot->getRootBoard(); + int numArgsParsed = 0; bool isLZ = (command == "lz-analyze" || command == "lz-genmove_analyze"); @@ -1243,9 +1246,9 @@ static GTPEngine::AnalyzeArgs parseAnalyzeCommand(const string& command, const v } else if(isKata && key == "ownership" && Global::tryStringToBool(value,showOwnership)) { continue; - } else if(isKata && key == "topleft" && Location::tryOfString(value, bot->getRootBoard(), problemAnalyzeTopLeftCorner)) { + } else if(isKata && key == "topleft" && Location::tryOfString(value, board, problemAnalyzeTopLeftCorner)) { continue; - } else if(isKata && key == "bottomright" && Location::tryOfString(value, bot->getRootBoard(), problemAnalyzeBottomRightCorner)) { + } else if(isKata && key == "bottomright" && Location::tryOfString(value, board, problemAnalyzeBottomRightCorner)) { continue; } @@ -2022,7 +2025,7 @@ int MainCmds::gtp(int argc, const char* const* argv) { else if(command == "genmove_analyze" || command == "lz-genmove_analyze" || command == "kata-genmove_analyze") { Player pla = engine->bot->getRootPla(); bool parseFailed = false; - GTPEngine::AnalyzeArgs args = parseAnalyzeCommand(command, pieces, pla, parseFailed); + GTPEngine::AnalyzeArgs args = parseAnalyzeCommand(command, pieces, engine, parseFailed); if(parseFailed) { responseIsError = true; response = "Could not parse genmove_analyze arguments or arguments out of range: '" + Global::concat(pieces," ") + "'"; @@ -2363,7 +2366,7 @@ int MainCmds::gtp(int argc, const char* const* argv) { else if(command == "analyze" || command == "lz-analyze" || command == "kata-analyze" || command == "kata-problem_analyze") { Player pla = engine->bot->getRootPla(); bool parseFailed = false; - GTPEngine::AnalyzeArgs args = parseAnalyzeCommand(command, pieces, pla, parseFailed); + GTPEngine::AnalyzeArgs args = parseAnalyzeCommand(command, pieces, engine, parseFailed); if(parseFailed) { responseIsError = true; diff --git a/cpp/search/asyncbot.cpp b/cpp/search/asyncbot.cpp index 09ee9b2a6..1660424a1 100644 --- a/cpp/search/asyncbot.cpp +++ b/cpp/search/asyncbot.cpp @@ -93,9 +93,9 @@ void AsyncBot::setProblemAnalyze(bool b) { search->setProblemAnalyze(b); } -void AsyncBot::setProblemAnalyzeTopLeft(Loc b) { +void AsyncBot::setProblemAnalyzeTopLeftCorner(Loc b) { stopAndWait(); - search->setProblemAnalyzeTopLeft(b); + search->setProblemAnalyzeTopLeftCorner(b); } void AsyncBot::setProblemAnalyzeBottomRightCorner(Loc b) { diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index 6b258d213..28c4d5964 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -978,18 +978,18 @@ void Search::maybeAddPolicyNoiseAndTempAlreadyLocked(SearchThread& thread, Searc } } -bool search::isInProblemArea(Loc moveLoc) const { +bool Search::isInProblemArea(Loc moveLoc) const { assert(moveLoc == Board::PASS_LOC || rootBoard.isOnBoard(moveLoc)); if (problemAnalyzeTopLeftCorner == Board::NULL_LOC || problemAnalyzeBottomRightCorner == Board::NULL_LOC) { // not limit return true; } - int x = Location::getX(moveLoc); - int y = Location::getY(moveLoc); - int x1 = Location::getX(problemAnalyzeTopLeftCorner); - int x2 = Location::getX(problemAnalyzeBottomRightCorner); - int y1 = Location::getY(problemAnalyzeTopLeftCorner); - int y2 = Location::getY(problemAnalyzeBottomRightCorner); + int x = Location::getX(moveLoc, rootBoard.x_size); + int y = Location::getY(moveLoc, rootBoard.x_size); + int x1 = Location::getX(problemAnalyzeTopLeftCorner, rootBoard.x_size); + int x2 = Location::getX(problemAnalyzeBottomRightCorner, rootBoard.x_size); + int y1 = Location::getY(problemAnalyzeTopLeftCorner, rootBoard.x_size); + int y2 = Location::getY(problemAnalyzeBottomRightCorner, rootBoard.x_size); if (x1 > x2) { // swap int tmp = x1; diff --git a/cpp/search/search.h b/cpp/search/search.h index f3e018b3d..27a54908f 100644 --- a/cpp/search/search.h +++ b/cpp/search/search.h @@ -327,7 +327,8 @@ struct Search { int getPos(Loc moveLoc) const; bool isAllowedRootMove(Loc moveLoc) const; - + bool isInProblemArea(Loc moveLoc) const; + void computeRootValues(); double getScoreUtility(double scoreMeanSum, double scoreMeanSqSum, double weightSum) const; From e4b2b188d844b8dc17d1b4beaae71191caf90f6b Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 08:13:46 +0800 Subject: [PATCH 3/9] add new knwon command --- cpp/command/gtp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/command/gtp.cpp b/cpp/command/gtp.cpp index f22ca1e6a..34f4c2e90 100644 --- a/cpp/command/gtp.cpp +++ b/cpp/command/gtp.cpp @@ -69,7 +69,7 @@ static const vector knownCommands = { // "analyze", "lz-analyze", "kata-analyze", - + "kata-problem_analyze", //Display raw neural net evaluations "kata-raw-nn", From 110e8cf95f98220eea0290f5b05189abe661c446 Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 14:54:51 +0800 Subject: [PATCH 4/9] fixes --- .gitignore | 3 ++- .vscode/settings.json | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 29b52cbf6..1cb085c06 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ __pycache__ *.cbp tmp*.txt - +test/ +.vscode/ cpp/write cpp/runtests cpp/example diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 1507357bc..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "functional": "cpp" - } -} \ No newline at end of file From 59a198a605acb22363265c22ce2d883ceadf873d Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 16:04:13 +0800 Subject: [PATCH 5/9] add wrong condition --- cpp/search/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index 28c4d5964..b7df8c41e 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -1849,7 +1849,7 @@ void Search::playoutDescend( //The absurdly rare case that the move chosen is not legal //(this should only happen either on a bug or where the nnHash doesn't have full legality information or when there's an actual hash collision). //Regenerate the neural net call and continue - if(!thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla)) { + if(!thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla) && !isProblemAnalyze) { bool isReInit = true; initNodeNNOutput(thread,node,isRoot,true,0,isReInit); From ddd598b2c6d11ccbe1f1e4cb378d169e196df05b Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sat, 27 Jun 2020 18:03:43 +0800 Subject: [PATCH 6/9] update readme --- docs/GTP_Extensions.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/GTP_Extensions.md b/docs/GTP_Extensions.md index 12b1e6ab7..512094e3d 100644 --- a/docs/GTP_Extensions.md +++ b/docs/GTP_Extensions.md @@ -104,7 +104,15 @@ In addition to a basic set of [GTP commands](https://www.lysator.liu.se/~gunnar/ * Like `lz-analyze`, will immediately begin printing a partial GTP response, with a new line every `interval` centiseconds. * Unlike `lz-analyze`, will teriminate on its own after the normal amount of time that a `genmove` would take and will NOT terminate prematurely or asynchronously upon recipt of a newline or an additional GTP command. * The final move made will be reported as a single line `play `, followed by the usual double-newline that signals a complete GTP response. - * `kata-genmove_analyze [player (optional)] [interval (optional)] KEYVALUEPAIR KEYVALUEPAIR` + * `kata-problem_analyze [player (optional)] [interval (optional)] KEYVALUEPAIR KEYVALUEPAIR` + * this extented GTP command is used for solving life-dead problems. + * Same as `kata-analyze` except with the options and fields : + * Additional possible key-value pairs: + * `topleft M19` - Sets the problem valid area - the top left corner + * `bottomright T14` - Sets the problem valid area - the bottom right corner + * if `topoleft` or `bottomright` is not set, use the full board. + + * `kata-genmove_analyze [player (optional)] [interval (optional)] KEYVALUEPAIR KEYVALUEPAIR` * Same as `lz-genmove_analyze` except with the options and fields of `kata-analyze` rather than `lz-analyze` * `analyze, genmove_analyze` * Same as `kata-analyze` and `kata-genmove_analyze`, but intended specifically for the Sabaki GUI app in that all floating point values are always formatted with a decimal point, even when a value happens to be an integer. May also have slightly less compact output in other ways (e.g. extra trailing zeros on some decimals). From d805374095fc1e833084b3e80ae2422acd87796a Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sun, 28 Jun 2020 08:36:54 +0800 Subject: [PATCH 7/9] fix ko --- cpp/game/boardhistory.cpp | 14 +++++++++++ cpp/game/boardhistory.h | 1 + cpp/search/search.cpp | 49 +++++++++++++++++++++++++++------------ cpp/search/search.h | 3 ++- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/cpp/game/boardhistory.cpp b/cpp/game/boardhistory.cpp index 0b9271c73..54993a01d 100644 --- a/cpp/game/boardhistory.cpp +++ b/cpp/game/boardhistory.cpp @@ -730,6 +730,20 @@ bool BoardHistory::isLegal(const Board& board, Loc moveLoc, Player movePla) cons return true; } +bool BoardHistory::isLegalAllowSuperKo(const Board& board, Loc moveLoc, Player movePla) const { + //Ko-moves in the encore that are recapture blocked are interpreted as pass-for-ko, so they are legal + if(encorePhase > 0 && moveLoc >= 0 && moveLoc < Board::MAX_ARR_SIZE && moveLoc != Board::PASS_LOC) { + Loc koCaptureLoc = board.getKoCaptureLoc(moveLoc,movePla); + if(koCaptureLoc != Board::NULL_LOC && koRecapBlocked[koCaptureLoc] && board.colors[koCaptureLoc] == getOpp(movePla)) + return true; + } + + if(!board.isLegal(moveLoc,movePla,rules.multiStoneSuicideLegal)) + return false; + + return true; +} + bool BoardHistory::isPassForKo(const Board& board, Loc moveLoc, Player movePla) const { if(encorePhase > 0 && moveLoc >= 0 && moveLoc < Board::MAX_ARR_SIZE && moveLoc != Board::PASS_LOC) { Loc koCaptureLoc = board.getKoCaptureLoc(moveLoc,movePla); diff --git a/cpp/game/boardhistory.h b/cpp/game/boardhistory.h index 426323aa5..b162dca39 100644 --- a/cpp/game/boardhistory.h +++ b/cpp/game/boardhistory.h @@ -120,6 +120,7 @@ struct BoardHistory { //Check if a move on the board is legal, taking into account the full game state and superko bool isLegal(const Board& board, Loc moveLoc, Player movePla) const; + bool isLegalAllowSuperKo(const Board& board, Loc moveLoc, Player movePla) const; //Check if passing right now would end the current phase of play, or the entire game bool passWouldEndPhase(const Board& board, Player movePla) const; bool passWouldEndGame(const Board& board, Player movePla) const; diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index b7df8c41e..d18d83a22 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -1675,7 +1675,7 @@ void Search::recomputeNodeStats(SearchNode& node, SearchThread& thread, int numV void Search::runSinglePlayout(SearchThread& thread) { bool posesWithChildBuf[NNPos::MAX_NN_POLICY_SIZE]; - playoutDescend(thread,*rootNode,posesWithChildBuf,true,0); + playoutDescend(thread,*rootNode,posesWithChildBuf,true,0, 0); //Restore thread state back to the root state thread.pla = rootPla; @@ -1794,7 +1794,8 @@ void Search::initNodeNNOutput( void Search::playoutDescend( SearchThread& thread, SearchNode& node, bool posesWithChildBuf[NNPos::MAX_NN_POLICY_SIZE], - bool isRoot, int32_t virtualLossesToSubtract + bool isRoot, int32_t virtualLossesToSubtract, + int32_t depth ) { //Hit terminal node, finish //In the case where we're forcing the search to make another move at the root, don't terminate, actually run search for a move more. @@ -1849,19 +1850,35 @@ void Search::playoutDescend( //The absurdly rare case that the move chosen is not legal //(this should only happen either on a bug or where the nnHash doesn't have full legality information or when there's an actual hash collision). //Regenerate the neural net call and continue - if(!thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla) && !isProblemAnalyze) { - bool isReInit = true; - initNodeNNOutput(thread,node,isRoot,true,0,isReInit); - - if(thread.logStream != NULL) - (*thread.logStream) << "WARNING: Chosen move not legal so regenerated nn output, nnhash=" << node.nnOutput->nnHash << endl; - - //As isReInit is true, we don't return, just keep going, since we didn't count this as a true visit in the node stats - selectBestChildToDescend(thread,node,bestChildIdx,bestChildMoveLoc,posesWithChildBuf,isRoot); - //We should absolutely be legal this time - assert(thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla)); + if (isProblemAnalyze) { + if(!thread.history.isLegalAllowSuperKo(thread.board,bestChildMoveLoc,thread.pla)) { + bool isReInit = true; + initNodeNNOutput(thread,node,isRoot,true,0,isReInit); + + if(thread.logStream != NULL) + (*thread.logStream) << "WARNING: Chosen move not legal so regenerated nn output, nnhash=" << node.nnOutput->nnHash << endl; + + //As isReInit is true, we don't return, just keep going, since we didn't count this as a true visit in the node stats + selectBestChildToDescend(thread,node,bestChildIdx,bestChildMoveLoc,posesWithChildBuf,isRoot); + //We should absolutely be legal this time + assert(thread.history.isLegalAllowSuperKo(thread.board,bestChildMoveLoc,thread.pla)); + } + } else { + if(!thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla)) { + bool isReInit = true; + initNodeNNOutput(thread,node,isRoot,true,0,isReInit); + + if(thread.logStream != NULL) + (*thread.logStream) << "WARNING: Chosen move not legal so regenerated nn output, nnhash=" << node.nnOutput->nnHash << endl; + + //As isReInit is true, we don't return, just keep going, since we didn't count this as a true visit in the node stats + selectBestChildToDescend(thread,node,bestChildIdx,bestChildMoveLoc,posesWithChildBuf,isRoot); + //We should absolutely be legal this time + assert(thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla)); + } } + if(bestChildIdx < -1) { lock.unlock(); throw StringError("Search error: No move with sane selection value - can't even pass?"); @@ -1906,8 +1923,10 @@ void Search::playoutDescend( thread.pla = getOpp(thread.pla); //Recurse! - playoutDescend(thread,*child,posesWithChildBuf,false,searchParams.numVirtualLossesPerThread); - + if (!isProblemAnalyze || depth < 50) { + playoutDescend(thread,*child,posesWithChildBuf,false,searchParams.numVirtualLossesPerThread, depth + 1); + } + //Update this node stats updateStatsAfterPlayout(node,thread,virtualLossesToSubtract,isRoot); } diff --git a/cpp/search/search.h b/cpp/search/search.h index 27a54908f..0c1123d02 100644 --- a/cpp/search/search.h +++ b/cpp/search/search.h @@ -407,7 +407,8 @@ struct Search { void playoutDescend( SearchThread& thread, SearchNode& node, bool posesWithChildBuf[NNPos::MAX_NN_POLICY_SIZE], - bool isRoot, int32_t virtualLossesToSubtract + bool isRoot, int32_t virtualLossesToSubtract, + int32_t depth ); bool shouldSuppressPassAlreadyLocked(const SearchNode* n) const; From 5197b1dfb39dc77b43b65dfee5ba539237810e06 Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sun, 28 Jun 2020 08:46:47 +0800 Subject: [PATCH 8/9] fix ko --- cpp/search/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index d18d83a22..ce6ae1907 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -1881,6 +1881,7 @@ void Search::playoutDescend( if(bestChildIdx < -1) { lock.unlock(); + assert(false); throw StringError("Search error: No move with sane selection value - can't even pass?"); } From df019ee0291231453c7a4dd2494b12b1d819e690 Mon Sep 17 00:00:00 2001 From: kinfkong Date: Sun, 28 Jun 2020 08:48:29 +0800 Subject: [PATCH 9/9] fix ko --- cpp/search/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/search/search.cpp b/cpp/search/search.cpp index ce6ae1907..cc488a195 100644 --- a/cpp/search/search.cpp +++ b/cpp/search/search.cpp @@ -1860,8 +1860,8 @@ void Search::playoutDescend( //As isReInit is true, we don't return, just keep going, since we didn't count this as a true visit in the node stats selectBestChildToDescend(thread,node,bestChildIdx,bestChildMoveLoc,posesWithChildBuf,isRoot); - //We should absolutely be legal this time - assert(thread.history.isLegalAllowSuperKo(thread.board,bestChildMoveLoc,thread.pla)); + // We should absolutely be legal this time + // assert(thread.history.isLegalAllowSuperKo(thread.board,bestChildMoveLoc,thread.pla)); } } else { if(!thread.history.isLegal(thread.board,bestChildMoveLoc,thread.pla)) {