過往搜尋會開設terr = 0, terr = 1分兩次來判斷為死活或者領土,但這樣的設計可能會多走一些重複的路,且確定只有此受到此變數的影響,改成一開始也能一起跑終局
else{
//官子題終局檢查
int end_state = is_end_2(color);
//若為真終局,則直接return
if(can_win_by_territory and (end_state == true_end )){
if(win_by_territory(color, 0)){
if(show_detail){
cout<<"win by territory---------------------\n";
print_board();
cout<<"-------------------------------------\n";
}
is_win = 1;
}
else is_win = 0;
}//若為偽終局,則僅在深度為0時return
else if(can_win_by_territory and end_state == pseudo_end and depth<=0){
is_win = win_by_territory(color, 0);
}
}
//無論是否終局皆先以淺層紀錄結果,其後可減少重複終局判斷的時間
recorder.record_minimax_solution(*this, color, current_color, is_win?100:0,is_win );
if(is_win)return 1;
}
現在嘗試了新的判斷方式,首先擴充真眼的定義必須為眼角一定為己方棋子才算真眼,不能自填真眼 (針對after n moves函數)
但是這個做法有弊端會讓許多無解的題目也被判定為雙活
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 39 | 2 | 0 | 11 |
| 官子題 | 0 | 7 | 7 | 4 |
新終局判斷-6depth-有限制
C級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 21 | 6 | 0 | 11 |
| 官子題 | 0 | 7 | 7 | 4 |
B級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 7 | 1 | 0 | 10 |
| 官子題 | 0 | 4 | 3 | 1 |
A級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 2 | 1 | 0 | 4 |
| 官子題 | 0 | 0 | 0 | 1 |
S級
耗時:100s
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 35 | 0 | 2 | 15 |
| 官子題 | 0 | 0 | 9 | 8 |
新終局判斷-6depth-有限制
C級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 19 | 0 | 0 | 19 |
| 官子題 | 0 | 0 | 4 | 14 |
B級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 3 | 0 | 0 | 15 |
| 官子題 | 0 | 0 | 3 | 5 |
A級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 0 | 0 | 0 | 7 |
| 官子題 | 0 | 0 | 0 | 1 |
S級
耗時:120s
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 19 | 10 | 0 | 23 |
| 官子題 | 0 | 7 | 4 | 7 |
新終局判斷-6depth-有限制
C級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 13 | 8 | 0 | 17 |
| 官子題 | 0 | 5 | 0 | 13 |
B級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 2 | 2 | 0 | 14 |
| 官子題 | 0 | 2 | 0 | 6 |
A級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 0 | 2 | 0 | 5 |
| 官子題 | 0 | 0 | 0 | 1 |
S級
耗時:83s
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 18 | 1 | 2 | 31 |
| 官子題 | 0 | 0 | 7 | 11 |
新終局判斷-6depth-無限制
C級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 12 | 0 | 1 | 25 |
| 官子題 | 0 | 0 | 2 | 16 |
B級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 0 | 0 | 2 | 16 |
| 官子題 | 0 | 0 | 2 | 6 |
A級
| 全殺 | 雙活 | 官子 | 無解 | |
|---|---|---|---|---|
| 死活題 | 0 | 0 | 0 | 7 |
| 官子題 | 0 | 0 | 0 | 1 |
S級
耗時:141s
原規則:在Go_board中以bool is_ko紀錄是否有劫,並且以單獨的pair<int, int> 紀錄位置
if(removed_stone_cnt == 1 and calculate_liberty( position ) == 1 and
get_component_size(position) == 1){
is_ko = 1;
ko_position = position;
current_record.make_ko = 1;
}但這樣的話不是應該是提掉的那一顆(也就是calculate_liberty<pos>的氣的位置被標記嗎?
加上目前只有標記為is_ko以後就沒有將ko經過多手後取消的操作
if(is_ko){
if( color != board[pt.first][pt.second] and
abs(pt.first-ko_position.first)+ abs( pt.second -ko_position.second ) <= 1){
return 0;
}
}直接更改就可以把這個周圍判斷省略了w
然後似乎可以記錄是黑棋白棋
或者改成以數字紀錄冷卻
新的方法改成紀錄ko_ban 二維陣列 -> 如果這裡做vector效率會如何,還是可以改成兩個版本比較?
還有盤面紀錄實作hash的變動
for(const auto& k : game.ko_bans){
if(k.active){
hash_value ^= ko_hash;
hash_value ^= position_hash[k.pt.first][k.pt.second];以人工紀錄有關劫、雙活的題號
| 正確辨認 | 非正確辨認 | 其他誤判 | |
|---|---|---|---|
判斷劫的方法目前只能從路徑追蹤來看,而我發現對於劫的處理常有回傳直接連接的棋路,嘗試對於這個行為扣分
vector<pair<int, int>> pending_recap;
is_pending_recap = (pair<int, int> pt) {
for (r : pending_recap)
if (r == pt)
return true;
return false;
};
if (is_pending_recap(pt))
//minus score判斷劫的方法目前只能從路徑追蹤來看,而我發現對於劫的處理常有回傳直接連接的棋路,嘗試對於這個行為扣分
| has_ko | retake_cd | |
|---|---|---|
| 舊版 | 3 | 3 |
| 新版 | 17 | 6 |