From 1985bee2a91e6d7154fedd60d74c05499e878b62 Mon Sep 17 00:00:00 2001 From: Emanuel Rietveld Date: Thu, 29 Jul 2021 21:53:56 +0200 Subject: [PATCH] add friendlyMaxVisitsFactor setting Makes KataGo keep pace with the opponent by adjusting max visits to how fast the opponent is playing. Useful if you're running a ranked bot on a go server and want to be friendly if the opponent is also playing fast, without sacrificing playing strength if the opponent makes full use of the time control. Using max visits makes the bot play naturally, responding quickly if the move is expected and taking more time if it's unexpected. (Of course, Katago's idea of what is obvious may differ from a human.) --- cpp/command/gtp.cpp | 34 +++++++++++++++++++++++++++++----- cpp/configs/gtp_example.cfg | 5 +++++ cpp/program/gtpconfig.cpp | 5 +++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/cpp/command/gtp.cpp b/cpp/command/gtp.cpp index ef990ad7a..ac6161e99 100644 --- a/cpp/command/gtp.cpp +++ b/cpp/command/gtp.cpp @@ -348,6 +348,10 @@ struct GTPEngine { double genmoveTimeSum; + ClockTimer gameTimer; + double gameGenmoveTimeSum; + double friendlyMaxVisitsFactor; + GTPEngine( const string& modelFile, SearchParams initialParams, Rules initialRules, bool assumeMultiBlackHandicap, bool prevtEncore, @@ -357,7 +361,8 @@ struct GTPEngine { double genmoveWRN, double analysisWRN, bool genmoveAntiMir, bool analysisAntiMir, Player persp, int pvLen, - std::unique_ptr&& pbTable + std::unique_ptr&& pbTable, + double friendlyMaxVisitsFact ) :nnModelFile(modelFile), assumeMultipleStartingBlackMovesAreHandicap(assumeMultiBlackHandicap), @@ -387,7 +392,9 @@ struct GTPEngine { avoidMYTDaggerHack(avoidDagger), patternBonusTable(std::move(pbTable)), perspective(persp), - genmoveTimeSum(0.0) + genmoveTimeSum(0.0), + gameGenmoveTimeSum(0.0), + friendlyMaxVisitsFactor(friendlyMaxVisitsFact) { } @@ -406,7 +413,8 @@ struct GTPEngine { } void clearStatsForNewGame() { - //Currently nothing + gameTimer.reset(); + gameGenmoveTimeSum = 0.0; } //Specify -1 for the sizes for a default @@ -861,6 +869,19 @@ struct GTPEngine { double searchFactor = PlayUtils::getSearchFactor(searchFactorWhenWinningThreshold,searchFactorWhenWinning,params,recentWinLossValues,pla); lastSearchFactor = searchFactor; + //Adjust to opponent's playing speed + if (friendlyMaxVisitsFactor > 0.0) { + double opponentMoveCount = round(moveHistory.size() / 2.0); + if (opponentMoveCount > 0) { + double timeSpentOpponent = (gameTimer.getSeconds() - gameGenmoveTimeSum); + params.maxVisits = lround(timeSpentOpponent / opponentMoveCount * friendlyMaxVisitsFactor); + } else { + // KataGo plays the very first move of the game, take 1s + params.maxVisits = lround(friendlyMaxVisitsFactor); + } + bot->setParams(params); + } + Loc moveLoc; bot->setAvoidMoveUntilByLoc(args.avoidMoveUntilByLocBlack,args.avoidMoveUntilByLocWhite); if(args.analyzing) { @@ -914,6 +935,7 @@ struct GTPEngine { //output of various things. double timeTaken = timer.getSeconds(); genmoveTimeSum += timeTaken; + gameGenmoveTimeSum += timeTaken; //Chatting and logging ---------------------------- @@ -1550,6 +1572,7 @@ int MainCmds::gtp(int argc, const char* const* argv) { const double normalAvoidRepeatedPatternUtility = initialParams.avoidRepeatedPatternUtility; const double handicapAvoidRepeatedPatternUtility = (cfg.contains("avoidRepeatedPatternUtility") || cfg.contains("avoidRepeatedPatternUtility0")) ? initialParams.avoidRepeatedPatternUtility : 0.005; + const double friendlyMaxVisitsFactor = cfg.contains("friendlyMaxVisitsFactor") ? cfg.getDouble("friendlyMaxVisitsFactor", 0.0, 1e10) : 0.0; const int defaultBoardXSize = cfg.contains("defaultBoardXSize") ? cfg.getInt("defaultBoardXSize",2,Board::MAX_LEN) : @@ -1591,12 +1614,13 @@ int MainCmds::gtp(int argc, const char* const* argv) { genmoveWideRootNoise,analysisWideRootNoise, genmoveAntiMirror,analysisAntiMirror, perspective,analysisPVLen, - std::move(patternBonusTable) + std::move(patternBonusTable), + friendlyMaxVisitsFactor ); engine->setOrResetBoardSize(cfg,logger,seedRand,defaultBoardXSize,defaultBoardYSize); //If nobody specified any time limit in any way, then assume a relatively fast time control - if(!cfg.contains("maxPlayouts") && !cfg.contains("maxVisits") && !cfg.contains("maxTime")) { + if(!cfg.contains("maxPlayouts") && !cfg.contains("maxVisits") && !cfg.contains("maxTime") && !cfg.contains("friendlyMaxVisitsFactor")) { double mainTime = 1.0; double byoYomiTime = 5.0; int byoYomiPeriods = 5; diff --git a/cpp/configs/gtp_example.cfg b/cpp/configs/gtp_example.cfg index 0772198ba..85a8ad548 100644 --- a/cpp/configs/gtp_example.cfg +++ b/cpp/configs/gtp_example.cfg @@ -206,6 +206,11 @@ maxVisits = 500 # If provided, cap search time at this many seconds. # maxTime = 10 +# If provided, adapt maxVisits to averageOpponentTimePerMove * friendlyMaxVisitsFactor. (The static maxVisits setting will be ignored.) +# Setting this to 150% of the visits/s you normally get on your hardware makes KataGo play approximately equally fast as the opponent. +# Useful if you're running a ranked bot on a go server, and you want to be friendly if the opponent is also playing fast. +# friendlyMaxVisitsFactor = 500 + # Ponder on the opponent's turn? ponderingEnabled = false maxTimePondering = 60 # Maximum time to ponder, in seconds. Comment out to make unlimited. diff --git a/cpp/program/gtpconfig.cpp b/cpp/program/gtpconfig.cpp index 20a56cabc..53559f914 100644 --- a/cpp/program/gtpconfig.cpp +++ b/cpp/program/gtpconfig.cpp @@ -125,6 +125,11 @@ resignConsecTurns = 3 # If provided, cap search time at this many seconds. $$MAX_TIME +# If provided, adapt maxVisits to averageOpponentTimePerMove * friendlyMaxVisitsFactor. (The static maxVisits setting will be ignored.) +# Setting this to 150% of the visits/s you normally get on your hardware makes KataGo play approximately equally fast as the opponent. +# Useful if you're running a ranked bot on a go server, and you want to be friendly if the opponent is also playing fast. +# friendlyMaxVisitsFactor = 500 + # Ponder on the opponent's turn? $$PONDERING # Note: you can also set "maxVisitsPondering" or "maxPlayoutsPondering" too.