diff --git a/src/Gtp.cpp b/src/Gtp.cpp index b4eb78c..a6bbb99 100644 --- a/src/Gtp.cpp +++ b/src/Gtp.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "DynamicKomi.h" #include "Gtp.h" @@ -67,8 +69,14 @@ static void GTP_final_status_list( void ); static void GTP_set_free_handicap( void ); // fixed_handicapコマンドを処理 static void GTP_fixed_handicap( void ); +// GOGUI +static void GTP_gogui_analyze_commands( void ); // -static void GTP_ray_analyze(void); +static void GTP_ray_toggle_live_best_sequence(); +// +static void GTP_ray_best_sequence(); +// +static void GTP_ray_stat(); // static void GTP_features_planes_file(void); // @@ -107,7 +115,10 @@ const GTP_command_t gtpcmd[GTP_COMMAND_NUM] = { { "place_free_handicap", GTP_fixed_handicap }, { "set_free_handicap", GTP_set_free_handicap }, { "kgs-genmove_cleanup", GTP_kgs_genmove_cleanup }, - { "ray_analyze", GTP_ray_analyze }, + { "gogui-analyze_commands", GTP_gogui_analyze_commands }, + { "ray-toggle_live_best_sequence", GTP_ray_toggle_live_best_sequence }, + { "ray-best_sequence", GTP_ray_best_sequence }, + { "ray-stat", GTP_ray_stat }, { "_clear", GTP_features_clear }, { "_store", GTP_features_store }, { "_dump", GTP_features_planes_file }, @@ -782,12 +793,32 @@ GTP_kgs_genmove_cleanup( void ) GTP_response(pos, true); } +///////////////////////////////////////// +// void GTP_gogui_analyze_commands() // +///////////////////////////////////////// +static void +GTP_gogui_analyze_commands() +{ + GTP_response( + "none/Togle Live Best Sequence/ray-toggle_live_best_sequence\n" + "gfx/Print Best Sequence/ray-best_sequence %m\n" + "hpstring/Print Moves/ray-stat %m\n" + "", + true); +} -////////////////////////// -// void GTP_genmove() // -////////////////////////// static void -GTP_ray_analyze(void) +GTP_ray_toggle_live_best_sequence() +{ + ToggleLiveBestSequence(); + GTP_response(brank, true); +} + +//////////////////////////////////// +// void GTP_ray_best_sequence() // +//////////////////////////////////// +static void +GTP_ray_best_sequence() { char *command; char c; @@ -798,26 +829,20 @@ GTP_ray_analyze(void) command = STRTOK(input_copy, DELIM, &next_token); CHOMP(command); - if (!strcmp("genmove_black", command)) { - color = S_BLACK; - } else if (!strcmp("genmove_white", command)) { + command = STRTOK(NULL, DELIM, &next_token); + if (command == NULL) { + GTP_response(err_genmove, true); + return; + } + CHOMP(command); + c = (char)tolower((int)command[0]); + if (c == 'w') { color = S_WHITE; + } else if (c == 'b') { + color = S_BLACK; } else { - command = STRTOK(NULL, DELIM, &next_token); - if (command == NULL) { - GTP_response(err_genmove, true); - return; - } - CHOMP(command); - c = (char)tolower((int)command[0]); - if (c == 'w') { - color = S_WHITE; - } else if (c == 'b') { - color = S_BLACK; - } else { - GTP_response(err_genmove, true); - return; - } + GTP_response(err_genmove, true); + return; } player_color = color; @@ -826,19 +851,55 @@ GTP_ray_analyze(void) point = SimulationGenmove(game, color); else point = UctSearchGenmove(game, color); - /* - if (point != RESIGN) { - PutStone(game, point, color); + + stringstream out; + PrintBestSequenceGFX(out, game, uct_node, current_root, color); + GTP_response(out.str().c_str(), true); +} + +/////////////////////////// +// void GTP_ray_stat() // +/////////////////////////// +static void +GTP_ray_stat() +{ + char *command; + char c; + char pos[10]; + int color; + int point = PASS; + + command = STRTOK(input_copy, DELIM, &next_token); + + CHOMP(command); + command = STRTOK(NULL, DELIM, &next_token); + if (command == NULL) { + GTP_response(err_genmove, true); + return; + } + CHOMP(command); + c = (char)tolower((int)command[0]); + if (c == 'w') { + color = S_WHITE; + } else if (c == 'b') { + color = S_BLACK; + } else { + GTP_response(err_genmove, true); + return; } - IntegerToString(point, pos); - */ - cout << "= "; - PrintLiveBestSequence(cerr, game, uct_node, current_root, color); - //GTP_response(pos, true); - cout << endl << endl; + player_color = color; - UctSearchPondering(game, FLIP_COLOR(color)); + if (sim_move) + point = SimulationGenmove(game, color); + else + point = UctSearchGenmove(game, color); + + stringstream out; + PrintMoveStat(out, game, uct_node, current_root); + + GTP_response(out.str().c_str(), true); + //cout << endl << endl; } static int features_turn_count = 0; diff --git a/src/Gtp.h b/src/Gtp.h index 1a8c423..a380ce9 100644 --- a/src/Gtp.h +++ b/src/Gtp.h @@ -1,7 +1,7 @@ #ifndef _GTP_H_ #define _GTP_H_ -const int GTP_COMMAND_NUM = 30; +const int GTP_COMMAND_NUM = 33; const int GTP_COMMAND_SIZE = 64; const int BUF_SIZE = 256; diff --git a/src/Message.cpp b/src/Message.cpp index ab8f080..dbb8cf7 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "Message.h" #include "Point.h" @@ -465,7 +467,7 @@ PrintBestSequence( const game_info_t *game, const uct_node_t *uct_node, const in void -PrintLiveBestSequence(std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int current_root, int start_color) +PrintBestSequenceGFX(std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int current_root, int start_color) { int current = current_root; int color = start_color; @@ -558,6 +560,138 @@ PrintLiveBestSequence(std::ostream& out, const game_info_t *game, const uct_node } +static void +PrintBestSequence(std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int current_root) +{ + int current = current_root; + + auto root = &uct_node[current_root]; + auto statistic = root->statistic; + auto uct_child = uct_node[current].child; + int child_num = uct_node[current].child_num; + + if (root->move_count == 0) + return; + + int index = -1; + int max = 0; + for (int i = 0; i < child_num; i++) { + if (uct_child[i].move_count > max) { + max = uct_child[i].move_count; + index = i; + } + } + if (node_hash[current].color == S_BLACK) out << "b "; + else if (node_hash[current].color == S_WHITE) out << "w "; + out << FormatMove(uct_child[index].pos) << " "; + + current = uct_child[index].index; + + while (current != NOT_EXPANDED) { + uct_child = uct_node[current].child; + child_num = uct_node[current].child_num; + + max = 50; + index = -1; + + for (int i = 0; i < child_num; i++) { + if (uct_child[i].move_count > max) { + max = uct_child[i].move_count; + index = i; + } + } + + if (index == -1) break; + + if (node_hash[current].color == S_BLACK) out << "b "; + else if (node_hash[current].color == S_WHITE) out << "w "; + out << FormatMove(uct_child[index].pos) << " "; + + current = uct_child[index].index; + } +} + +void +PrintMoveStat( std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int current_root ) +{ + bool evaled = uct_node[current_root].evaled; + const child_node_t *uct_child = uct_node[current_root].child; + const int child_num = uct_node[current_root].child_num; + const double scale = std::max(0.2, std::min(1.0, 1.0 - (game->moves - 200) / 50.0)) * value_scale; + + vector idx(child_num); + iota(idx.begin(), idx.end(), 0); + + auto idxComp = [&uct_child](size_t i1, size_t i2) { + return uct_child[i1].move_count > uct_child[i2].move_count; + }; + + sort(idx.begin(), idx.end(), idxComp); + + out << "|Move|Count|Simulation|Policy |Value |Win |Best Sequence" << endl; + // UCB値最大の手を求める + for (int j = 0; j < std::min(10, child_num); j++) { + int i = idx[j]; + if (uct_child[i].move_count == 0) + continue; + if (!uct_child[i].flag && !uct_child[i].open) + continue; + //double p2 = -1; + double value_win = 0; + double value_move_count = 0; + + if (uct_child[i].index >= 0 && i != 0) { + auto node = &uct_node[uct_child[i].index]; + if (node->value_move_count > 0) { + //p2 = 1 - (double)node->value_win / node->value_move_count; + value_win = node->value_win; + value_move_count = node->value_move_count; + value_win = value_move_count - value_win; + } + //cerr << "VA:" << (value_win / value_move_count) << " VS:" << uct_child[i].value << endl; + } + if (value_move_count == 0 && uct_child[i].value >= 0) { + value_move_count = 1; + value_win = uct_child[i].value; + } + + double win = uct_child[i].win; + double move_count = uct_child[i].move_count; + double p0 = win / move_count; + + out << "|" << setw(4) << FormatMove(uct_child[i].pos); + out << "|" << setw(5) << (int) move_count; + + auto precision = out.precision(); + out.precision(4); + out << "|" << setw(10) << fixed << (p0 * 100); + if (evaled) { + out << "|" << setw(10) << fixed << (uct_child[i].nnrate * 100); + if (value_move_count > 0) { + double p1 = value_win / value_move_count; + double p = p0 * (1 - scale) + p1 * scale; + out + << "|" << setw(10) << fixed << (p1 * 100) + << "|" << setw(10) << fixed << (p * 100); + } else { + out + << "|" + << "|"; + } + } else { + out + << "|" + << "|" + << "|"; + } + out.precision(precision); + out << "|"; + if (uct_child[i].index > 0) + PrintBestSequence(out, game, uct_node, uct_child[i].index); + out << endl; + } +} + /////////////////////// // 探索の情報の表示 // /////////////////////// diff --git a/src/Message.h b/src/Message.h index 76764a1..579f4ed 100644 --- a/src/Message.h +++ b/src/Message.h @@ -34,7 +34,8 @@ void PrintOwner( const uct_node_t *root, const int color, double *own ); // 最善応手列の表示 void PrintBestSequence( const game_info_t *game, const uct_node_t *uct_node, const int root, const int start_color ); -void PrintLiveBestSequence( std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int root, int start_color ); +void PrintBestSequenceGFX( std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int root, int start_color ); +void PrintMoveStat( std::ostream& out, const game_info_t *game, const uct_node_t *uct_node, int current_root ); // 探索の情報の表示 void PrintPlayoutInformation( const uct_node_t *root, const po_info_t *po_info, const double finish_time, const int pre_simulated ); diff --git a/src/UctSearch.cpp b/src/UctSearch.cpp index 33137e9..9fd495c 100644 --- a/src/UctSearch.cpp +++ b/src/UctSearch.cpp @@ -167,6 +167,9 @@ bool reuse_subtree = false; // 自分の手番の色 int my_color; +// +static bool live_best_sequence = false; + const double pass_po_limit = 0.5; const int policy_batch_size = 16; const int value_batch_size = 64; @@ -346,6 +349,14 @@ SetEarlyPass(bool pass) early_pass = pass; } +////////////////////////////// +// Toggle Live Best Sequece // +////////////////////////////// +void +ToggleLiveBestSequence() +{ + live_best_sequence = !live_best_sequence; +} //////////////////////////////////////////// // 盤の大きさに合わせたパラメータの設定 // @@ -1708,8 +1719,8 @@ SelectMaxUcbChild( const game_info_t *game, int current, int color ) double ucb_bonus_weight = bonus_weight * sqrt(bonus_equivalence / (sum + bonus_equivalence)); const bool debug = current == current_root && sum % 10000 == 0 && GetDebugMessageMode(); - if (current == current_root && sum % 1000 == 0) { - PrintLiveBestSequence(cerr, game, uct_node, current_root, color); + if (live_best_sequence && current == current_root && sum % 1000 == 0) { + PrintBestSequenceGFX(cerr, game, uct_node, current_root, color); } //if (evaled) { //cerr << "use nn" << endl; diff --git a/src/UctSearch.h b/src/UctSearch.h index c68470e..d3cd30d 100644 --- a/src/UctSearch.h +++ b/src/UctSearch.h @@ -166,6 +166,9 @@ void SetEarlyPass( bool pass ); // ノード展開の有無指定 void SetNoExpand(bool flag); +// +void ToggleLiveBestSequence(); + // パラメータの設定 void SetParameter( void );