Skip to content

Commit

Permalink
Merge pull request #164 from kobanium/development
Browse files Browse the repository at this point in the history
Support CGOS player
  • Loading branch information
kobanium authored Jan 27, 2024
2 parents 6d1ed59 + 271280f commit b864067
Show file tree
Hide file tree
Showing 21 changed files with 703 additions and 74 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ ray

learning_result/**/*.txt
learning_result/**/*.log
sim_params/*.txt
uct_params/*.txt
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Ray's command line options are as follows,
| `--komi` | Komi value | Real number | 6.5 | KOMI ( = 6.5 ) | KOMI is defined in include/board/Constant.hpp |
| `--superko` | Positional super ko | - | - | - | Supporting positional super ko only |
| `--handicap` | The number of handicap stones | Integer more than 1 | 2 | 0 | This option is for debugging. |
| `--cgos` | CGOS player mode | - | - | - | Activating capturing all dead stones mode |

### annotation
The `--playout` option, the `--const-time option`, and the `--time` option are effective when specified last, respectively.
Expand All @@ -37,6 +38,7 @@ The `--playout` option, the `--const-time option`, and the `--time` option are e
| `--reuse-subtree` | Reusing MCTS sub-tree | - | - | - | |
| `--pondering` | Pondering on opponent's thinking time | - | - | - | |
| `--tree-size` | Maximum number of MCTS nodes | Integer power of 2 | 16834 | UCT_HASH_SIZE ( = 16834 ) | UCT_HASH_SIZE is defined in include/board/ZobristHash.hpp |
| `--resign` | Resign threshold | Rean number more than or equal to 0.0 and less than or equal to 1.0 | 0.1 | RESIGN_THRESHOLD ( = 0.20 ) | RESIGN_THRESHOLD is defined in include/mcts/MoveSelection.hpp |

### annotation
When the `--pondering` option is enabled, the `--reuse-pondering` option is automatically enabled automatically.
Expand Down
29 changes: 29 additions & 0 deletions doc/ja/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Windowsでの動作確認はしていません. Linuxで利用する際には下
# make
```

```sim_params``````uct_params```の各パラメータファイルは[こちら](https://github.com/kobanium/Ray/releases)からダウンロードして各フォルダに配置してください.

使い方
------

Expand All @@ -30,6 +32,7 @@ Windowsでの動作確認はしていません. Linuxで利用する際には下
| `--komi` | コミの値の設定 | 実数 | 6.5 | KOMI ( = 6.5 ) | KOMI は include/board/Constant.hpp に定義しています。 |
| `--superko` | 超劫の有効化 | - | - | - | Positional Super Koのみサポートしています。 |
| `--handicap` | 置き石の数の指定 | 1以上の整数 | 2 | 0 | デバッグ用のオプションです。 |
| `--cgos` | CGOS用のオプション | - | - | - | 相手の死に石を全て打ち上げるまでパスしないモードです。 |

### 注意
--playoutオプション, --const-timeオプション, --timeオプションはそれぞれ最後に指定されたものが有効になります.
Expand All @@ -46,6 +49,7 @@ Windowsでの動作確認はしていません. Linuxで利用する際には下
| `--reuse-subtree` | サブツリー再利用の有効化 | - | - | - | |
| `--pondering` | 予測読みの有効化 | - | - | - | |
| `--tree-size` | MCTSノード数の指定 | 2のべき乗の整数 | 16834 | UCT_HASH_SIZE ( = 16834 ) | UCT_HASH_SIZE は include/board/ZobristHash.hpp に定義しています。 |
| `--resign` | 投了の閾値の指定 | 0.0以上1.0以下の実数 | 0.1 | RESIGN_THRESHOLD ( = 0.20 ) | RESIGN_THRESHOLD は include/mcts/MoveSelection.hpp に定義しています。 |

### 注意
--ponderingオプションを有効にすると, 自動的に--reuse-ponderingオプションが自動で有効になります.
Expand All @@ -58,6 +62,31 @@ Windowsでの動作確認はしていません. Linuxで利用する際には下
| `--no-debug` | デバッグメッセージ出力の抑制 | - | - | - | |


## 使用例
デフォルトの設定では, Rayは1手あたり10秒探索して着手を生成します.
```
./ray
```

探索スレッド数を8にし, 1手あたり4秒探索する.
```
./ray --const-time 4 --thread 8
```

1手あたり1000プレイアウト探索する.
```
./ray --playout 1000
```

探索スレッド数を16, 探索木のノード数を65536, 持ち時間を30分にし, 相手の考慮時間中も探索する.
```
./ray --time 1800 --thread 16 --tree-size 65536 --pondering
```

## ライセンス
Rayは2条項BSDライセンスを適用しています.
詳細は"COPYING"ファイルをご覧ください.

## 開発者向け
モンテカルロ・シミュレーション用のパラメータの学習の方法は[こちら](LearningForSimulation.md).
木探索用のパラメータの学習方法は[こちら](LearningForTree.md).
3 changes: 3 additions & 0 deletions include/feature/Semeai.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ bool IsSelfAtari( const game_info_t *game, const int color, const int pos );
// 欠け眼を継ぐかどうかの判定の準備
bool IsAlreadyCaptured( const game_info_t *game, const int id, int player_id[], int player_ids );

// 自己アタリ
bool IsMeaningfulSelfAtari( const game_info_t *game, const int color, const int pos );

#endif
10 changes: 10 additions & 0 deletions include/feature/Territory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef _TERRITORY_HPP_
#define _TERRITORY_HPP_

#include "board/GoBoard.hpp"
#include "mcts/Statistic.hpp"


bool IsRemainingDeadStone( const game_info_t *game, const int color, const statistic_t statistic[] );

#endif
2 changes: 1 addition & 1 deletion include/gtp/Gtp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const int BUF_SIZE = 256;
#define PROGRAM_NAME "Ray"

// プログラムのバージョン
#define PROGRAM_VERSION "10.3.0"
#define PROGRAM_VERSION "11.0.0"

// GTPのバージョン
#define PROTOCOL_VERSION "2"
Expand Down
151 changes: 151 additions & 0 deletions include/mcts/AnalysisData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#ifndef _ANALYSIS_DATA_HPP_
#define _ANALYSIS_DATA_HPP_

#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>

#include "mcts/MCTSNode.hpp"
#include "mcts/UctSearch.hpp"
#include "util/Utility.hpp"


class PrincipalVariationData {
private:
int move;
double playout_win_rate;
double prior;
int visits;
int pv_depth_limit;
std::vector<std::string> pv;

public:
PrincipalVariationData( const uct_node_t &root, const int child_index, const int depth_limit = 100 )
: move(root.child[child_index].pos), playout_win_rate(CalculateWinningRate(root.child[child_index])),
prior(root.child[child_index].rate), visits(root.child[child_index].move_count.load()), pv_depth_limit(depth_limit)
{
const child_node_t &child = root.child[child_index];

pv.push_back(ParsePoint(child.pos));

int index = child.index;

while (pv.size() < pv_depth_limit && index != NOT_EXPANDED) {
const uct_node_t &node = GetNode(index);
const child_node_t *children = node.child;
const int num_children = node.child_num;

if (node.move_count == 0) {
break;
}

int max_count = children[PASS_INDEX].move_count;
int max_index = PASS_INDEX;

for (int i = 1; i < num_children; i++) {
if (children[i].move_count > max_count) {
max_count = children[i].move_count;
max_index = i;
}
}

pv.push_back(ParsePoint(children[max_index].pos));
index= children[max_index].index;
}
}

bool
operator>( const PrincipalVariationData &data ) const
{
return visits > data.visits;
}

std::string
GetJsonData( void ) const
{
std::ostringstream oss;

oss << "{ ";
oss << "\"move\": \"" << ParsePoint(move) << "\",";
oss << "\"winrate\": " << std::fixed << std::setprecision(4) << playout_win_rate << ",";
oss << "\"prior\": " << std::fixed << std::setprecision(6) << prior << ",";
oss << "\"pv\" : \"" << JoinStrings(pv, " ") << "\",";
oss << "\"visits\" : " << visits;
oss << "}";

return oss.str();
}
};


class CgosAnalyzeData {
private:
const int visits;
double win_rate;
std::vector<PrincipalVariationData> pv_data;
const char owner_char[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
std::string ownership;
std::string comment;

public:
CgosAnalyzeData( const uct_node_t &root, const int color )
: visits(root.move_count)
{
if (root.move_count == 0) {
win_rate = 0.5;
ownership = "";
for (int i = 0; i < pure_board_max; i++) {
ownership += owner_char[31];
}
comment = u8"Ray selected pass immediately.";
} else {
win_rate = root.win / root.move_count;

const child_node_t *children = root.child;

for (int i = 0; i < root.child_num; i++) {
if (children[i].move_count > 0) {
pv_data.push_back(PrincipalVariationData(root, i));
}
}
std::sort(pv_data.begin(), pv_data.end(), std::greater<PrincipalVariationData>());
ownership = "";
for (int i = 0; i < pure_board_max; i++) {
const double owner = root.ownership[onboard_pos[i]] / root.move_count;
const int owner_index = static_cast<int>(owner * 62);
ownership += owner_char[owner_index];
}
comment = u8"This is the result of Monte-Carlo tree search.";
}

}


std::string
GetJsonData( void ) const
{
std::ostringstream oss;
std::vector<std::string> pv_str;

for (const PrincipalVariationData &datum : pv_data) {
pv_str.push_back(datum.GetJsonData());
}
oss << "{ ";
oss << "\"winrate\": " << std::fixed << std::setprecision(4) << win_rate << ",";
oss << "\"visits\": " << visits << ", ";
if (!pv_str.empty()) {
oss << "\"moves\": [" << JoinStrings(pv_str, ",") << "],";
}
oss << "\"ownership\": \"" << ownership << "\",";
oss << "\"comment\" : \"" << comment << "\"";
oss << "}";

return oss.str();
}

};


#endif
5 changes: 5 additions & 0 deletions include/mcts/MCTSNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct uct_node_t {
int child_num; // 子ノードの個数
child_node_t child[UCT_CHILD_MAX]; // 子ノードの情報
bool seki[BOARD_MAX]; // セキの判定
double ownership[BOARD_MAX]; // Onwership
};


Expand All @@ -60,4 +61,8 @@ void InitializeNode( uct_node_t &node, const int pm1, const int pm2 );

double CalculatePassWinningPercentage( const uct_node_t &node );

double CalculateWinningRate( const child_node_t &child );

void UpdateOwnership( uct_node_t &node, game_info_t *game, const int current_color );

#endif
5 changes: 4 additions & 1 deletion include/mcts/MoveSelection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ constexpr double PASS_THRESHOLD = 0.90;
constexpr double RESIGN_THRESHOLD = 0.20;


// CGOSモードの設定
void SetCaptureAllMode( const bool flag );

// 投了する閾値の設定
void SetResignThreshold( const double threshold );

// 探索回数最大の子ノードのインデックスを取得
int SelectMaxVisitChild( const uct_node_t &root );

// 探索結果から着手選択
int SelectMove( const game_info_t *game, const uct_node_t &root, double &best_wp );
int SelectMove( const game_info_t *game, const uct_node_t &root, const int color, double &best_wp );

#endif
23 changes: 23 additions & 0 deletions include/mcts/Statistic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef _STATISTIC_HPP_
#define _STATISTIC_HPP_

#include <atomic>

struct statistic_t {
std::atomic<int> colors[3]; // その箇所を領地にした回数

void clear() {
for (int i = 0; i < 3; i++) {
colors[i] = 0;
}
}

statistic_t& operator=( const statistic_t& v ) {
for (int i = 0; i < 3; i++) {
colors[i] = v.colors[i].load();
}
return *this;
}
};

#endif
23 changes: 6 additions & 17 deletions include/mcts/UctSearch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "board/ZobristHash.hpp"
#include "mcts/MCTSNode.hpp"
#include "mcts/SearchManager.hpp"
#include "mcts/Statistic.hpp"

////////////
// 定数 //
Expand Down Expand Up @@ -36,23 +37,6 @@ struct thread_arg_t {
int lz_analysis_cs;
};

struct statistic_t {
std::atomic<int> colors[3]; // その箇所を領地にした回数

void clear() {
for (int i = 0; i < 3; i++) {
colors[i] = 0;
}
}

statistic_t& operator=(const statistic_t& v) {
for (int i = 0; i < 3; i++) {
colors[i] = v.colors[i].load();
}
return *this;
}
};

struct rate_order_t {
int index; // ノードのインデックス
double rate; // その手のレート
Expand Down Expand Up @@ -116,5 +100,10 @@ int UctSearchGenmoveCleanUp( game_info_t *game, int color );
// 探索の再利用の設定
void SetReuseSubtree( bool flag );

// 指定したインデックスのノードを取得
uct_node_t& GetNode( const int index );

// ルートノードを取得
uct_node_t& GetRootNode( void );

#endif
1 change: 1 addition & 0 deletions include/util/Command.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum COMMAND {
COMMAND_NO_DEBUG,
COMMAND_SUPERKO,
COMMAND_RESIGN_THRESHOLD,
COMMAND_CGOS_MODE,
COMMAND_MAX,
};

Expand Down
3 changes: 3 additions & 0 deletions include/util/Utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <chrono>
#include <string>
#include <vector>

#if defined (_WIN32)
const std::string PATH_SEPARATOR = "\\";
Expand All @@ -29,4 +30,6 @@ void SetWorkingDirectory( const char *program_path );

std::string GetWorkingDirectory( void );

std::string JoinStrings( const std::vector<std::string> &str_vec, const char *deliminter );

#endif
Loading

0 comments on commit b864067

Please sign in to comment.