├── .gitignore ├── README.md └── badukGo-0.1.5 ├── Board.cpp ├── Board.h ├── Board_Thread.cpp ├── FastLog.h ├── Go.cpp ├── Go.h ├── Makefile ├── amaf.h ├── baduk.cpp ├── base.h ├── compile.bat ├── group.cpp ├── group.h ├── gtp.cpp ├── gtp.h ├── gtpcmds.cpp ├── libgcc_s_dw2-1.dll ├── libstdc++-6.dll ├── main.cpp ├── priors.cpp ├── start_pattern.cpp ├── tree.cpp └── tree.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go 2 | *Go Engine based on Monte-Carlo using C++ programming language* 3 | 4 | This is a course final project for ***Artificial Intelligence (EI339)*** in **Shanghai Jiao Tong University**, original project referenced and promoted from https://github.com/antoniogarro/Hara, which was written by [Antonio Garro](https://github.com/antoniogarro) and released under a permissive BSD License. 5 | 6 | --- 7 | 8 | + How to play? 9 | BadukGo-0.1.5-release supports Windows7, Windows8.1 and later. 10 | You can use any GoGui applications which support the Go Text Protocol (GTP). 11 | Currently we set the board size 13*13 , the time limit 3 sec and the komi 6.5. 12 | Also we do not support any handicaps yet. 13 | 14 | + Version 15 | This is the 0.1.5-version released, using WIN32 API to support multithreads programming. 16 | The basic searching strategy is Monte-Carlo based UCT. Some simple pattern are added and some heuristic tricks are used. 17 | 18 | + Copyright 19 | Released under the MIT License (MIT), Copyright (C) 2016 . 20 | Please contact us at Github :) 21 | 22 | [@Phonicavi](https://github.com/Phonicavi) [@lawinse](https://github.com/lawinse) [@Slimpid](https://github.com/lawinse) 23 | 24 | + Acknowledgement 25 | Technical supports of Go (weiqi, igo, baduk) from YUAN Yuancheng, *University of Science and Technology of China*. 26 | -------------------------------------------------------------------------------- /badukGo-0.1.5/Board.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "Board.h" 22 | #include 23 | #include 24 | #define komi_int 7 25 | 26 | Board::Board(int newsize) 27 | { 28 | size = (newsize <= MAXSIZE) ? newsize : size; 29 | size2 = size*size; 30 | komi = 0.5; 31 | last_point2 = 0; 32 | clear(); 33 | init_four_side(); 34 | init_four_corner(); 35 | init_eight_around(); 36 | init_distance(); 37 | init_manhattan(); 38 | GroupFather.clear(); 39 | IS_REAL_GAME =0; 40 | } 41 | 42 | //store the current situation 43 | void Board::backup(){ 44 | side_bu = side; 45 | ko_point_bu = ko_point; 46 | size_bu = size, size2_bu = size2; 47 | komi_bu = komi; 48 | handicap_bu = handicap; 49 | empty_points_bu = empty_points; 50 | for (unordered_set::iterator it = GroupFather.begin(); it != GroupFather.end(); ++it) 51 | groups_bu[*it] = groups[*it]; 52 | 53 | stones_on_board_bu[1] = stones_on_board[1]; 54 | stones_on_board_bu[0] = stones_on_board[0]; 55 | last_point_bu = last_point, last_point2_bu = last_point2; 56 | last_atari_black_bu = last_atari[0]?last_atari[0]->get_father():0; 57 | last_atari_white_bu = last_atari[1]?last_atari[1]->get_father():0; 58 | } 59 | 60 | //resume the situation from backup 61 | void Board::resume(){ 62 | side = side_bu; 63 | ko_point = ko_point_bu; 64 | size = size_bu, size2 = size2_bu; 65 | komi = komi_bu; 66 | handicap = handicap_bu; 67 | 68 | for (int i = 0; i <= size2; i++) { 69 | belongedGroup[i] = 0; 70 | } 71 | last_atari[0] = 0; 72 | last_atari[1] = 0; 73 | for (unordered_set::iterator it = GroupFather.begin(); it != GroupFather.end(); ++it){ 74 | groups[*it] = groups_bu[*it]; 75 | for (Group::StnItr st(&groups[*it]); st; ++st){ 76 | belongedGroup[*st] = &groups[*it]; 77 | if (*it == last_atari_black_bu) last_atari[0] = &groups[*it]; 78 | else if (*it == last_atari_white_bu) last_atari[1] = &groups[*it]; 79 | } 80 | } 81 | stones_on_board[1] = stones_on_board_bu[1]; 82 | stones_on_board[0] = stones_on_board_bu[0]; 83 | last_point = last_point_bu, last_point2 = last_point2_bu; 84 | empty_points = empty_points_bu; 85 | } 86 | 87 | void Board::reset() 88 | { 89 | side = BLACK; 90 | ko_point = 0; 91 | stones_on_board[BLACK] = 0, stones_on_board[WHITE] = 0; 92 | last_atari[BLACK] = 0, last_atari[WHITE] = 0; 93 | last_point = 0, last_point2 = 0; 94 | 95 | for (int i = 0; i <= size2; i++) { 96 | if (Group *point = belongedGroup[i]) { 97 | point->clear(); 98 | } 99 | belongedGroup[i] = 0; 100 | } 101 | 102 | empty_points.clear(); 103 | for (int j = 0; j < size2; j++) { 104 | empty_points.add(j+1); 105 | } 106 | } 107 | 108 | void Board::clear() 109 | { 110 | reset(); 111 | handicap = 0; 112 | game_history.clear(); 113 | } 114 | 115 | void Board::restore() 116 | { 117 | reset(); 118 | for (int i = 0; i < game_history.length(); i++) { 119 | if (game_history[i]) { 120 | drop_stone(game_history[i], side); 121 | side = !side; 122 | } else { 123 | side = !side; 124 | } 125 | } 126 | } 127 | 128 | void Board::init_four_side() 129 | { 130 | for (int k = 1; k <= size2; k++) { 131 | int nadj = 0; 132 | if (k <= size*(size-1)) { //N 133 | four_side[k][nadj++] = k + size; 134 | } 135 | if (k % size) { //E 136 | four_side[k][nadj++] = k + 1; 137 | } 138 | if (k > size) { //S 139 | four_side[k][nadj++] = k - size; 140 | } 141 | if (k % size != 1) { //W 142 | four_side[k][nadj++] = k -1; 143 | } 144 | four_side[k][nadj] = 0; 145 | } 146 | } 147 | 148 | void Board::init_four_corner() 149 | { 150 | 151 | for (int k = 1; k <= size2; k++) { 152 | int ndiag = 0; 153 | if (k <= size*(size-1) && k % size != 1) { //NW 154 | four_corner[k][ndiag++] = k + size - 1; 155 | } 156 | if (k <= size*(size-1) && k % size) { //NE 157 | four_corner[k][ndiag++] = k + size + 1; 158 | } 159 | if (k > size && k % size) { //SE 160 | four_corner[k][ndiag++] = k - size +1; 161 | } 162 | if (k > size && k % size != 1) { //SW 163 | four_corner[k][ndiag++] = k - size -1; 164 | } 165 | four_corner[k][ndiag] = 0; 166 | } 167 | } 168 | 169 | //Precomputed 8 neighbours, to be used in pattern matching. Order matters. 170 | void Board::init_eight_around() 171 | { 172 | for (int i = 0; i <= size2; i++) { 173 | for (int j = 0; j < 16; j++) { 174 | eight_around[i][j] = 0; 175 | } 176 | } 177 | //Duplicate to calculate rotations,avoiding run-time modulo division: 178 | for (int i = 0; i < 2; i++) { 179 | for (int k = 1; k <= size2; k++) { 180 | if (k <= size*(size-1)) { 181 | if (k % size != 1) { //NW 182 | eight_around[k][0+8*i] = k + size - 1; 183 | } 184 | eight_around[k][1+8*i] = k + size; //N 185 | } 186 | if (k % size ) { 187 | if (k <= size*(size-1)) { //NE 188 | eight_around[k][2+8*i] = k + size + 1; 189 | } 190 | eight_around[k][3+8*i] = k + 1; //E 191 | } 192 | if (k > size) { 193 | if (k % size) { //SE 194 | eight_around[k][4+8*i] = k - size +1; 195 | } 196 | eight_around[k][5+8*i] = k - size; //S 197 | } 198 | if (k % size != 1) { 199 | if (k > size) { //SW 200 | eight_around[k][6+8*i] = k - size -1; 201 | } 202 | eight_around[k][7+8*i] = k - 1; //W 203 | } 204 | } 205 | } 206 | } 207 | 208 | void Board::init_distance() 209 | { 210 | for (int p = 0; p <= size2; p++) { 211 | int d = (p-1)%size < (p-1)/size ? (p-1)%size : (p-1)/size; 212 | if (size - (p-1)%size - 1 < d) { 213 | d = size - (p-1)%size - 1; 214 | } 215 | if (size - (p-1)/size - 1 < d) { 216 | d = size - (p-1)/size - 1; 217 | } 218 | distance2edge[p] = d; 219 | } 220 | } 221 | 222 | void Board::init_manhattan() 223 | { 224 | for (int p = 1; p <= size2; p++) { 225 | for (int dis = 1; dis <= 4; dis++) { 226 | int len = 0; 227 | for (int d = 0; d <= dis; d++) { 228 | if ((p-1)%size >= d && size-(p-1)/size-1 >= (dis-d) ) { 229 | within_manhattan[p][dis-1][len++] = p - d + (dis-d)*size; 230 | } else { 231 | within_manhattan[p][dis-1][len++] = 0; 232 | } 233 | if (d != dis) { 234 | if ((p-1)%size >= d && (p-1)/size >= (dis-d)) { 235 | within_manhattan[p][dis-1][len++] = p - d - (dis-d)*size; 236 | } else { 237 | within_manhattan[p][dis-1][len++] = 0; 238 | } 239 | } 240 | if (d != 0) { 241 | if (size-(p-1)%size-1 >= d && size-(p-1)/size-1 >= (dis-d)) { 242 | within_manhattan[p][dis-1][len++] = p + d + (dis-d)*size; 243 | } else { 244 | within_manhattan[p][dis-1][len++] = 0; 245 | } 246 | if (d != dis) { 247 | if (size-(p-1)%size-1 >= d && (p-1)/size >= (dis-d)) { 248 | within_manhattan[p][dis-1][len++] = p + d - (dis-d)*size; 249 | } else { 250 | within_manhattan[p][dis-1][len++] = 0; 251 | } 252 | } 253 | } 254 | } 255 | } 256 | } 257 | } 258 | 259 | int Board::set_size(int newsize) 260 | { 261 | size = (newsize <= MAXSIZE) ? newsize : size; 262 | size2 = size*size; 263 | init_four_side(); 264 | init_four_corner(); 265 | init_eight_around(); 266 | init_distance(); 267 | init_manhattan(); 268 | clear(); 269 | 270 | return size; 271 | } 272 | 273 | inline void Board::remove_empty(int point) 274 | { 275 | empty_points.remove(point); 276 | } 277 | 278 | 279 | int Board::drop_stone(int point, bool color) 280 | { 281 | if (belongedGroup[point] != 0) 282 | print_goban(); 283 | 284 | PointSet<5> liberties; 285 | point_liberties(point, liberties); 286 | 287 | groups[point].set_up(point, color, liberties); 288 | belongedGroup[point] = &(groups[point]); 289 | if (IS_REAL_GAME) 290 | GroupFather.insert(point); 291 | 292 | remove_empty(point); 293 | stones_on_board[color]++; 294 | 295 | ko_point = handle_neighbours(point); 296 | 297 | if (belongedGroup[point]->get_libs_num() == 0) { //suicide. 298 | erase_neighbour(belongedGroup[point]); 299 | } else if (belongedGroup[point]->has_one_liberty()) { //self-atari. 300 | last_atari[color] = belongedGroup[point] ; 301 | } 302 | last_point2 = last_point; 303 | last_point = point; 304 | return point; 305 | } 306 | 307 | int Board::handle_neighbours(int point) 308 | { 309 | int captured_lone = 0, ncapt_lone = 0; 310 | GroupSet<4> neighbours; 311 | Group * great_gr = belongedGroup[point]; 312 | int nneigh = neighbour_groups(point, neighbours,great_gr); 313 | GroupSet<4> need_merge; 314 | need_merge.add(belongedGroup[point]); 315 | 316 | for (int i = 0; i < nneigh; i++) { 317 | Group *current_neigh = neighbours[i]; 318 | if (current_neigh->get_color() == belongedGroup[point]->get_color()) { 319 | need_merge.add(current_neigh); 320 | } else { 321 | if (current_neigh->has_one_liberty()) { 322 | if (current_neigh->get_stones_num() == 1) { 323 | ncapt_lone++; 324 | captured_lone = current_neigh->get_the_stone(0); 325 | } 326 | erase_neighbour(current_neigh); 327 | } else { 328 | current_neigh->erase_liberties(point); 329 | if (current_neigh->has_one_liberty()) { 330 | last_atari[current_neigh->get_color()] = current_neigh; 331 | } 332 | } 333 | } 334 | } 335 | 336 | if (need_merge.length()>1) 337 | merge_neighbour(point,&need_merge,great_gr); 338 | 339 | if (ncapt_lone == 1 && belongedGroup[point]->get_stones_num()== 1) { 340 | return captured_lone; //new ko point. 341 | } else { 342 | return 0; 343 | } 344 | } 345 | 346 | void Board::merge_neighbour(int point, Group *neigh) 347 | { 348 | Group *group = belongedGroup[point]; 349 | neigh->erase_liberties(point); 350 | group->attach_group(neigh); 351 | for (Group::StnItr st(neigh); st; ++st) { 352 | belongedGroup[*st] = group; 353 | } 354 | if (IS_REAL_GAME){ 355 | unordered_set::iterator it; 356 | if ((it = GroupFather.find(neigh->get_father())) != GroupFather.end()) 357 | GroupFather.erase(it); 358 | } 359 | 360 | neigh->clear(); 361 | if (neigh == last_atari[neigh->get_color()]) { 362 | last_atari[neigh->get_color()] = 0; 363 | //merged group may still be in atari, but this case is handled in 'drop_stone()'. 364 | } 365 | } 366 | 367 | void Board::merge_neighbour(int point,GroupSet<4> * groupset, Group * Greatgroup){ 368 | int len =groupset->length(); 369 | Group *cur_gr; 370 | for (int i=0; iget_by_index(i); 372 | cur_gr->erase_liberties(point); 373 | if (cur_gr!=Greatgroup){ 374 | Greatgroup->attach_group(cur_gr); 375 | for (Group::StnItr st(cur_gr); st; ++st){ 376 | belongedGroup[*st] = Greatgroup; 377 | } 378 | if (IS_REAL_GAME){ 379 | unordered_set::iterator it; 380 | if ((it = GroupFather.find(cur_gr->get_father())) != GroupFather.end()) 381 | GroupFather.erase(it); 382 | } 383 | cur_gr->clear(); 384 | } 385 | if (cur_gr == last_atari[cur_gr->get_color()]){ 386 | last_atari[cur_gr->get_color()] =0; 387 | } 388 | } 389 | } 390 | 391 | void Board::erase_neighbour(Group *neigh) 392 | { 393 | for (Group::StnItr st(neigh); st; ++st) { 394 | belongedGroup[*st] = 0; 395 | stones_on_board[neigh->get_color()]--; 396 | empty_points.add(*st); 397 | 398 | GroupSet<4> meta_neigh; 399 | int nmeta = neighbour_groups(*st, meta_neigh); 400 | for (int k = 0; k < nmeta; k++) { 401 | meta_neigh[k]->add_liberties(*st); 402 | if (meta_neigh[k] == last_atari[meta_neigh[k]->get_color()]) { 403 | last_atari[meta_neigh[k]->get_color()] = 0; 404 | } 405 | } 406 | } 407 | 408 | if (neigh == last_atari[neigh->get_color()]) { 409 | last_atari[neigh->get_color()] = 0; 410 | } 411 | if (IS_REAL_GAME){ 412 | unordered_set::iterator it; 413 | if ((it = GroupFather.find(neigh->get_father())) != GroupFather.end()) 414 | GroupFather.erase(it); 415 | } 416 | neigh->clear(); 417 | } 418 | 419 | //this move isn't stored in game_history. 420 | int Board::play_move(int point) 421 | { 422 | if (point) 423 | drop_stone(point, side); 424 | side = !side; 425 | 426 | return point; 427 | } 428 | 429 | int Board::play_move(int point, bool color) 430 | { 431 | 432 | IS_REAL_GAME = 1; 433 | if (side != color) //two consecutive moves of the same color are 434 | game_history.add(PASS); //represented by a pass inbetween. 435 | 436 | 437 | if (point > 0) { 438 | if (!is_occupied(point) && is_legal(point, color)) { 439 | drop_stone(point, color); 440 | } else { 441 | IS_REAL_GAME = 0; 442 | return -1; 443 | } 444 | } else 445 | ko_point = 0; 446 | 447 | side = !color; 448 | game_history.add(point); 449 | IS_REAL_GAME = 0; 450 | 451 | return point; 452 | } 453 | 454 | bool Board::set_position(const LList &moves) 455 | { 456 | for (int i = 0; i < moves.length(); i++) { 457 | if (moves[i]) { 458 | if (!belongedGroup[moves[i]] && is_legal(moves[i], side)) { 459 | drop_stone(moves[i], side); 460 | game_history.add(moves[i]); 461 | side = !side; 462 | } else { 463 | return false; 464 | } 465 | } else { 466 | side = !side; 467 | } 468 | } 469 | return true; 470 | } 471 | 472 | bool Board::set_position(const Board *original) 473 | { 474 | return set_position(original->game_history); 475 | } 476 | 477 | int Board::point_liberties(int point, LList &liberties) const 478 | { 479 | // liberties must be of size > 4. 480 | for (int i = 0; int adj=four_side[point][i]; i++) { 481 | if (belongedGroup[adj] == 0) { 482 | liberties.add(adj); 483 | } 484 | } 485 | return liberties.length(); 486 | } 487 | 488 | int Board::point_liberties(int point) const 489 | { 490 | int nlibs = 0; 491 | for (int i = 0; four_side[point][i]; i++) { 492 | if (belongedGroup[four_side[point][i]] == 0) nlibs++; 493 | } 494 | return nlibs; 495 | } 496 | 497 | int Board::neighbour_groups(int point, GroupSet<4> &neighbours) const 498 | { 499 | for (int i = 0; four_side[point][i]; i++) { 500 | neighbours.add(belongedGroup[four_side[point][i]]); 501 | } 502 | return neighbours.length(); 503 | } 504 | 505 | int Board::neighbour_groups(int point, GroupSet<4> &neighbours, Group *Greatgroup) const 506 | { 507 | int maxLen = 1; 508 | for (int i = 0; four_side[point][i]; i++) { 509 | neighbours.add(belongedGroup[four_side[point][i]]); 510 | if (belongedGroup[four_side[point][i]]->get_stones_num() > maxLen){ 511 | maxLen = belongedGroup[four_side[point][i]]->get_stones_num(); 512 | Greatgroup = belongedGroup[four_side[point][i]]; 513 | } 514 | } 515 | return neighbours.length(); 516 | } 517 | 518 | int Board::neighbour_groups(int point, bool color, int max_liberties, 519 | GroupSet *neighbours) const 520 | { 521 | int nneigh = 0; 522 | for (int i = 0; four_side[point][i]; i++) { 523 | Group *current_group = belongedGroup[four_side[point][i]]; 524 | if (current_group && current_group->get_color() == color 525 | && current_group->get_libs_num() <= max_liberties) { 526 | if (neighbours) neighbours->add(current_group); 527 | nneigh++; 528 | } 529 | } 530 | return nneigh; 531 | } 532 | 533 | int Board::neighbour_groups(const Group *group, bool color, int max_liberties, 534 | GroupSet &neighbours) const 535 | { 536 | for (Group::StnItr st(group); st; ++st) { 537 | neighbour_groups(*st, color, max_liberties, &neighbours); 538 | } 539 | return neighbours.length(); 540 | } 541 | 542 | int Board::neighbours_size(int point, bool color) const 543 | { 544 | int nstones = 0; 545 | GroupSet<4> neighbours; 546 | int nneigh = neighbour_groups(point, neighbours); 547 | for (int i = 0; i < nneigh; i++) { 548 | const Group *curr_neigh = neighbours[i]; 549 | if (curr_neigh->get_color() == color) { 550 | nstones += curr_neigh->get_stones_num(); 551 | } 552 | } 553 | return nstones; 554 | } 555 | 556 | int Board::neighbours_in_atari(int point, bool color, const GroupSet<4> &neighbours) const 557 | { 558 | int natari = 0; 559 | for (int i = 0; i < neighbours.length(); i++) { 560 | if (neighbours[i]->get_color() !=color && neighbours[i]->has_one_liberty()) { 561 | natari++; 562 | } 563 | } 564 | return natari; 565 | } 566 | 567 | bool Board::is_surrounded(int point, bool color, int consider_occupied) const 568 | { 569 | if (belongedGroup[point] != 0) return false; 570 | for (int i = 0; int adj=four_side[point][i]; i++) { 571 | if (adj == consider_occupied) continue; 572 | if (belongedGroup[adj] == 0 || belongedGroup[adj]->get_color() != color) { 573 | return false; 574 | } 575 | } 576 | return true; 577 | } 578 | 579 | bool Board::is_true_eye(int point, bool color, int consider_occupied) const 580 | { 581 | int i, ncontrolled = 0; 582 | 583 | if (!is_surrounded(point, color, consider_occupied)) 584 | return false; 585 | 586 | for (i = 0; int diag=four_corner[point][i]; i++) { 587 | if (belongedGroup[diag]) { 588 | if (belongedGroup[diag]->get_color() == color) { 589 | ncontrolled++; 590 | } 591 | } else { 592 | if (is_surrounded(diag, color, consider_occupied)) { 593 | ncontrolled++; 594 | } 595 | } 596 | } 597 | if (i == 4) { 598 | if (ncontrolled > 2) return true; 599 | } else if (ncontrolled == i) { 600 | return true; 601 | } 602 | 603 | return false; 604 | } 605 | 606 | #define FALSE_EYES 607 | #ifdef FALSE_EYES 608 | bool Board::is_false_eye(int point, bool color) const 609 | { 610 | if (!is_surrounded(point, color)) return false; 611 | int nopponent = 0; 612 | for (int i = 0; i < 4; i++) { 613 | if (int diag = four_corner[point][i]) { 614 | if (belongedGroup[diag] && belongedGroup[diag]->get_color() != color) { 615 | nopponent++; 616 | } 617 | } else { 618 | nopponent++; 619 | break; 620 | } 621 | } 622 | return nopponent < 2; 623 | } 624 | 625 | #else 626 | bool Board::is_false_eye(int point, bool color) const 627 | { 628 | if (!is_surrounded(point, color)) 629 | return false; 630 | for (int i = 0; int adj=four_side[point][i]; i++) { 631 | if (belongedGroup[adj]->has_one_liberty()) 632 | return false; 633 | } 634 | 635 | return true; 636 | } 637 | #endif 638 | 639 | bool Board::is_legal(int point, bool color) const 640 | { 641 | if (point == ko_point) return false; 642 | if (point_liberties(point) > 0) return true; 643 | 644 | GroupSet<4> neighbours; 645 | int nneigh = neighbour_groups(point, neighbours); 646 | for (int i = 0; i < nneigh; i++) { 647 | if (neighbours[i]->get_color() == color && !neighbours[i]->has_one_liberty()) { 648 | return true; 649 | } 650 | } 651 | return neighbours_in_atari(point, color, neighbours) > 0; 652 | } 653 | 654 | //Value 1 for Black, -1 for White, 0 for empty. 655 | int Board::get_value(int point) const 656 | { 657 | if (belongedGroup[point]) { 658 | return belongedGroup[point]->get_color() ? -1:1; 659 | } 660 | 661 | return 0; 662 | } 663 | 664 | float Board::score_count() const 665 | { 666 | int ret = 0; 667 | for (int i = 1; i <= size2; i++) { 668 | if (belongedGroup[i]) { 669 | ret += (-(belongedGroup[i]->get_color()<<1)+1); 670 | } else { 671 | if (is_surrounded(i, BLACK)) ++ret; 672 | else if (is_surrounded(i, WHITE)) --ret; 673 | } 674 | 675 | } 676 | 677 | return ret-komi; 678 | } 679 | 680 | void Board::score_area(int point_list[]) const 681 | { 682 | for (int i = 1; i <= size2; i++) { 683 | if (belongedGroup[i]) { 684 | if (belongedGroup[i]->get_color()) point_list[i]--; 685 | else point_list[i]++; 686 | } else { 687 | if (is_surrounded(i, WHITE)) point_list[i]--; 688 | else if (is_surrounded(i, BLACK)) point_list[i]++; 689 | } 690 | } 691 | } 692 | 693 | int Board::mercy() const 694 | { 695 | const int v = size2/3; 696 | for (int s = 0; s < 2; s++) { 697 | if (stones_on_board[s] - stones_on_board[1-s] > v) { 698 | return s; 699 | } 700 | } 701 | 702 | return -1; 703 | } 704 | 705 | void Board::print_goban() const 706 | { 707 | std::cerr << " "; 708 | for (int i = 0; i -1; y--) { 711 | std::cerr << " |"; 712 | for (int x = 1; x < size+1; x++) { 713 | if (belongedGroup[size*y + x]) { 714 | if (belongedGroup[size*y + x]->get_color()) std::cerr << "#"; 715 | else std::cerr << "o"; 716 | if (size*y + x == last_point) std::cerr << "!"; 717 | else std::cerr << " "; 718 | } else { 719 | std::cerr << ". "; 720 | } 721 | } 722 | std::cerr << "|" << y+1 << "\n"; 723 | } 724 | std::cerr << " "; 725 | for (int i = 0; iget_the_stone(0): 0); 731 | int lat2 = (last_atari[WHITE] ? last_atari[WHITE]->get_the_stone(0) : 0); 732 | std::cerr << " last atari: black " << lat1<< " white " << lat2 << "\n"; 733 | } 734 | 735 | 736 | void Board::record_goban() 737 | { 738 | ofstream ss("record.txt",ios::app); 739 | ss << " "; 740 | for (int i = 0; i -1; y--) { 743 | ss << " |"; 744 | for (int x = 1; x < size+1; x++) { 745 | if (belongedGroup[size*y + x]) { 746 | if (belongedGroup[size*y + x]->get_color()) ss << "#"; 747 | else ss << "o"; 748 | if (size*y + x == last_point) ss << "!"; 749 | else ss << " "; 750 | } else { 751 | ss << ". "; 752 | } 753 | } 754 | ss << "|" << y+1 << "\n"; 755 | } 756 | ss << " "; 757 | for (int i = 0; iget_the_stone(0): 0); 763 | int lat2 = (last_atari[WHITE] ? last_atari[WHITE]->get_the_stone(0) : 0); 764 | ss << " last atari: black " << lat1<< " white " << lat2 << "\n"; 765 | ss << " "; 766 | for (int i = 0; i -1; y--) { 769 | ss << " |"; 770 | for (int x = 1; x < size+1; x++) { 771 | ss << (belongedGroup[size*y+x]?belongedGroup[size*y+x]->get_libs_num():0) << " "; 772 | } 773 | ss << "|" << y+1 << "\n"; 774 | } 775 | ss.close(); 776 | } 777 | 778 | int Board::print_libs_of(int point, int libs[]) 779 | { 780 | int fa = belongedGroup[point]->get_father(); 781 | int num_lib = belongedGroup[fa]->get_libs_num(); 782 | int cnt = 0; 783 | for (Group::LibItr lit(belongedGroup[fa]); lit; ++lit){ 784 | libs[cnt++] = *lit; 785 | } 786 | 787 | return num_lib; 788 | } 789 | 790 | int Board::print_group_of(int point, int st[]) 791 | { 792 | int fa = belongedGroup[point]->get_father(); 793 | int num_st = belongedGroup[fa]->get_stones_num(); 794 | int cnt = 0; 795 | for (Group::StnItr lit(belongedGroup[fa]); lit; ++lit){ 796 | st[cnt++] = *lit; 797 | } 798 | 799 | return num_st; 800 | } 801 | 802 | int Board::first_legal_moves(int moves[],int last[],int flag,int cur_step) const 803 | { 804 | int nlegal = 0; 805 | int star_point[4] = {127,49,43,121}; 806 | 807 | if (!flag){ //flag == 0,不需要模拟,主要面向前几步 808 | int temp_board[MAXSIZE2 + 1] = {0}; 809 | for (int i = 0; i < empty_points.length(); ++i) 810 | temp_board[empty_points[i]] = 1; 811 | 812 | if (cur_step == -1){ 813 | for (int i = 0;i < 4; ++i) 814 | if(temp_board[star_point[i]] && is_legal(star_point[i],side)){ 815 | moves[nlegal++] = star_point[i]; 816 | break; 817 | } 818 | } 819 | 820 | else if(cur_step == 0){ 821 | for (int i = 0; i < 4; ++i) 822 | if(star_point[i] == last[0]){ 823 | if(temp_board[star_point[(i + 1)%4]]) 824 | moves[nlegal++] = star_point[(i + 1)%4]; 825 | else if (temp_board[star_point[(i + 3)%4]]) 826 | moves[nlegal++] = star_point[(i + 3)%4]; 827 | else{ 828 | for(int k = 0; k < 8; ++k) 829 | if (temp_board[eight_around[star_point[(i + 1)%4]][k]]) 830 | moves[nlegal++] = eight_around[star_point[(i + 1)%4]][k]; 831 | } 832 | break; 833 | } 834 | }else if(cur_step == 1){ 835 | int mid_point = (last[0] + last[1]) / 2; 836 | for(int i = 0; i < 8; ++i) 837 | if (temp_board[eight_around[mid_point][i]]) 838 | moves[nlegal++] = eight_around[mid_point][i]; 839 | } 840 | 841 | if(nlegal == 0){ 842 | for (int i = 0; i < empty_points.length(); i++) { 843 | int point = empty_points[i]; 844 | if (is_legal(point, side)) { 845 | moves[nlegal++] = point; 846 | } 847 | } 848 | } 849 | } // need simulation, mainly to the previous 20 steps 850 | else if (flag == 2){ 851 | if(ONE_EXIST) 852 | return legal_moves(moves); 853 | for (int i = 0; i < empty_points.length(); i++) { 854 | int point = empty_points[i]; 855 | if (board_map[point] != 1 && is_legal(point, side)) { 856 | moves[nlegal++] = point; 857 | } 858 | } 859 | moves[nlegal++] = PASS; 860 | }// need simulation, mainly to the previous 10 steps 861 | else if (flag == 1){ 862 | if(TWO_EXIST) 863 | return legal_moves(moves); 864 | for (int i = 0; i < empty_points.length(); i++) { 865 | int point = empty_points[i]; 866 | if (!board_map[point] && is_legal(point, side)) { 867 | moves[nlegal++] = point; 868 | } 869 | } 870 | moves[nlegal++] = PASS; 871 | } 872 | return nlegal; 873 | } 874 | 875 | -------------------------------------------------------------------------------- /badukGo-0.1.5/Board.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __BOARD_H__ 22 | #define __BOARD_H__ 23 | 24 | #include "group.h" 25 | #include "amaf.h" 26 | #include 27 | 28 | using namespace std; 29 | 30 | struct Prior{ 31 | double prior; 32 | double equiv; 33 | }; 34 | 35 | class Board{ 36 | private: 37 | static const bool BLACK = 0, WHITE = 1; 38 | unordered_set GroupFather; 39 | 40 | bool IS_REAL_GAME = 0; 41 | 42 | bool side_bu; 43 | int ko_point_bu; 44 | int size_bu, size2_bu; 45 | float komi_bu; 46 | int handicap_bu; 47 | 48 | Group groups_bu[MAXSIZE2+1]; 49 | EmptyPointSet empty_points_bu; 50 | int stones_on_board_bu[2]; 51 | int last_point_bu, last_point2_bu; 52 | int last_atari_black_bu; 53 | int last_atari_white_bu; 54 | bool side; 55 | int ko_point; 56 | int size, size2; 57 | float komi; 58 | int handicap; 59 | 60 | Group *belongedGroup[MAXSIZE2+1]; 61 | Group groups[MAXSIZE2+1]; 62 | int stones_on_board[2]; 63 | Group *last_atari[2]; 64 | int last_point, last_point2; 65 | 66 | int four_side[MAXSIZE2+1][5]; 67 | int four_corner[MAXSIZE2+1][5]; 68 | int eight_around[MAXSIZE2+1][16]; 69 | int distance2edge[MAXSIZE2+1]; 70 | int within_manhattan[MAXSIZE2+1][4][20]; 71 | 72 | EmptyPointSet empty_points; 73 | PointList<3*MAXSIZE2> game_history; 74 | 75 | 76 | void init_four_side(); 77 | void init_four_corner(); 78 | void init_eight_around(); 79 | void init_distance(); 80 | void init_manhattan(); 81 | void reset(); 82 | 83 | //special positions: 84 | bool is_tengen(int point) const; 85 | bool is_star_point(int point) const; 86 | bool is_point_3_3(int point) const; 87 | bool is_point_5_5(int point) const; 88 | bool is_point_3_4(int point) const; 89 | bool is_point_4_5(int point) const; 90 | bool is_point_3_5(int point) const; 91 | bool is_point_4_6(int point) const; 92 | 93 | 94 | //4-neighbours iterating methods: 95 | int point_liberties(int point) const; 96 | int point_liberties(int point, LList &liberties) const; 97 | int neighbour_groups(int point, GroupSet<4> &neighbours) const; 98 | int neighbour_groups(int point, GroupSet<4> &neighbours, Group *Greatgroup) const; 99 | int neighbour_groups(int point, bool color, int max_liberties, 100 | GroupSet *neighbours) const; 101 | int neighbour_groups(const Group *group, bool color, int max_liberties, 102 | GroupSet &neighbours) const; 103 | int neighbours_size(int point, bool color) const; 104 | int neighbours_in_atari(int point, bool color, const GroupSet<4> &neighbours) const; 105 | 106 | //Playing methods: 107 | int drop_stone(int point, bool color); 108 | int handle_neighbours(int point); 109 | void merge_neighbour(int point, Group *neighbour); 110 | void merge_neighbour(int point,GroupSet<4> * groupset, Group * Greatgroup); 111 | void erase_neighbour(Group *neighbour); 112 | inline void remove_empty(int point); 113 | 114 | bool is_surrounded(int point, bool color, int consider_occupied=0) const; 115 | bool is_true_eye(int point, bool color, int consider_occupied=0) const; 116 | bool is_false_eye(int point, bool color) const; 117 | bool is_legal(int point, bool color) const; 118 | 119 | //Heuristics: 120 | bool is_stones_around(int, int) const; 121 | int get_total_liberties(int, bool, LList*, int, const Group*) const; 122 | int atari_escapes(const Group*, LList&) const; 123 | bool grow_liberties(int, const Group*) const; 124 | bool is_self_atari(int, bool) const; 125 | int atari_last_liberty(int, bool) const; 126 | bool is_ladder(int, bool) const; 127 | int creates_eyes(int,bool) const; 128 | 129 | int random_choose(const LList&, bool(Board::*)(int, bool) const) const; 130 | bool random_method(int, bool) const; 131 | bool wiser_method(int, bool) const; 132 | int last_atari_trick() const; 133 | void nakade_trick(int, LList&) const; 134 | void capture_trick(int, LList&) const; 135 | void save_trick(int, LList&) const; 136 | void pattern_trick(int, LList&) const; 137 | bool is_match_mogo_pattern(int,bool) const; 138 | 139 | public: 140 | static const int PASS = 0; 141 | Board(int size = 13); 142 | int get_history_length()const {return game_history.length();} 143 | 144 | int get_empty_length(){return empty_points.length();} 145 | void clear(); 146 | void restore(); 147 | void set_komi(float newkomi) { komi = newkomi; } 148 | int set_size(int new_size); 149 | bool set_position(const LList &moves); 150 | bool set_position(const Board *original); 151 | 152 | void shuffle_empty() { empty_points.shuffle(); } 153 | int play_move(int point); 154 | int play_move(int point, bool color); 155 | int play_random(); 156 | int play_wiser(); 157 | 158 | float get_komi() const { return komi; } 159 | bool get_side() const { return side; } 160 | int get_size() const { return size; } 161 | int get_size2() const { return size2; } 162 | // int get_last_point() const { return last_point; } 163 | bool is_occupied(int point) const { return belongedGroup[point] != 0; } 164 | int get_value(int point) const; 165 | int legal_moves(int moves[]) const; 166 | int legal_moves_origin(int moves[]) const; 167 | float score_count() const; 168 | void score_area(int point_list[]) const; 169 | int mercy() const; 170 | void init_priors(Prior priors[]) const; 171 | void print_goban() const; 172 | void record_goban(); 173 | 174 | int print_libs_of(int point, int libs[]); 175 | int print_group_of(int point, int st[]); 176 | 177 | 178 | void backup(); 179 | void resume(); 180 | void copy_from(Board *board); 181 | int first_legal_moves(int moves[],int last[],int flag,int cur_step) const; 182 | // int get_last2() {if(!last_point2) last_point2 = 127; return last_point2;} 183 | 184 | }; 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /badukGo-0.1.5/Board_Thread.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "Board.h" 22 | #include "Go.h" 23 | #include 24 | 25 | #define BACKUP_NEED_CRITICAL_LIMIT_EMPTY 90 26 | #define RELATE_PRUNE 27 | #define LOCK_UCT_SELECT 28 | 29 | void Board::copy_from(Board *board) 30 | { 31 | side_bu = board->side; 32 | ko_point_bu = board->ko_point; 33 | size_bu = board->size, size2_bu = board->size2; 34 | komi_bu = board->komi; 35 | handicap_bu = board->handicap; 36 | empty_points_bu = board->empty_points; 37 | game_history = board->game_history; 38 | GroupFather = board->GroupFather; 39 | 40 | for (unordered_set::iterator it = (GroupFather).begin(); it != (GroupFather).end(); ++it){ 41 | groups_bu[*it] = board->groups[*it]; 42 | } 43 | 44 | stones_on_board_bu[1] = board->stones_on_board[1]; 45 | stones_on_board_bu[0] = board->stones_on_board[0]; 46 | last_point_bu = board->last_point, last_point2_bu = board->last_point2; 47 | last_atari_black_bu = board->last_atari[0]?board->last_atari[0]->get_father():0; 48 | last_atari_white_bu = board->last_atari[1]?board->last_atari[1]->get_father():0; 49 | 50 | resume(); 51 | } 52 | 53 | 54 | void Go::run_thread(int max_time_thread,Board *cur_board, AmafBoard *cur_amaf,int tid,int cur_step) 55 | { 56 | Node * n = NULL; 57 | #ifdef STD_ERR_PRINT 58 | std::cerr << "here!!" << std::endl; 59 | #endif 60 | rand_movs[tid-1] = 0; 61 | int nnode_hist = 0; 62 | Node *node_history[3*MAXSIZE2]; 63 | int result =2; 64 | int last[2]; 65 | bool side = -1; 66 | int simul_len_thread; 67 | int ct; 68 | int pruntime = 0; 69 | int prePunc = 0; 70 | int debugTime = fin_clock; 71 | int pass; 72 | double aver_winrate; 73 | Node *root; 74 | Node *node; 75 | float score; 76 | aver_winrate = (lastWinRate[main_board->get_side()] + last2WinRate[main_board->get_side()])/2 ; 77 | // std::cerr << "aver_winrate:" << aver_winrate<0.5*CLOCKS_PER_SEC){ 83 | debugTime = clock(); 84 | std::cerr << "id:" << tid << " time:" << debugTime <get_side(); 91 | root = tree.get_root(); 92 | 93 | Node *node; 94 | 95 | 96 | #ifdef RELATE_PRUNE 97 | if (aver_winrate>STOP_THERESHOLD) 98 | goto JUMP_R_PRUN; 99 | else if (aver_winrate > SOFT_THERESHOLD) 100 | r_prun_alpha = SOFT_R_PRUN_ALPHA; 101 | else if (aver_winrate> LAZY_THERESHOLD) 102 | r_prun_alpha = LAZY_R_PRUN_ALPHA; 103 | 104 | ct = (clock()-fin_clock)/CLOCKS_PER_SEC; 105 | if (cur_board->get_history_length() > BEGIN_PRUN && cur_board->get_history_length() < END_PRUN 106 | &&(tid == 1) && (!prePunc) && ((ct == 1 && pruntime == 0) || (ct ==2 && pruntime == 1))) 107 | { 108 | EnterCriticalSection(&TREE_CRITICAL); 109 | tree.do_r_prun(root->get_visits(),r_prun_alpha); 110 | LeaveCriticalSection(&TREE_CRITICAL); 111 | pruntime++; 112 | #ifdef STD_ERR_PRINT 113 | std::cerr << "prun_num:" << tree.relative_prun_num <get_visits() <set_up(cur_board->get_side(), cur_board->get_size()); 123 | node = root; 124 | nnode_hist = 0; 125 | 126 | while (node->has_childs() && pass < 2) { 127 | node_history[nnode_hist++] = node; 128 | #ifdef LOCK_UCT_SELECT 129 | EnterCriticalSection(&TREE_CRITICAL); 130 | #endif 131 | node = node->select_child(); 132 | #ifdef LOCK_UCT_SELECT 133 | LeaveCriticalSection(&TREE_CRITICAL); 134 | #endif 135 | int move = node->get_move(); 136 | 137 | if(move == Board::PASS) pass++; 138 | else pass = 0; 139 | 140 | cur_board->play_move(move); 141 | cur_amaf->play(move, ++simul_len_thread); 142 | } 143 | 144 | if (node->is_expand==0 &&(node->get_visits() >= EXPAND || node == root) ) { 145 | node->is_expand = tid; 146 | if (node->is_expand == tid){ 147 | Prior priors[MAXSIZE2+1] = {{0,0}}; 148 | int legal_moves[MAXSIZE2+1],nlegal; 149 | if(node == root){ 150 | //====分4-10步,10-20步情况,20步后===/// 151 | if (cur_step >= STEPS_BOUNDARY_TWO) 152 | nlegal = cur_board->legal_moves(legal_moves); 153 | else if (cur_step > STEPS_BOUNDARY_ONE && cur_step < STEPS_BOUNDARY_TWO) 154 | nlegal = cur_board->first_legal_moves(legal_moves,last,2,cur_step); 155 | else if (cur_step >= STEPS_START_END && cur_step <= STEPS_BOUNDARY_ONE) 156 | nlegal = cur_board->first_legal_moves(legal_moves,last,1,cur_step); 157 | else 158 | nlegal = cur_board->legal_moves(legal_moves); 159 | } 160 | else{ 161 | nlegal = cur_board->legal_moves_origin(legal_moves); 162 | } 163 | 164 | #ifdef NEED_PRIORS 165 | if ((aver_winrateget_history_length()>=8 && cur_board->get_empty_length()>20) 166 | cur_board->init_priors(priors); 167 | #endif 168 | 169 | EnterCriticalSection(&TREE_CRITICAL); 170 | tree.expand(node, legal_moves, nlegal, priors); 171 | LeaveCriticalSection(&TREE_CRITICAL); 172 | 173 | } 174 | } 175 | 176 | node_history[nnode_hist++] = node; 177 | score = 0; 178 | 179 | result = play_random_game_thread(cur_board->get_history_length()>8,simul_len_thread,cur_board,cur_amaf,tid,score); 180 | #ifdef DEBUG_INFO 181 | cur_board->print_board(); 182 | std::cerr << result << "\n"; 183 | #endif 184 | 185 | cur_board->resume(); 186 | if (result == -1) continue; 187 | if (side) result = 1-result,score = -score; 188 | 189 | EnterCriticalSection(&TREE_CRITICAL); 190 | #ifdef STD_ERR_PRINT 191 | if (nnode_hist > 1 && node_history[1] == NULL){ 192 | std::cerr<<"CAONIDAYE" < 1 && node_history[1] != NULL) 197 | // {node_history[1]->update_score(score);} 198 | back_up_results_thread(result, node_history, nnode_hist, side,cur_amaf,score); 199 | 200 | LeaveCriticalSection(&TREE_CRITICAL); 201 | } 202 | 203 | #ifdef STD_ERR_PRINT 204 | std::cerr << rand_movs[tid-1] << " " << tid << std::endl; 205 | #endif 206 | } 207 | 208 | int Go::play_random_game_thread(bool wiser, int simul_len_thread, 209 | Board *cur_board, AmafBoard *cur_amaf,int tid,float &score){ 210 | int pass = 0; 211 | int mercy; 212 | int size2 = cur_board->get_size2(); 213 | if (!rand()%10)cur_board->shuffle_empty(); 214 | while (pass < 2) { 215 | int move = wiser ? cur_board->play_wiser() : cur_board->play_random(); 216 | cur_amaf->play(move, ++simul_len_thread); 217 | 218 | rand_movs[tid-1]++; 219 | if (move == Board::PASS) pass++; 220 | else pass = 0; 221 | #ifdef DEBUG_INFO 222 | cur_board->print_board(); 223 | #endif 224 | 225 | int mercy = cur_board->mercy(); 226 | if (mercy != -1) { 227 | score = (((1-mercy)<<1)-1)*size2/3; 228 | return 1-mercy; 229 | } 230 | 231 | if (simul_len_thread > 2*cur_board->get_size2()) { 232 | std::cerr << "WARNING: Simulation exceeded max length.\n"; 233 | discarded++; 234 | return -1; 235 | } 236 | } 237 | 238 | return ((score = cur_board->score_count()) > 0); 239 | } 240 | 241 | void Go::back_up_results_thread(int result, Node *node_history[], int nnodes, bool side,AmafBoard *cur_amaf,float sc) 242 | { 243 | int t = -1; 244 | for (int i = 0; i < nnodes; i++) { 245 | if (node_history[i]->is_pruned) return; 246 | node_history[i]->update_score(t*sc); 247 | node_history[i]->set_results(1-result); 248 | node_history[i]->set_amaf(result, cur_amaf, side, i+1); 249 | side = !side; 250 | result = 1-result; 251 | t = -t; 252 | } 253 | } 254 | 255 | #ifdef NEED_PONDER 256 | void Go::start_ponder(int step) 257 | { 258 | if (step <= START_PONDER_STEP) return; 259 | is_ponder = true; 260 | std::cerr << "start pondering..." << std::endl; 261 | 262 | 263 | bool side = main_board->get_side(); 264 | int last[2]; 265 | Node *root = tree.get_root(); 266 | rand_movs[0] = 0, discarded = 0; 267 | double aver_winrate = (lastWinRate[side] + last2WinRate[side])/2 ; 268 | main_board->shuffle_empty(); 269 | 270 | 271 | #ifdef CHANGE_THEARD_NUM 272 | int empty_len = main_board->get_empty_length(); 273 | if (empty_len > FIRST_LEVEL_EMPTY){ 274 | real_thread_num = SYS_THREAD_LIMIT; 275 | }else if (empty_len > SECOND_LEVEL_EMPTY){ 276 | real_thread_num = min(4,SYS_THREAD_LIMIT); 277 | }else real_thread_num = 1; 278 | #else 279 | 280 | #endif 281 | for (int i=0; ithread_id = i+1; 284 | cid->orig_bd = main_board; 285 | cid->cur_bd = thread_board[i]; 286 | cid->step = step; 287 | cid->goo = this; 288 | cid->max_time_thread = 0; 289 | cid->tamaf = amaf_thread[i]; 290 | slave_thread[i] = CreateThread(NULL,0,slave_runner_ponder,cid,0,NULL); 291 | } 292 | return; 293 | } 294 | 295 | void Go::run_thread_ponder(int max_time_thread,Board *cur_board, AmafBoard *cur_amaf,int tid,int cur_step) 296 | { 297 | Node * n = NULL; 298 | #ifdef STD_ERR_PRINT 299 | std::cerr << "here!!" << std::endl; 300 | #endif 301 | rand_movs[tid-1] = 0; 302 | int nnode_hist = 0; 303 | Node *node_history[3*MAXSIZE2]; 304 | int result =2; 305 | int last[2]; 306 | bool side = -1; 307 | int simul_len_thread; 308 | int ct; 309 | int pruntime = 0; 310 | int prePunc = 0; 311 | int debugTime = fin_clock; 312 | int pass; 313 | double aver_winrate; 314 | Node *root; 315 | Node *node; 316 | float score; 317 | aver_winrate = (lastWinRate[main_board->get_side()] + last2WinRate[main_board->get_side()])/2 ; 318 | // std::cerr << "aver_winrate:" << aver_winrate<0.5*CLOCKS_PER_SEC){ 324 | debugTime = clock(); 325 | std::cerr << "id:" << tid << " time:" << debugTime <get_side(); 332 | root = tree.get_root(); 333 | if (root->get_visits()>PONDER_PLAYOUTS) break; 334 | 335 | Node *node; 336 | 337 | 338 | cur_amaf->set_up(cur_board->get_side(), cur_board->get_size()); 339 | node = root; 340 | nnode_hist = 0; 341 | 342 | while (node->has_childs() && pass < 2) { 343 | node_history[nnode_hist++] = node; 344 | #ifdef LOCK_UCT_SELECT 345 | EnterCriticalSection(&TREE_CRITICAL); 346 | #endif 347 | node = node->select_child(); 348 | #ifdef LOCK_UCT_SELECT 349 | LeaveCriticalSection(&TREE_CRITICAL); 350 | #endif 351 | int move = node->get_move(); 352 | 353 | if(move == Board::PASS) pass++; 354 | else pass = 0; 355 | 356 | cur_board->play_move(move); 357 | cur_amaf->play(move, ++simul_len_thread); 358 | } 359 | 360 | if (node->is_expand==0 &&(node->get_visits() >= EXPAND || node == root) ) { 361 | node->is_expand = tid; 362 | if (node->is_expand == tid){ 363 | Prior priors[MAXSIZE2+1] = {{0,0}}; 364 | int legal_moves[MAXSIZE2+1],nlegal; 365 | if(node == root){ 366 | //====分4-10步,10-20步情况,20步后===/// 367 | if (cur_step >= STEPS_BOUNDARY_TWO) 368 | nlegal = cur_board->legal_moves(legal_moves); 369 | else if (cur_step > STEPS_BOUNDARY_ONE && cur_step < STEPS_BOUNDARY_TWO) 370 | nlegal = cur_board->first_legal_moves(legal_moves,last,2,cur_step); 371 | else if (cur_step >= STEPS_START_END && cur_step <= STEPS_BOUNDARY_ONE) 372 | nlegal = cur_board->first_legal_moves(legal_moves,last,1,cur_step); 373 | else 374 | nlegal = cur_board->legal_moves(legal_moves); 375 | } 376 | else{ 377 | nlegal = cur_board->legal_moves_origin(legal_moves); 378 | } 379 | 380 | #ifdef NEED_PRIORS 381 | if ((aver_winrateget_history_length()>=8 && cur_board->get_empty_length()>20) 382 | cur_board->init_priors(priors); 383 | #endif 384 | 385 | EnterCriticalSection(&TREE_CRITICAL); 386 | tree.expand(node, legal_moves, nlegal, priors); 387 | LeaveCriticalSection(&TREE_CRITICAL); 388 | 389 | } 390 | } 391 | 392 | node_history[nnode_hist++] = node; 393 | score = 0; 394 | 395 | result = play_random_game_thread(cur_board->get_history_length()>8,simul_len_thread,cur_board,cur_amaf,tid,score); 396 | #ifdef DEBUG_INFO 397 | cur_board->print_board(); 398 | std::cerr << result << "\n"; 399 | #endif 400 | 401 | cur_board->resume(); 402 | if (result == -1) continue; 403 | if (side) result = 1-result,score = -score; 404 | 405 | EnterCriticalSection(&TREE_CRITICAL); 406 | #ifdef STD_ERR_PRINT 407 | if (nnode_hist > 1 && node_history[1] == NULL){ 408 | std::cerr<<"CAONIDAYE" < 1 && node_history[1] != NULL) 413 | // {node_history[1]->update_score(score);} 414 | back_up_results_thread(result, node_history, nnode_hist, side,cur_amaf,score); 415 | 416 | LeaveCriticalSection(&TREE_CRITICAL); 417 | } 418 | 419 | #ifdef STD_ERR_PRINT 420 | std::cerr << rand_movs[tid-1] << " " << tid << std::endl; 421 | #endif 422 | } 423 | 424 | #endif -------------------------------------------------------------------------------- /badukGo-0.1.5/FastLog.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef FASTLOG_H 22 | #define FASTLOG_H 23 | #include 24 | #include 25 | #define MAX_MANTISSA_BITS 23 26 | 27 | 28 | class FastLog 29 | { 30 | public: 31 | FastLog(int mantissaBits) 32 | : m_mantissaBitsDiff(MAX_MANTISSA_BITS - mantissaBits) 33 | { 34 | m_lookupTable = new float[1 << mantissaBits]; 35 | IntFloat x; 36 | x.m_int = 0x3F800000; 37 | int incr = (1 << m_mantissaBitsDiff); 38 | int p = static_cast(pow(2.0f, mantissaBits)); 39 | float invLogTwo = 1.f / log(2.f); 40 | for (int i = 0; i < p; ++i) 41 | { 42 | m_lookupTable[i] = log(x.m_float) * invLogTwo; 43 | x.m_int += incr; 44 | } 45 | } 46 | ~FastLog() 47 | { 48 | delete[] m_lookupTable; 49 | } 50 | 51 | 52 | float Log(float val) const; 53 | 54 | private: 55 | union IntFloat 56 | { 57 | int m_int; 58 | 59 | float m_float; 60 | }; 61 | const int m_mantissaBitsDiff; 62 | float* m_lookupTable; 63 | }; 64 | 65 | inline float FastLog::Log(float val) const 66 | { 67 | IntFloat x; 68 | x.m_float = val; 69 | int logTwo = ((x.m_int >> MAX_MANTISSA_BITS) & 255) - 127; 70 | x.m_int &= 0x7FFFFF; 71 | x.m_int >>= m_mantissaBitsDiff; 72 | return ((m_lookupTable[x.m_int] + float(logTwo)) * 0.69314718f); 73 | } 74 | #endif 75 | -------------------------------------------------------------------------------- /badukGo-0.1.5/Go.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include 22 | #include 23 | #include "Go.h" 24 | 25 | const double TIME_TOLERANCE = 0.01; 26 | const double TIME_UP_LIMIT_SYSTEM = 3; 27 | const double TIME_LIMIT = TIME_UP_LIMIT_SYSTEM-TIME_TOLERANCE; 28 | // #define CHANGE_THEARD_NUM 29 | 30 | 31 | Go::Go(Board *board):tree(DEF_TREESIZE, board), amaf(board->get_size()) 32 | { 33 | 34 | lastWinRate[0] = lastWinRate[1] = last2WinRate[0] = last2WinRate[1] = 0.0; 35 | r_prun_alpha = AGRESSIVE_R_PRUN_ALPHA; 36 | #ifdef _RWLOCK_ 37 | InitializeSRWLock(&TREE_SRW); 38 | #else 39 | InitializeCriticalSection(&TREE_CRITICAL); 40 | #endif 41 | SYSTEM_INFO sinfo; 42 | GetSystemInfo(&sinfo); 43 | SYS_THREAD_LIMIT = max(min((int)sinfo.dwNumberOfProcessors,MAX_THREAD_LIMIT),4); 44 | real_thread_num = SYS_THREAD_LIMIT; 45 | main_board = board; 46 | max_playouts = DEF_PLAYOUTS; 47 | max_time = TIME_LIMIT*CLOCKS_PER_SEC; 48 | //max_time = INFINITE; 49 | tree_size = DEF_TREESIZE; 50 | memset(rand_movs,0,sizeof rand_movs); 51 | for (int i=0; iget_size()); 53 | amaf_thread[i] = new AmafBoard(board->get_size()); 54 | } 55 | } 56 | 57 | void Go::reset() 58 | { 59 | memset(rand_movs,0,sizeof rand_movs); 60 | tree.clear(); 61 | amaf.set_up(main_board->get_side(), main_board->get_size()); 62 | } 63 | 64 | void Go::set_playouts(int playouts) 65 | { 66 | max_playouts = playouts; 67 | max_time = INFINITE; 68 | } 69 | 70 | 71 | int Go::play_random_game(bool wiser,float &score) 72 | { 73 | int pass = 0; 74 | int mercy; 75 | int size2 = main_board->get_size2(); 76 | if (!rand()%10)main_board->shuffle_empty(); 77 | while (pass < 2) { 78 | int move = wiser ? main_board->play_wiser() : main_board->play_random(); 79 | amaf.play(move, ++simul_len); 80 | rand_movs[0]++; 81 | if (move == Board::PASS) pass++; 82 | else pass = 0; 83 | #ifdef DEBUG_INFO 84 | main_board->print_board(); 85 | #endif 86 | int mercy = main_board->mercy(); 87 | if (mercy != -1) { 88 | score = (((1-mercy)<<1)-1)*size2/3; 89 | return 1-mercy; 90 | } 91 | if (simul_len > 2*main_board->get_size2()) { 92 | std::cerr << "WARNING: Simulation exceeded max length.\n"; 93 | discarded++; 94 | return -1; 95 | } 96 | } 97 | return ((score = main_board->score_count()) > 0); 98 | } 99 | 100 | int Go::generate_move(bool early_pass,int cur_step) 101 | { 102 | bool side = main_board->get_side(); 103 | int last[2]; 104 | Node *root = tree.get_root(); 105 | std::cerr <<"root_visit_by_pondering: "<< root->get_visits() << std::endl; 106 | rand_movs[0] = 0, discarded = 0; 107 | double aver_winrate = (lastWinRate[side] + last2WinRate[side])/2 ; 108 | main_board->shuffle_empty(); 109 | 110 | fin_clock = clock(); 111 | 112 | #ifdef CHANGE_THEARD_NUM 113 | int empty_len = main_board->get_empty_length(); 114 | if (empty_len > FIRST_LEVEL_EMPTY){ 115 | real_thread_num = SYS_THREAD_LIMIT; 116 | }else if (empty_len > SECOND_LEVEL_EMPTY){ 117 | real_thread_num = min(4,SYS_THREAD_LIMIT); 118 | }else real_thread_num = 1; 119 | #else 120 | 121 | #endif 122 | 123 | for (int i=0; ithread_id = i+1; 126 | cid->orig_bd = main_board; 127 | cid->cur_bd = thread_board[i]; 128 | cid->step = cur_step; 129 | cid->goo = this; 130 | cid->max_time_thread = max_time; 131 | cid->tamaf = amaf_thread[i]; 132 | slave_thread[i] = CreateThread(NULL,0,slave_runner,cid,0,NULL); 133 | } 134 | WaitForMultipleObjects(real_thread_num,slave_thread,true,INFINITE); 135 | for (int i=0; iget_value(1); 143 | std:cerr << "winrate: " << lastWinRate[side] << " " << last2WinRate[side] << std::endl; 144 | #ifdef STD_ERR_PRINT 145 | print_PV(); 146 | #endif 147 | if (best->get_move() == Board::PASS) return Board::PASS; 148 | std::cerr << best->get_value(1) <get_visits() << std::endl; 150 | std::cerr << "best score:" << best->get_score() << std::endl; 151 | return best->get_move(); 152 | } 153 | 154 | void Go::back_up_results(int result, Node *node_history[], int nnodes, bool side) 155 | { 156 | for (int i = 0; i < nnodes; i++) { 157 | node_history[i]->set_results(1-result); 158 | node_history[i]->set_amaf(result, amaf, side, i+1); 159 | side = !side; 160 | result = 1-result; 161 | } 162 | } 163 | 164 | void Go::print_PV() const 165 | { 166 | #ifdef STD_ERR_PRINT 167 | fin_clock = clock() - fin_clock; 168 | bool side = main_board->get_side(); 169 | 170 | tree.print((last2WinRate[side] + lastWinRate[side])/2); 171 | int nplayouts = tree.get_root()->get_visits(); 172 | int rand_movettl = 0; 173 | for (int i=0; iget_history_length() 176 | << ", empty_length: " << main_board->get_empty_length() 177 | << ", average length: " << (rand_movettl)/nplayouts 178 | << ", discarded: " << discarded << ", playouts/sec: " 179 | << (float)nplayouts/fin_clock*CLOCKS_PER_SEC << "\n"; 180 | main_board->print_goban(); 181 | #endif 182 | } 183 | 184 | float Go::score(std::vector *dead) 185 | { 186 | const int PLAYOUTS = 5000; 187 | int score = 0; 188 | float tmp; 189 | int score_table[MAXSIZE2+1] = {0}; 190 | for (int i = 0; i < PLAYOUTS; i++) { 191 | simul_len = 0; 192 | play_random_game(LIGHT,tmp); 193 | main_board->score_area(score_table); 194 | main_board->restore(); 195 | } 196 | for (int i = 1; i <= main_board->get_size2(); i++) { 197 | if (score_table[i] > PLAYOUTS/2) score_table[i] = 1; 198 | else if (score_table[i] < -PLAYOUTS/2) score_table[i] = -1; 199 | else score_table[i] = 0; 200 | 201 | if (dead && main_board->get_value(i) 202 | && score_table[i] != main_board->get_value(i)) { 203 | dead->insert(dead->end(), i); 204 | } 205 | } 206 | 207 | for (int i = 1; i <= main_board->get_size2(); i++) { 208 | score += score_table[i]; 209 | } 210 | return score - main_board->get_komi(); 211 | } 212 | 213 | void Go::perft(int max) 214 | { 215 | 216 | } 217 | 218 | 219 | DWORD WINAPI slave_runner(void *args){ 220 | 221 | struct id * cid = (id*)args; 222 | srand(cid->thread_id*time(NULL)+1); 223 | cid->cur_bd->copy_from(cid->orig_bd); 224 | cid->goo->run_thread(cid->max_time_thread,cid->cur_bd,cid->tamaf,cid->thread_id,cid->step); 225 | return 0; 226 | } 227 | #ifdef NEED_PONDER 228 | DWORD WINAPI slave_runner_ponder(void *args){ 229 | 230 | struct id * cid = (id*)args; 231 | srand(cid->thread_id*time(NULL)+1); 232 | cid->cur_bd->copy_from(cid->orig_bd); 233 | cid->goo->run_thread_ponder(cid->max_time_thread,cid->cur_bd,cid->tamaf,cid->thread_id,cid->step); 234 | return 0; 235 | } 236 | #endif -------------------------------------------------------------------------------- /badukGo-0.1.5/Go.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __GO_H__ 22 | #define __GO_H__ 23 | #include 24 | #include "Board.h" 25 | #include "amaf.h" 26 | #include "tree.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #define FIRST_LEVEL_EMPTY 70 33 | #define SECOND_LEVEL_EMPTY 35 34 | #define MAX_THREAD_LIMIT 6 35 | #define EXPAND 8 36 | #define NEED_PRIORS 37 | #ifdef NEED_PRIORS 38 | #define STOP_PRIORS_WINRATE_THERESHOLD 0.87 39 | #endif 40 | const int FIRST_R_PRUN_TIME = 1; 41 | const int SECOND_R_PRUN_TIME = 2; 42 | 43 | class Go{ 44 | private: 45 | const bool HEAVY = true, LIGHT = false; 46 | int SYS_THREAD_LIMIT; 47 | int real_thread_num; 48 | double r_prun_alpha; 49 | double lastWinRate[2],last2WinRate[2]; 50 | CRITICAL_SECTION TREE_CRITICAL; 51 | HANDLE slave_thread[MAX_THREAD_LIMIT]; 52 | Board *main_board; 53 | Board *thread_board[MAX_THREAD_LIMIT]; 54 | AmafBoard *amaf_thread[MAX_THREAD_LIMIT]; 55 | int tree_size, max_playouts; 56 | int rand_movs[MAX_THREAD_LIMIT], simul_len, discarded; 57 | Tree tree; 58 | AmafBoard amaf; 59 | mutable clock_t fin_clock, max_time; 60 | #ifdef NEED_PONDER 61 | bool is_ponder; 62 | #endif 63 | 64 | int get_best_move() const; 65 | int play_random_game(bool wiser, float &score); 66 | int play_random_game_thread(bool wiser, int simul_len_thread, 67 | Board *cur_board, AmafBoard *cur_amaf, int tid, float &score); 68 | 69 | void back_up_results(int result, Node *node_history[], int nnodes, bool side); 70 | void back_up_results_thread(int result, Node *node_history[], 71 | int nnodes, bool side,AmafBoard *cur_amaf,float sc); 72 | void print_PV() const; 73 | 74 | 75 | public: 76 | 77 | Go(Board *board); 78 | ~Go(){ 79 | DeleteCriticalSection(&TREE_CRITICAL); 80 | for (int i=0; i *dead); 104 | int generate_move(bool early_pass,int); 105 | void perft(int max); 106 | void report_move(int move,int step) { tree.promote(move,step); } 107 | 108 | 109 | 110 | 111 | }; 112 | 113 | 114 | 115 | struct id{ 116 | int thread_id; 117 | Board *orig_bd; 118 | Board *cur_bd; 119 | Go *goo; 120 | int step; 121 | int max_time_thread; 122 | AmafBoard * tamaf; 123 | }; 124 | 125 | #ifndef SLAVE_RUNNER 126 | #define SLAVE_RUNNER 127 | DWORD WINAPI slave_runner(void *args); 128 | #ifdef NEED_PONDER 129 | DWORD WINAPI slave_runner_ponder(void *args); 130 | #endif 131 | #endif 132 | 133 | 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /badukGo-0.1.5/Makefile: -------------------------------------------------------------------------------- 1 | NAME=BadukGO 2 | CXX=g++ 3 | CXXFLAGS=--std=gnu++11 -Wall -Wno-unused -Ofast -flto -ffast-math 4 | CSTATLIB=-static-libgcc 5 | CSTATSTD=-static-libstdc++ 6 | 7 | CXXSRCS=*.cpp 8 | CXXPARAM=$(CSTATLIB) $(CSTATSTD) $(CXXFLAGS) 9 | 10 | 11 | $(NAME): $(CXXSRCS) 12 | $(CXX) $(CXXSRCS) -o $(NAME) $(CXXPARAM) 13 | -------------------------------------------------------------------------------- /badukGo-0.1.5/amaf.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __AMAF_H__ 22 | #define __AMAF_H__ 23 | #include "base.h" 24 | #include 25 | 26 | class AmafBoard{ 27 | private: 28 | int board[MAXSIZE2+1]; 29 | int size; 30 | bool side; 31 | 32 | public: 33 | AmafBoard(int sz = 13) 34 | { 35 | size = sz <= MAXSIZE ? sz : MAXSIZE; 36 | side = 0; 37 | clear(); 38 | } 39 | 40 | void clear() 41 | { 42 | for (int i = 0; i <= size*size; i++) { 43 | board[i] = 0; 44 | } 45 | } 46 | 47 | void set_up(bool sd, int sz) 48 | { 49 | size = sz; 50 | side = sd; 51 | clear(); 52 | } 53 | 54 | int play(int coord, int depth) 55 | { 56 | if (board[coord] == 0) { 57 | board[coord] = side ? -depth : depth; 58 | side = !side; 59 | return 0; 60 | } else { 61 | side = !side; 62 | return -1; 63 | } 64 | } 65 | 66 | double value(int coord, int depth, bool side, double discount) const 67 | { 68 | if (coord == 0) return 0.0; 69 | int val = side ? -board[coord] : board[coord]; 70 | if (val >= depth) { 71 | return 1.0-val*discount; 72 | } else { 73 | return 0; 74 | } 75 | } 76 | 77 | void print() const{ 78 | for (int y = size - 1; y > -1; y--) { 79 | std::cerr << " |"; 80 | for (int x = 1; x < size+1; x++) { 81 | 82 | if (board[size*y + x] < 0) { 83 | std::cerr << std::setw(3) << board[size*y + x] << "|"; 84 | } else if(board[size*y + x] > 0) { 85 | std::cerr << std::setw(3) << board[size*y + x] << "|"; 86 | } else { 87 | std::cerr << " |"; 88 | } 89 | } 90 | std::cerr << "|" << "\n"; 91 | } 92 | std::cerr << "pass: " << board[0] << "\n"; 93 | } 94 | }; 95 | #endif 96 | -------------------------------------------------------------------------------- /badukGo-0.1.5/baduk.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "Board.h" 22 | 23 | int Board::random_choose(const LList &list, bool(Board::*Play)(int, bool) const) const 24 | { 25 | if (list.length() == 0) return 0; 26 | int i = rand() % list.length(); 27 | int cnt = 0; 28 | for ( ; (++cnt)<20; i=rand() % list.length() ) { 29 | int point = list[i]; 30 | if ((this->*Play)(point, side)) { 31 | return point; 32 | } 33 | } 34 | for (int j = i; j*Play)(point, side)) { 37 | return point; 38 | } 39 | } 40 | 41 | 42 | for (int j = 0; j < i; ++j) { 43 | int point = list[j]; 44 | if ((this->*Play)(point, side)) { 45 | return point; 46 | } 47 | } 48 | return PASS; 49 | } 50 | 51 | bool Board::random_method(int point, bool side) const 52 | { 53 | if (is_false_eye(point, side)) return false; 54 | if (!is_legal(point, side)) return false; 55 | return true; 56 | } 57 | 58 | bool Board::wiser_method(int point, bool side) const 59 | { 60 | if (is_false_eye(point, side)) return false; 61 | if (!is_legal(point, side)) return false; 62 | if (is_self_atari(point, side)) return false; 63 | if (is_ladder(point,side)) return false; 64 | return true; 65 | } 66 | 67 | int Board::play_random() 68 | { 69 | return play_move(random_choose(empty_points, &Board::random_method)); 70 | } 71 | 72 | int Board::play_wiser() 73 | { 74 | if (int move = last_atari_trick()) { 75 | return play_move(move); 76 | } 77 | 78 | 79 | if (last_point) { 80 | PointSet list; 81 | if (rand()%10<9){ 82 | nakade_trick(last_point, list); 83 | if (int move = random_choose(list, &Board::wiser_method)) { 84 | return play_move(move); 85 | } 86 | list.clear(); 87 | } 88 | if (rand()%10<9){ 89 | save_trick(last_point, list); 90 | if (int move = random_choose(list, &Board::wiser_method)) { 91 | return play_move(move); 92 | } 93 | list.clear(); 94 | } 95 | pattern_trick(last_point, list); 96 | if (int move = random_choose(list, &Board::wiser_method)) { 97 | return play_move(move); 98 | } 99 | list.clear(); 100 | #define CAPTURE_HEURISTICS 101 | #ifdef CAPTURE_HEURISTICS 102 | // list.clear(); 103 | if (rand()%10<9){ 104 | capture_trick(last_point, list); 105 | if (int move = random_choose(list, &Board::wiser_method)) { 106 | return play_move(move); 107 | } 108 | } 109 | #endif 110 | } 111 | 112 | 113 | return play_random(); 114 | } 115 | 116 | int Board::last_atari_trick() const 117 | { 118 | if (Group *group = last_atari[!side]) { 119 | int move = group->get_the_lib(0); 120 | if (is_legal(move, side) && 121 | !is_self_atari(move, side) && 122 | grow_liberties(move, group)) { 123 | return move; 124 | } 125 | } 126 | 127 | PointList save; 128 | if (last_atari[side]) { 129 | atari_escapes(last_atari[side], save); 130 | if (int move = random_choose(save, &Board::wiser_method)) { 131 | return move; 132 | } 133 | } 134 | return 0; 135 | } 136 | 137 | void Board::nakade_trick(int point, LList &list) const 138 | { 139 | for (int i = 0; i < 8; i++) { 140 | if (int v = eight_around[point][i]) { 141 | if (belongedGroup[v] == 0 && (creates_eyes(v, 0) > 1 || creates_eyes(v, 1) > 1)) { 142 | list.add(v); 143 | } 144 | } 145 | } 146 | } 147 | 148 | void Board::capture_trick(int point, LList &list) const 149 | { 150 | for (int i = 0; i < 8; i++) { 151 | Group *group = belongedGroup[eight_around[point][i]]; 152 | if (group && group->get_color() != side && group->has_one_liberty()) { 153 | int lib = group->get_the_lib(0); 154 | if (grow_liberties(lib, group)) { 155 | list.add(lib); 156 | } 157 | } 158 | } 159 | } 160 | 161 | void Board::save_trick(int point, LList &list) const 162 | { 163 | if (belongedGroup[point] && belongedGroup[point]->get_libs_num() == 2) { 164 | for (int i = 0; i < 2; i++) { 165 | int lib = belongedGroup[point]->get_the_lib(i); 166 | if (grow_liberties(lib, belongedGroup[point])) { 167 | list.add(lib); 168 | } 169 | } 170 | } 171 | GroupSet<4> neigh; 172 | int nneigh = neighbour_groups(point, neigh); 173 | for (int j = 0; j < nneigh; j++) { 174 | if (neigh[j]->get_color() == side && neigh[j]->get_libs_num() <= 2) { // <2? 175 | atari_escapes(neigh[j], list); 176 | } 177 | } 178 | } 179 | 180 | void Board::pattern_trick(int point, LList &list) const 181 | { 182 | for (int i = 0; i < 8; i++) { 183 | if (int v = eight_around[point][i]) { 184 | if (belongedGroup[v] == 0 && is_match_mogo_pattern(v, side)) { 185 | list.add(v); 186 | } 187 | } 188 | } 189 | } 190 | 191 | bool Board::is_stones_around(int point, int distance) const 192 | { 193 | for (int i = 0; i < distance; i++) { 194 | for (int j = 0; j < 4*(i+1); j++) { 195 | int v = within_manhattan[point][i][j]; 196 | if (is_occupied(v)) return true; 197 | } 198 | } 199 | return false; 200 | } 201 | 202 | int Board::get_total_liberties(int point, bool color, LList *liberties, int enough=0, const Group *exclude=0) const 203 | { 204 | PointSet libs; 205 | if (liberties) point_liberties(point, *liberties); 206 | point_liberties(point, libs); 207 | if (enough && libs.length() > enough) return libs.length(); 208 | 209 | GroupSet<4> neighbours; 210 | int nneigh = neighbour_groups(point, neighbours); 211 | for (int i = 0; i < nneigh; i++) { 212 | const Group *curr_neigh = neighbours[i]; 213 | if (curr_neigh != exclude) { 214 | if (curr_neigh->get_color() == color) { 215 | for (Group::LibItr lib(curr_neigh); lib; ++lib) { 216 | if (*lib != point) { 217 | if (liberties) liberties->add(*lib); 218 | libs.add(*lib); 219 | if (enough && libs.length() > enough) return libs.length(); 220 | } 221 | } 222 | } else if (curr_neigh->get_libs_num() == 1) { 223 | for (Group::StnItr st(curr_neigh); st; ++st) { 224 | for (int j = 0; four_side[*st][j]; j++) { 225 | if (four_side[*st][j] == point) { 226 | libs.add(*st); 227 | if (enough && libs.length() > enough) return libs.length(); 228 | } else if (belongedGroup[four_side[*st][j]] && 229 | belongedGroup[four_side[*st][j]]->get_color() == color) { 230 | for (int k = 0; k < nneigh; k++) { 231 | if (belongedGroup[four_side[*st][j]] == neighbours[k]) { 232 | libs.add(*st); 233 | if (enough && libs.length() > enough) return libs.length(); 234 | } 235 | } 236 | } 237 | } 238 | } 239 | } 240 | } 241 | } 242 | return libs.length(); 243 | } 244 | 245 | bool Board::grow_liberties(int point, const Group *group) const 246 | { 247 | int curr_liberties = 1; 248 | if (group) curr_liberties = group->get_libs_num(); 249 | int nlibs = get_total_liberties(point, group->get_color(), 0, curr_liberties, group); 250 | return nlibs > curr_liberties; 251 | } 252 | 253 | bool Board::is_self_atari(int point, bool color) const 254 | { 255 | return (get_total_liberties(point, color, 0, 1) == 1); 256 | } 257 | 258 | int Board::atari_last_liberty(int point, bool color) const 259 | { 260 | PointSet liberties; 261 | if (get_total_liberties(point, color, &liberties, 1) == 1) return liberties[0]; //Maybe 0! 262 | return -1; 263 | } 264 | 265 | int Board::atari_escapes(const Group *group, LList &escapes) const 266 | { 267 | for (Group::LibItr lib(group); lib; ++lib) { 268 | if (grow_liberties(*lib, group)) { 269 | escapes.add(*lib); 270 | } 271 | } 272 | GroupSet neighbours; 273 | int nneigh = neighbour_groups(group, !group->get_color(), group->get_libs_num(), neighbours); 274 | for (int i = 0; i < nneigh; i++) { 275 | for (Group::LibItr lib(neighbours[i]); lib; ++lib) { 276 | if (grow_liberties(*lib, group)) { 277 | escapes.add(*lib); 278 | } 279 | } 280 | } 281 | return escapes.length(); 282 | } 283 | 284 | bool Board::is_ladder(int point, bool color) const 285 | { 286 | if (get_total_liberties(point, color, 0) != 2) return false; 287 | if (neighbour_groups(point, !color, 2, 0)) return false; 288 | PointList<5> liberties; 289 | point_liberties(point, liberties); 290 | for (int i = 0; i < liberties.length(); i++) { 291 | PointList<5> secondary_libs; 292 | int delta[2] = {0}; 293 | if (point_liberties(liberties[i], secondary_libs) == 4) continue; 294 | 295 | delta[0] = liberties[i] - point; 296 | for (int j = 0; j < secondary_libs.length(); j++) { 297 | if (secondary_libs[j] != point && secondary_libs[j] != liberties[i] + delta[0]) { 298 | delta[1] = secondary_libs[j] - liberties[i]; 299 | break; 300 | } 301 | } 302 | if (delta[1] == 0) return true; 303 | int p = point, act = 0; 304 | while (distance2edge[p] > 1) { 305 | p = p + delta[act]; 306 | if (belongedGroup[p]) { 307 | if (belongedGroup[p]->get_color() == color) break; 308 | else return true; 309 | } 310 | if (belongedGroup[p + delta[act]]) { 311 | if (belongedGroup[p + delta[act]]->get_color() == color) break; 312 | else return true; 313 | } 314 | act = 1-act; 315 | } 316 | if (distance2edge[p] < 2) return true; 317 | } 318 | return false; 319 | } 320 | 321 | int Board::creates_eyes(int point, bool color) const 322 | { 323 | int neyes = 0; 324 | for (int i = 0; four_side[point][i]; i++) { 325 | if (is_true_eye(four_side[point][i], color, point)) { 326 | neyes++; 327 | } 328 | } 329 | return neyes; 330 | } 331 | 332 | 333 | 334 | 335 | 336 | bool Board::is_match_mogo_pattern(int point, bool side) const 337 | { 338 | if (point == 1 || point == size || point == size2 || point == size*(size-1)+1) return false; //filter corners. 339 | 340 | if (point > size && point % size && point <= size*(size-1) && point % size != 1) { 341 | const int *vic = eight_around[point]; 342 | for (int i = 1; i < 8; i+=2) { 343 | if (belongedGroup[vic[i]]) { 344 | bool adj_color = belongedGroup[vic[i]]->get_color(); 345 | if (belongedGroup[vic[i-1]] && belongedGroup[vic[i-1]]->get_color() != adj_color) { 346 | if (belongedGroup[vic[i+2]] == 0 && belongedGroup[vic[i+6]] == 0) { 347 | if (belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() != adj_color) { 348 | return true; 349 | } 350 | if (belongedGroup[vic[i+1]] == 0 && belongedGroup[vic[i+4]] == 0) { 351 | return true; 352 | } 353 | } 354 | if (belongedGroup[vic[i+2]] == 0 && belongedGroup[vic[i+4]] == 0 && 355 | belongedGroup[vic[i+6]] && belongedGroup[vic[i+6]]->get_color() != adj_color) { 356 | return true; 357 | } 358 | if (belongedGroup[vic[i+6]] && belongedGroup[vic[i+6]]->get_color() == adj_color) { 359 | if ((belongedGroup[vic[i+2]] || belongedGroup[vic[i+4]] == 0 || belongedGroup[vic[i+4]]->get_color() == adj_color) && 360 | (belongedGroup[vic[i+4]] || belongedGroup[vic[i+2]] == 0 || belongedGroup[vic[i+2]]->get_color() == adj_color)) { 361 | return true; 362 | } 363 | } 364 | } 365 | if (belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() != adj_color) { 366 | if (belongedGroup[vic[i+2]] == 0 && belongedGroup[vic[i+6]] == 0) { 367 | if (belongedGroup[vic[i-1]] == 0 && belongedGroup[vic[i+4]] == 0) { 368 | return true; 369 | } 370 | } 371 | if (belongedGroup[vic[i+4]] == 0 && belongedGroup[vic[i+6]] == 0 && 372 | belongedGroup[vic[i+2]] && belongedGroup[vic[i+2]]->get_color() != adj_color) { 373 | return true; 374 | } 375 | } 376 | if (belongedGroup[vic[i+2]] && belongedGroup[vic[i+6]] && belongedGroup[vic[i+2]]->get_color() != adj_color && 377 | belongedGroup[vic[i+6]]->get_color() != adj_color && 378 | (belongedGroup[vic[i+4]] == 0 || belongedGroup[vic[i+4]]->get_color() == adj_color) && 379 | (belongedGroup[vic[i+3]] == 0 || belongedGroup[vic[i+3]]->get_color() == adj_color) && 380 | (belongedGroup[vic[i+5]] == 0 || belongedGroup[vic[i+5]]->get_color() == adj_color)) { 381 | return true; 382 | } 383 | if (adj_color != side && belongedGroup[vic[i-1]] && belongedGroup[vic[i-1]]->get_color() == side && 384 | belongedGroup[vic[i+2]] == 0 && belongedGroup[vic[i+4]] == 0 && belongedGroup[vic[i+6]] == 0 && 385 | belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() == adj_color) { 386 | return true; 387 | } 388 | if (adj_color != side && belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() == side && 389 | belongedGroup[vic[i+2]] == 0 && belongedGroup[vic[i+4]] == 0 && belongedGroup[vic[i+6]] == 0 && 390 | belongedGroup[vic[i-1]] && belongedGroup[vic[i-1]]->get_color() == adj_color) { 391 | return true; 392 | } 393 | } 394 | } 395 | } else { 396 | for (int i = 1; i < 8; i+=2) { 397 | const int *vic = eight_around[point]; 398 | if (vic[i]) { 399 | if (belongedGroup[vic[i]]) { 400 | if (vic[i+2] && belongedGroup[vic[i+2]] && belongedGroup[vic[i+2]]->get_color() != belongedGroup[vic[i]]->get_color() && 401 | (vic[i+6]==0 || belongedGroup[vic[i+6]] == 0 || belongedGroup[vic[i+6]]->get_color() != belongedGroup[vic[i]]->get_color())) { 402 | return true; 403 | } 404 | if (vic[i+6] && belongedGroup[vic[i+6]] && belongedGroup[vic[i+6]]->get_color() != belongedGroup[vic[i]]->get_color() && 405 | (vic[i+2]== 0 || belongedGroup[vic[i+2]] == 0 || belongedGroup[vic[i+2]]->get_color() != belongedGroup[vic[i]]->get_color())) { 406 | return true; 407 | } 408 | if (belongedGroup[vic[i]]->get_color() == side) { 409 | if ((vic[i+1] && belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() != side)) { 410 | return true; 411 | } 412 | if ((vic[i-1] && belongedGroup[vic[i-1]] && belongedGroup[vic[i-1]]->get_color() != side)) { 413 | return true; 414 | } 415 | } 416 | if (belongedGroup[vic[i]]->get_color() != side) { 417 | if (vic[i+1] && belongedGroup[vic[i+1]] && belongedGroup[vic[i+1]]->get_color() == side) { 418 | if (vic[i+2] == 0 || belongedGroup[vic[i+2]] == 0 || belongedGroup[vic[i+2]]->get_color() == side) { 419 | return true; 420 | } 421 | if (vic[i+2] && belongedGroup[vic[i+2]] && belongedGroup[vic[i+2]]->get_color() != side 422 | && vic[i+6] && belongedGroup[vic[i+6]] && belongedGroup[vic[i+6]]->get_color() == side) { 423 | return true; 424 | } 425 | } 426 | if (vic[i-1] && belongedGroup[vic[i-1]] && belongedGroup[vic[i-1]]->get_color() == side) { 427 | if (vic[i+6] == 0 || belongedGroup[vic[i+6]] == 0 || belongedGroup[vic[i+6]]->get_color() == side) { 428 | return true; 429 | } 430 | if (vic[i+6] && belongedGroup[vic[i+6]] && belongedGroup[vic[i+6]]->get_color() != side && 431 | vic[i+2] && belongedGroup[vic[i+2]] && belongedGroup[vic[i+2]]->get_color() == side) { 432 | return true; 433 | } 434 | } 435 | } 436 | } else if ((vic[i+6] && belongedGroup[vic[i+6]] && vic[i-1] && belongedGroup[vic[i-1]] && 437 | belongedGroup[vic[i+6]]->get_color() != belongedGroup[vic[i-1]]->get_color()) 438 | || (vic[i+2] && belongedGroup[vic[i+2]] && vic[i+1] && belongedGroup[vic[i+1]] && 439 | belongedGroup[vic[i+2]]->get_color() != belongedGroup[vic[i+1]]->get_color())) { 440 | return true; 441 | } 442 | } 443 | } 444 | } 445 | return false; 446 | } 447 | -------------------------------------------------------------------------------- /badukGo-0.1.5/base.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __BASE_H__ 22 | #define __BASE_H__ 23 | #include 24 | #include 25 | #include "FastLog.h" 26 | #include 27 | 28 | //#define DEBUG_INFO 29 | #define DEF_PLAYOUTS 3000000 30 | #define DEF_TREESIZE 10000000 31 | #define ASTRAY_RED_FRAME() rand() 32 | #define ALIE_STRIKE(a) srand(a) 33 | 34 | #define NEED_PONDER 35 | #ifdef NEED_PONDER 36 | #define PONDER_PLAYOUTS 200000 37 | #define START_PONDER_STEP 10 38 | #define PONDER_THREAD 4 39 | #endif 40 | #define START_REUSE_SUBTREE 10 41 | 42 | #define MAXSIZE 13 43 | #define MAXSIZE2 169 44 | #define STEPS_START_END 3 //开局要走多少步固定位置 45 | #define STEPS_BOUNDARY_TWO 20 //多少步以内忽略棋牌最外圈两层点 46 | #define STEPS_BOUNDARY_ONE 10 //多少步以内忽略棋牌最外圈一层点 47 | // #define STD_ERR_PRINT 48 | 49 | const char COORDINATES[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'}; 50 | 51 | static int TWO_EXIST = 0; 52 | static int ONE_EXIST = 0; 53 | static int board_map[MAXSIZE2 + 1] = {0}; 54 | 55 | static void init_board_map(){ 56 | int gap = MAXSIZE * (MAXSIZE - 1); 57 | //最外层 58 | for (int i = 1; i <= MAXSIZE; ++i) 59 | board_map[i] = board_map[i + gap] = 1; 60 | for (int i = 1; i <= 157; i += MAXSIZE) 61 | board_map[i] = board_map[i + 12] = 1; 62 | 63 | //倒数外二层 64 | for (int i = 15; i <= 25; ++i) 65 | board_map[i] = board_map[i + 130] = 2; 66 | for (int i = 15; i <= 145; i += MAXSIZE) 67 | board_map[i] = board_map[i + 10] = 2; 68 | } 69 | 70 | static void coord_to_char(int coord, std::string &response, int size){ 71 | if(coord == 0){ 72 | response.append("pass"); 73 | } 74 | else{ 75 | int y = (coord - 1)/size + 1; 76 | int x = (coord - 1) % size; 77 | std::string auxstring; 78 | std::stringstream auxstream; 79 | auxstream << COORDINATES[x]; 80 | auxstream >> auxstring; 81 | response.append(auxstring); 82 | 83 | auxstream.clear(); 84 | auxstream << y; 85 | auxstream >> auxstring; 86 | 87 | response.append(auxstring); 88 | } 89 | } 90 | #endif 91 | -------------------------------------------------------------------------------- /badukGo-0.1.5/compile.bat: -------------------------------------------------------------------------------- 1 | mingw32-make 2 | -------------------------------------------------------------------------------- /badukGo-0.1.5/group.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "group.h" 22 | #include 23 | #include 24 | 25 | Group::Group() 26 | { 27 | color = 0; 28 | stones[0] = 0; 29 | liberties[0] = 0; 30 | num_stones = 0; 31 | num_libs = 0; 32 | memset(libs_ptr,0,sizeof(libs_ptr)); 33 | } 34 | 35 | void Group::set_up(int point, bool new_color, const LList &new_liberties) 36 | { 37 | color = new_color; 38 | num_stones = 0; 39 | stones[num_stones++] = point; 40 | stones[num_stones] = 0; 41 | num_libs = 0; 42 | memset(libs_ptr,0,sizeof(libs_ptr)); 43 | 44 | for (int i = 0; i < new_liberties.length(); i++) { 45 | liberties[num_libs++] = new_liberties[i]; 46 | libs_ptr[new_liberties[i]] = num_libs; 47 | liberties[num_libs] = 0; 48 | } 49 | } 50 | 51 | int Group::add_liberties(int i) 52 | { 53 | if (libs_ptr[i] != 0) return 0; 54 | 55 | 56 | libs_ptr[i] = num_libs+1; 57 | liberties[num_libs++] = i; 58 | liberties[num_libs] = 0; 59 | return num_libs; 60 | } 61 | 62 | int Group::erase_liberties(int lib) 63 | { 64 | if (libs_ptr[lib] == 0 ) return 0; 65 | else{ 66 | int pos = libs_ptr[lib]-1; 67 | if (posnum_stones; i++) { 94 | this->stones[num_stones++] = attached->stones[i]; 95 | this->stones[num_stones] = 0; 96 | } 97 | for (int i = 0; i < attached->num_libs; i++) { 98 | this->add_liberties(attached->liberties[i]); 99 | } 100 | } 101 | void Group::print_group() const 102 | { 103 | std::cerr << "Color: " << color; 104 | for (int i = 0; i < num_stones; i++) std::cerr << " " << stones[i]; 105 | std::cerr << "\n"; 106 | } 107 | -------------------------------------------------------------------------------- /badukGo-0.1.5/group.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __GROUP_H__ 22 | #define __GROUP_H__ 23 | 24 | #include "base.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | class LList{ 31 | public: 32 | virtual void add(int p) = 0; 33 | virtual void remove(int p) = 0; 34 | virtual int operator[](int i)const = 0; 35 | virtual int length() const = 0; 36 | 37 | }; 38 | 39 | class Group{ 40 | private: 41 | bool color; 42 | int stones[MAXSIZE2]; 43 | int num_stones; 44 | int liberties[MAXSIZE2*2/3]; 45 | int num_libs; 46 | int libs_ptr[MAXSIZE2+1]; 47 | public: 48 | Group(); 49 | int get_father(){return num_stones?stones[0]:0;} 50 | void set_up(int point, bool color, const LList &liberties); 51 | void clear(); 52 | void attach_group(Group *attached); 53 | 54 | bool get_color() const { return color; } 55 | int get_stones_num() const { return num_stones; } 56 | int get_the_stone(int i) const { return stones[i]; } 57 | const int *get_the_stones() const { return stones; } 58 | 59 | int get_libs_num() const { return num_libs; } 60 | int get_the_lib(int i) const { return liberties[i]; } 61 | const int *get_the_libs() const { return liberties; } 62 | 63 | class StnItr{ 64 | protected: 65 | const int *it; 66 | public: 67 | StnItr() { it = 0; } 68 | StnItr(const Group *gr) { it = gr->get_the_stones(); } 69 | void operator++() { ++it; } 70 | int operator*() const { return *it; } 71 | operator bool() const { return *it != 0; } 72 | }; 73 | 74 | class LibItr : public StnItr{ 75 | public: 76 | LibItr(const Group *gr) { it = gr->get_the_libs(); } 77 | }; 78 | 79 | bool has_one_liberty() const { return num_libs == 1; } 80 | bool has_two_liberties() const { return num_libs == 2; } 81 | int add_liberties(int lib); 82 | int erase_liberties(int lib); 83 | void print_group() const; 84 | }; 85 | 86 | template class GroupSet{ 87 | protected: 88 | Group *groups[S]; 89 | int len; 90 | 91 | public: 92 | GroupSet() 93 | { 94 | len = 0; 95 | groups[0] = 0; 96 | } 97 | 98 | bool add(Group *gr) 99 | { 100 | if (gr == 0) return false; 101 | for (int i = 0; i < len; i++) { 102 | if (groups[i] == gr) { 103 | return false; 104 | } 105 | } 106 | groups[len++] = gr; 107 | return true; 108 | } 109 | 110 | Group *operator[](int i) const { return groups[i]; } 111 | Group *get_by_index(int i) const { return groups[i]; } 112 | int length() const{ return len; } 113 | }; 114 | 115 | template class PointList : public LList { //不用防止重复 116 | protected: 117 | int Points[S]; 118 | int len; 119 | 120 | public: 121 | PointList() 122 | { 123 | len = 0; 124 | Points[0] = 0; 125 | } 126 | void clear() 127 | { 128 | len = 0; 129 | Points[0] = 0; 130 | } 131 | virtual void add(int p) 132 | { 133 | if (len == S) { 134 | #ifdef DEBUG_INFO 135 | std::cerr << "long list\n"; 136 | #endif 137 | return; 138 | } 139 | Points[len++] = p; 140 | Points[len] = 0; 141 | } 142 | void remove(int p) 143 | { 144 | for (int j = 0; j < len; j++) { 145 | if (Points[j] == p) { 146 | Points[j] = Points[--len]; 147 | Points[len] = 0; 148 | break; 149 | } 150 | } 151 | } 152 | 153 | int operator[](int i) const { return Points[i]; } 154 | int length() const { return len; } 155 | 156 | void shuffle() { std::random_shuffle(Points, Points+len); } 157 | 158 | }; 159 | 160 | template class PointSet : public PointList { //要防止重复 161 | public: 162 | void add(int p) 163 | { 164 | if (PointList::len == S) { 165 | return; 166 | } 167 | for (int i = 0; i < PointList::len; i++) { 168 | if (PointList::Points[i] == p) return; 169 | } 170 | PointList::Points[PointList::len++] = p; 171 | PointList::Points[PointList::len] = 0; 172 | } 173 | }; 174 | 175 | template class EmptyPointSet : public LList { 176 | protected: 177 | int Points[S]; 178 | int len; 179 | int pointer[MAXSIZE2+1]; 180 | 181 | public: 182 | EmptyPointSet() 183 | { 184 | len = 0; 185 | Points[0] = 0; 186 | memset(pointer,0,sizeof(pointer)); 187 | } 188 | void clear() 189 | { 190 | len = 0; 191 | Points[0] = 0; 192 | memset(pointer,0,sizeof(pointer)); 193 | 194 | } 195 | virtual void add(int p) 196 | { 197 | if (len == S) { 198 | return; 199 | } 200 | if (pointer[p] !=0) return; 201 | pointer[p] = len+1; 202 | Points[len++] = p; 203 | Points[len] = 0; 204 | 205 | } 206 | void remove(int p) 207 | { 208 | 209 | if (pointer[p] == 0) return; 210 | else{ 211 | int pos = pointer[p]-1; 212 | if (pos < len-1){ 213 | Points[pos] = Points[--len]; 214 | pointer[p] = 0; 215 | pointer[Points[len]] = pos+1; 216 | Points[len] = 0; 217 | }else{ 218 | pointer[p] = 0; 219 | Points[pos] = 0; 220 | --len; 221 | } 222 | } 223 | 224 | } 225 | 226 | int operator[](int i) const { return Points[i]; } 227 | int length() const { return len; } 228 | void shuffle() { 229 | int a; 230 | for (int i=0; i * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include 22 | #include 23 | #include 24 | #include "gtp.h" 25 | #include "base.h" 26 | 27 | using namespace std; 28 | 29 | 30 | GTP::GTP():BadukGo(&main_board) 31 | { 32 | early_pass = true; 33 | Current_Step[0] = Current_Step[1] = -1; 34 | } 35 | 36 | int GTP::GTP_loop() 37 | { 38 | #ifdef LOG 39 | std::string filename = "log"; 40 | filename.append(PROGVERSION); 41 | filename.append(".txt"); 42 | engine_log.open(filename); 43 | #endif 44 | loop = true; 45 | init_board_map(); 46 | 47 | while (loop && getline(cin, command_string)) { 48 | 49 | #ifdef LOG 50 | engine_log << command_std::string; 51 | engine_log.flush(); 52 | #endif 53 | parse(command_string); 54 | exec(); 55 | } 56 | #ifdef LOG 57 | engine_log.close(); 58 | #endif 59 | return 0; 60 | } 61 | 62 | int GTP::parse(const std::string &command_str) 63 | { 64 | std::stringstream auxstream(command_str); 65 | std::string auxstring; 66 | float auxint; 67 | int id; 68 | cmd_args.clear(); 69 | cmd_int_args.clear(); 70 | 71 | //TODO: findfirstof(#) and eliminate 72 | //TODO: handle empty lines 73 | 74 | auxstream >> auxstring; 75 | std::stringstream tempstream(auxstring); 76 | 77 | if (tempstream >> id) { 78 | //TODO:handle negative IDs?? 79 | cmd_id = auxstring; 80 | cmd_id.append(" "); 81 | auxstream >> cmd_name; 82 | } else { 83 | cmd_id = " "; 84 | cmd_name = auxstring; 85 | } 86 | cmd = string_to_cmd(cmd_name); 87 | 88 | while (auxstream.good()) { 89 | auxstream >> auxstring; 90 | cmd_args.insert(cmd_args.end(), auxstring); 91 | 92 | tempstream.clear(); 93 | tempstream.str(auxstring); 94 | tempstream >> auxint; 95 | cmd_int_args.insert(cmd_int_args.end(), auxint); 96 | } 97 | return 0; 98 | } 99 | 100 | int GTP::exec(){ 101 | response = "="; 102 | response.append(cmd_id); 103 | #ifdef NEED_PONDER 104 | BadukGo.stop_ponder(); 105 | #endif 106 | 107 | switch (cmd) { 108 | case PROTOCOL_VERSION: 109 | protocol_version(); 110 | break; 111 | case NAME: 112 | name(); 113 | break; 114 | case VERSION: 115 | version(); 116 | break; 117 | case KNOWN_COMMAND: 118 | known_command(); 119 | break; 120 | case LIST_COMMANDS: 121 | list_commands(); 122 | break; 123 | case QUIT: 124 | quit(); 125 | break; 126 | case BOARDSIZE: 127 | boardsize(); 128 | break; 129 | case CLEAR_BOARD: 130 | clear_board(); 131 | break; 132 | case KOMI: 133 | komi(); 134 | break; 135 | case PLAY: 136 | play(); 137 | break; 138 | case GENMOVE: 139 | genmove(); 140 | #ifdef NEED_PONDER 141 | BadukGo.start_ponder(Current_Step[main_board.get_side()]); 142 | #endif 143 | break; 144 | case SHOWBOARD: 145 | showboard(); 146 | break; 147 | case FIXED_HANDICAP: 148 | fixed_handicap(); 149 | break; 150 | case LEVEL: 151 | level(); 152 | break; 153 | case TIME_SETTINGS: 154 | time_settings(); 155 | break; 156 | case TIME_LEFT: 157 | time_left(); 158 | break; 159 | case FINAL_SCORE: 160 | final_score(); 161 | break; 162 | case FINAL_STATUS_LIST: 163 | final_status_list(); 164 | break; 165 | case KGS_TIME_SETTINGS: 166 | kgs_time_settings(); 167 | break; 168 | case KGS_GENMOVE_CLEANUP: 169 | kgs_genmove_cleanup(); 170 | break; 171 | case SEE_LIBERTY: 172 | see_liberty(); 173 | break; 174 | case SEE_GROUP: 175 | see_group(); 176 | break; 177 | default: 178 | unknown_command(); 179 | break; 180 | } 181 | response.append("\n\n"); 182 | std::cout << response; 183 | 184 | #ifdef LOG 185 | engine_log << response; 186 | engine_log.flush(); 187 | #endif 188 | return 0; 189 | } 190 | 191 | int GTP::string_to_cmd(const std::string &command_str) 192 | { 193 | for (int cmd = 0; cmd < NCOMMANDS; cmd++) { 194 | if (!command_str.compare(COMMANDS[cmd])) { 195 | return cmd; 196 | } 197 | } 198 | return -1; 199 | } 200 | 201 | int GTP::char_to_color(std::string &color) 202 | { 203 | transform(color.begin(), color.end(), color.begin(), ::tolower); 204 | 205 | if (!color.compare("white") || !color.compare("w")) return 1; 206 | else { 207 | if (!color.compare("black") || !color.compare("b")) return 0; 208 | else return -1; 209 | } 210 | } 211 | 212 | int GTP::char_to_coordinate(std::string &coordinate) 213 | { 214 | int coord; 215 | transform(coordinate.begin(), coordinate.end(), coordinate.begin(), ::toupper); 216 | 217 | if (!coordinate.compare("PASS")) return 0; 218 | 219 | std::stringstream auxstream(coordinate.substr(1,2)); 220 | if (auxstream >> coord && coord <= main_board.get_size()) { 221 | coord = (coord - 1)*main_board.get_size(); 222 | } else { 223 | return -1; 224 | } 225 | 226 | for (int i = 0; i < main_board.get_size(); i++) { 227 | if (coordinate[0] == COORDINATES[i]) { 228 | coord += i+1; 229 | return coord; 230 | } 231 | } 232 | return -1; 233 | } 234 | 235 | void GTP::print_coordinate(int coord) 236 | { 237 | if (coord == -1) { 238 | response.append("resign"); 239 | } else { 240 | coord_to_char(coord, response, main_board.get_size()); 241 | } 242 | } 243 | 244 | void GTP::perft(int max) 245 | { 246 | clock_t t = clock(); 247 | BadukGo.perft(max); 248 | t = clock() - t; 249 | float ts = (float)t/CLOCKS_PER_SEC; 250 | std::cerr << "Finish " << ts << ":" << max/ts << "pps.\n"; 251 | } 252 | -------------------------------------------------------------------------------- /badukGo-0.1.5/gtp.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __GTP_H__ 22 | #define __GTP_H__ 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "Board.h" 30 | #include "Go.h" 31 | 32 | #define PROTOCOLVERSION "2" 33 | #define PROGVERSION "0.1.5_release" 34 | #define PROGNAME "BadukGo" 35 | //#define LOG 36 | 37 | class GTP { 38 | private: 39 | bool loop, early_pass; 40 | int cmd; 41 | int Current_Step[2]; 42 | std::string cmd_id; 43 | std::string cmd_name; 44 | std::vector cmd_args; 45 | std::vector cmd_int_args; 46 | std::string command_string; 47 | std::string response; 48 | #ifdef LOG 49 | ofstream engine_log; 50 | #endif 51 | Board main_board; 52 | Go BadukGo; 53 | 54 | void protocol_version(); 55 | void name(); 56 | void version(); 57 | void known_command(); 58 | void list_commands(); 59 | void quit(); 60 | void boardsize(); 61 | void clear_board(); 62 | void komi(); 63 | void play(); 64 | void genmove(); 65 | void kgs_genmove_cleanup(); 66 | void unknown_command(); 67 | void showboard(); 68 | void fixed_handicap(); 69 | void level(); 70 | void time_settings(); 71 | void kgs_time_settings(); 72 | void time_left(); 73 | void final_score(); 74 | void final_status_list(); 75 | void see_liberty(); 76 | void see_group(); 77 | 78 | enum {PROTOCOL_VERSION, NAME, VERSION, KNOWN_COMMAND, LIST_COMMANDS, 79 | QUIT, BOARDSIZE, CLEAR_BOARD, KOMI, PLAY, GENMOVE, SHOWBOARD, 80 | FIXED_HANDICAP, LEVEL,TIME_SETTINGS, TIME_LEFT, FINAL_SCORE, 81 | FINAL_STATUS_LIST, KGS_TIME_SETTINGS, KGS_GENMOVE_CLEANUP, 82 | SEE_LIBERTY, SEE_GROUP, NCOMMANDS}; 83 | 84 | const std::string COMMANDS[NCOMMANDS] = 85 | {"protocol_version","name","version","known_command","list_commands", 86 | "quit","boardsize","clear_board","komi","play","genmove","showboard", 87 | "fixed_handicap","level","time_settings","time_left","final_score", 88 | "final_status_list","kgs-time_settings", "kgs-genmove_cleanup", 89 | "see_liberty", "see_group"}; 90 | 91 | int parse(const std::string&); 92 | int string_to_cmd(const std::string&); 93 | int char_to_color(std::string&); 94 | int char_to_coordinate(std::string&); 95 | void print_coordinate(int); 96 | 97 | public: 98 | GTP(); 99 | int GTP_loop(); 100 | int exec(); 101 | void perft(int); 102 | 103 | }; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /badukGo-0.1.5/gtpcmds.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "gtp.h" 22 | 23 | void GTP::protocol_version() 24 | { 25 | response.append(PROTOCOLVERSION); 26 | } 27 | 28 | void GTP::name() 29 | { 30 | response.append(PROGNAME); 31 | } 32 | 33 | void GTP::version() 34 | { 35 | response.append(PROGVERSION); 36 | } 37 | 38 | void GTP::known_command() 39 | { 40 | for (int i = 0; i < NCOMMANDS; i++) { 41 | if (!cmd_args[0].compare(COMMANDS[i])) 42 | response.append("true"); 43 | } 44 | response.append("false"); 45 | } 46 | 47 | void GTP::list_commands() 48 | { 49 | for (int i = 0; i < NCOMMANDS; i++) { 50 | response.append(COMMANDS[i]); 51 | response.append("\n"); 52 | } 53 | } 54 | 55 | void GTP::quit() 56 | { 57 | loop = false; 58 | } 59 | 60 | void GTP::boardsize() 61 | { 62 | if (cmd_args.size() > 0) { 63 | if (cmd_int_args[0] != main_board.set_size(cmd_int_args[0])) { 64 | response[0] = '?'; 65 | response.append("unacceptable size"); 66 | } else { 67 | BadukGo.reset(); 68 | } 69 | } else { 70 | response[0] = '?'; 71 | response.append("syntax error"); 72 | } 73 | } 74 | 75 | void GTP::clear_board() 76 | { 77 | main_board.clear(); 78 | BadukGo.reset(); 79 | Current_Step[0] = Current_Step[1] = -1; 80 | } 81 | 82 | void GTP::komi() 83 | { 84 | if (cmd_args.size() > 0) { 85 | main_board.set_komi(cmd_int_args[0]); 86 | } else { 87 | response[0] = '?'; 88 | response.append("syntax error"); 89 | } 90 | } 91 | 92 | void GTP::play() 93 | { 94 | int color, coord; 95 | if (cmd_args.size() > 1) { 96 | color = char_to_color(cmd_args[0]); 97 | coord = char_to_coordinate(cmd_args[1]); 98 | 99 | if (color > -1 && coord > -1) { 100 | ++Current_Step[color]; 101 | main_board.play_move(coord, color); 102 | BadukGo.report_move(coord,Current_Step[color]); 103 | if(board_map[coord] == 1) 104 | ONE_EXIST = 1; 105 | else if(board_map[coord] == 2) 106 | TWO_EXIST = ONE_EXIST = 1; 107 | } else { 108 | response[0] = '?'; 109 | response.append("invalid color or coordinate"); 110 | } 111 | } else { 112 | response[0] = '?'; 113 | response.append("syntax error"); 114 | } 115 | } 116 | 117 | void GTP::kgs_genmove_cleanup() 118 | { 119 | early_pass = false; 120 | genmove(); 121 | early_pass = true; 122 | } 123 | 124 | void GTP::genmove() 125 | { 126 | #ifdef STD_ERR_PRINT 127 | std::cerr << "enter genmove" < 0){ 130 | bool color = char_to_color(cmd_args[0]); 131 | if(color != main_board.get_side()){ 132 | main_board.play_move(0, !color); 133 | BadukGo.report_move(0,Current_Step[!color]); 134 | } 135 | #ifdef STD_ERR_PRINT 136 | std::cerr << "enter generate_move" < 0 && cmd_int_args[0] > 0) { 179 | BadukGo.set_playouts(10000*cmd_int_args[0]); 180 | } else { 181 | response[0] = '?'; 182 | response.append("syntax error"); 183 | } 184 | } 185 | 186 | void GTP::time_settings() 187 | { 188 | return ; 189 | } 190 | 191 | void GTP::kgs_time_settings() 192 | { 193 | return ; 194 | } 195 | 196 | void GTP::time_left() 197 | { 198 | return ; 199 | } 200 | 201 | void GTP::final_score() 202 | { 203 | std::stringstream auxstream; 204 | float score = BadukGo.score(0); 205 | if (score > 0) { 206 | auxstream << score; 207 | response.append("B+"); 208 | response.append(auxstream.str()); 209 | } else { 210 | auxstream << -score; 211 | response.append("W+"); 212 | response.append(auxstream.str()); 213 | } 214 | } 215 | 216 | void GTP::final_status_list() 217 | { 218 | if (cmd_args.size() > 0 && !cmd_args[0].compare("dead")) { 219 | std::vector list; 220 | BadukGo.score(&list); 221 | //TODO: support 'alive' status. 222 | for (std::vector::iterator it = list.begin(); it != list.end(); ++it) { 223 | coord_to_char(*it, response, main_board.get_size()); 224 | response.append("\n"); 225 | } 226 | } else { 227 | response[0] = '?'; 228 | response.append("syntax error"); 229 | } 230 | } 231 | 232 | void GTP::see_liberty() 233 | { 234 | if (cmd_args.size() > 0) { 235 | int point = char_to_coordinate(cmd_args[0]); 236 | int tmp[169]; 237 | int numlibs = main_board.print_libs_of(point, tmp); 238 | for (int i = 0; i < numlibs; ++i) { 239 | coord_to_char(tmp[i], response, main_board.get_size()); 240 | response.append("\t"); 241 | } 242 | } else { 243 | response[0] = '?'; 244 | response.append("syntax error"); 245 | } 246 | } 247 | 248 | void GTP::see_group() 249 | { 250 | if(cmd_args.size() > 0){ 251 | int point = char_to_coordinate(cmd_args[0]); 252 | int tmp[169]; 253 | int numlibs = main_board.print_group_of(point, tmp); 254 | for (int i = 0; i < numlibs; ++i) { 255 | coord_to_char(tmp[i], response, main_board.get_size()); 256 | response.append("\t"); 257 | } 258 | } else { 259 | response[0] = '?'; 260 | response.append("syntax error"); 261 | } 262 | } 263 | 264 | -------------------------------------------------------------------------------- /badukGo-0.1.5/libgcc_s_dw2-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phonicavi/Go/73e64c32c4ed091865370cefcf5ac70272a3b18f/badukGo-0.1.5/libgcc_s_dw2-1.dll -------------------------------------------------------------------------------- /badukGo-0.1.5/libstdc++-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Phonicavi/Go/73e64c32c4ed091865370cefcf5ac70272a3b18f/badukGo-0.1.5/libstdc++-6.dll -------------------------------------------------------------------------------- /badukGo-0.1.5/main.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include 22 | #include "gtp.h" 23 | #include "Go.h" 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | int seed; 30 | 31 | void print_info(){ 32 | SYSTEM_INFO sinfo; 33 | GetSystemInfo(&sinfo); 34 | int thread_num = max(min((int)sinfo.dwNumberOfProcessors,6),4); 35 | std::cerr << "BadukGo 0.1.5 \ 36 | \nCopyright (C) 2016 by the authors of the BadukGo project under the MIT License (MIT). \ 37 | \nWe are QIU, BIAN and LAI. Since it's our first Go project, \ 38 | \nCurrently, we fix board size at 13*13, with time limit 3s. \ 39 | \nWe hope this project can bring us more knowledge about AI. \ 40 | \nAny questions or suggestions, welcome to discuss with us ^_^.\n " 41 | < * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "Board.h" 22 | 23 | 24 | void Board::init_priors(Prior priors[]) const 25 | { 26 | const double EQUIV = size; 27 | priors[PASS].prior = 0.1*EQUIV, priors[PASS].equiv = EQUIV; 28 | 29 | for(int i = 0; i < empty_points.length(); ++i){ 30 | int p = empty_points[i]; 31 | priors[p].prior = 0.5*EQUIV, priors[p].equiv = EQUIV; 32 | } 33 | for(int i = 0; i < empty_points.length(); ++i){ 34 | int p = empty_points[i]; 35 | if(is_self_atari(p, side)){ 36 | priors[p].prior = 0.2*EQUIV, priors[p].equiv = 2*EQUIV; 37 | continue; 38 | } 39 | if(is_surrounded(p, side)){ 40 | priors[p].prior = 0.3*EQUIV, priors[p].equiv = EQUIV; 41 | continue; 42 | } 43 | priors[p].prior = 0.5*EQUIV, priors[p].equiv = EQUIV; 44 | if(size > 11){ 45 | if(distance2edge[p] == 0 && !is_stones_around(p, 4)){ 46 | priors[p].prior = 0.1*EQUIV, priors[p].equiv = EQUIV; 47 | } 48 | else if(distance2edge[p] == 3 && !is_stones_around(p, 4)){ 49 | priors[p].prior = 0.9*EQUIV, priors[p].equiv = EQUIV; 50 | } 51 | } 52 | 53 | GroupSet<4> neigh; 54 | int nneigh = neighbour_groups(p, neigh); 55 | for(int j = 0; j < nneigh; j++){ 56 | if(neigh[j]->has_one_liberty()){ 57 | if(neigh[j]->get_color() != side){ 58 | priors[p].prior = 1.4*EQUIV, priors[p].equiv = 2*EQUIV; 59 | goto endloop; 60 | } 61 | else{ 62 | priors[p].prior = 0.6*EQUIV, priors[p].equiv = EQUIV; 63 | goto endloop; 64 | } 65 | } 66 | } 67 | if(is_match_mogo_pattern(p, side)){ 68 | priors[p].prior = 0.9*EQUIV, priors[p].equiv = EQUIV; 69 | continue; 70 | } 71 | endloop:; 72 | } 73 | int last_point3 = game_history[game_history.length()-3]; 74 | // std::cerr << "last_point3: " << last_point3 < list; 81 | // nakade_trick(last_point, list); 82 | // for(int i = 0; i < list.length(); i++){ 83 | // priors[list[i]].prior += 2*EQUIV, priors[list[i]].equiv += 2*EQUIV; 84 | // } 85 | // list.clear(); 86 | capture_trick(last_point, list); 87 | for(int i = 0; i < list.length(); i++){ 88 | priors[list[i]].prior += 3*EQUIV, priors[list[i]].equiv += 3*EQUIV; 89 | } 90 | list.clear(); 91 | 92 | save_trick(last_point, list); 93 | for(int i = 0; i < list.length(); i++){ 94 | priors[list[i]].prior += 2*EQUIV, priors[list[i]].equiv += 2*EQUIV; 95 | } 96 | list.clear(); 97 | 98 | pattern_trick(last_point, list); 99 | for(int i = 0; i < list.length(); i++){ 100 | priors[list[i]].prior += 2*EQUIV, priors[list[i]].equiv += 2*EQUIV; 101 | } 102 | list.clear(); 103 | 104 | 105 | for(int i = 0; last_point && i < 4; i++){ 106 | for(int j = 0; j < 4*(i+1); j++){ 107 | int v = within_manhattan[last_point][i][j]; 108 | if (v == last_point3) is_l3_l1_near = true; 109 | if(v) { 110 | priors[v].prior += (1.0-0.1*i)*EQUIV, priors[v].equiv += EQUIV; 111 | } 112 | } 113 | } 114 | 115 | 116 | 117 | if (last_point3 && !is_l3_l1_near){ 118 | PointList list; 119 | // nakade_trick(last_point, list); 120 | // for(int i = 0; i < list.length(); i++){ 121 | // priors[list[i]].prior += 2*EQUIV, priors[list[i]].equiv += 2*EQUIV; 122 | // } 123 | // list.clear(); 124 | capture_trick(last_point3, list); 125 | for(int i = 0; i < list.length(); i++){ 126 | priors[list[i]].prior += 2*EQUIV, priors[list[i]].equiv += 2*EQUIV; 127 | } 128 | list.clear(); 129 | 130 | save_trick(last_point3, list); 131 | for(int i = 0; i < list.length(); i++){ 132 | priors[list[i]].prior += EQUIV, priors[list[i]].equiv += EQUIV; 133 | } 134 | list.clear(); 135 | 136 | pattern_trick(last_point3, list); 137 | for(int i = 0; i < list.length(); i++){ 138 | priors[list[i]].prior += EQUIV, priors[list[i]].equiv += EQUIV; 139 | } 140 | list.clear(); 141 | 142 | 143 | for(int i = 0; last_point3 && i < 4; i++){ 144 | for(int j = 0; j < 4*(i+1); j++){ 145 | int v = within_manhattan[last_point3][i][j]; 146 | if(v) { 147 | priors[v].prior += (1.0-0.1*i)*EQUIV, priors[v].equiv += EQUIV; 148 | } 149 | } 150 | } 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /badukGo-0.1.5/start_pattern.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "Board.h" 22 | #include 23 | 24 | 25 | #define set_4(x) size*(x-1)+x,size*(size-x)+x,size*(x-1)+size-(x-1),size*(size-x)+size-(x-1) 26 | #define set_8(a,b) size*(a-1)+b,size*(b-1)+a,size*(size-a)+b,size*(size-b)+a,size*(a-1)+size-(b-1),size*(b-1)+size-(a-1),size*(size-a)+size-(b-1),size*(size-b)+size-(a-1) 27 | #define center size/2+1 28 | #define set_ce(x) size*(x-1)+center,size*(size-x)+center,size*(center-1)+x,size*(center-1)+size-(x-1) 29 | 30 | // first-step: star_point*4 = 4 31 | #define recommend_1 {set_4(4)} 32 | // first-2: star_point*4 + 3-4_point*8 = 12 33 | #define recommend_2 {set_4(4),set_8(3,4)} 34 | // first-3: nine(9)[without:5-5] + 3-6_point = 40 35 | #define recommend_3 {set_4(3),set_4(4),set_8(3,4),set_8(3,5),set_8(3,6),set_8(4,5)} 36 | // first-4: line[3, 4, 5] more = 72 37 | #define recommend_4 {set_4(3),set_4(4),set_4(5),set_8(3,4),set_8(3,5),set_8(4,5),set_8(3,6),set_8(4,6),set_8(5,6),set_ce(3),set_ce(4),set_ce(5)} 38 | 39 | const int star_xm_gua[4][5] = { 40 | {121,134,120,107,135}, 41 | {127,140,128,115,139}, 42 | {49,50,36,35,63}, 43 | {43,30,42,55,31}, 44 | }; 45 | 46 | inline int star_xm_which(int point) { 47 | switch(point){ 48 | case 121: 49 | case 134: 50 | case 120: 51 | return 0; 52 | case 127: 53 | case 140: 54 | case 128: 55 | return 1; 56 | case 49: 57 | case 50: 58 | case 36: 59 | return 2; 60 | case 43: 61 | case 30: 62 | case 42: 63 | return 3; 64 | default: 65 | return -1; 66 | } 67 | } 68 | 69 | 70 | 71 | inline bool is_in_set(int point, int set[], int length) 72 | { 73 | for (int i=0; iget_history_length(); 84 | std::cerr << "la2 " <get_side() == 0){ 92 | for (int i=0; i<4; ++i) 93 | for (int j=0; j<3; ++j){ 94 | recommend[rcmd_len++] = star_xm_gua[i][j]; 95 | } 96 | }else{ 97 | std::cerr << "dasdsad " <get_side() == 0){ 145 | int last_self = last_point2_bu; 146 | if (is_star_point(last_self)){ 147 | int which = star_xm_which(last_self); 148 | recommend[rcmd_len++] = star_xm_gua[which][3]; 149 | recommend[rcmd_len++] = star_xm_gua[which][4]; 150 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][0]; 151 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][1]; 152 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][2]; 153 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][0]; 154 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][1]; 155 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][2]; 156 | }else{ 157 | assert(is_point_3_4(last_self)); 158 | int which = star_xm_which(last_self); 159 | if (last_self == star_xm_gua[which][1]) 160 | recommend[rcmd_len++] = star_xm_gua[which][3]; 161 | else recommend[rcmd_len++] = star_xm_gua[which][4]; 162 | for (int j=0; j<3; ++j){ 163 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][j]; 164 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][j]; 165 | } 166 | } 167 | 168 | }else{ 169 | if (is_point_3_4(last_point_bu)){ 170 | int which = star_xm_which(last_point_bu); 171 | if (last_point_bu == star_xm_gua[which][1]) 172 | recommend[rcmd_len++] = star_xm_gua[which][3]; 173 | else 174 | recommend[rcmd_len++] = star_xm_gua[which][4]; 175 | // for (int i=0; i<4; ++i){ 176 | // if (i == which) continue; 177 | // for (int j=0; j<3; ++j){ 178 | // recommend[rcmd_len++] = star_xm_gua[i][j]; 179 | // } 180 | // } 181 | 182 | }else if (is_star_point(last_point_bu)){ 183 | int last_self = last_point2_bu; 184 | int which_self = star_xm_which(last_self); 185 | int which_opp = star_xm_which(last_point_bu); 186 | if (which_self != -1){ 187 | for (int j=0; j<3; ++j){ 188 | if (last_self == star_xm_gua[which_self][j]){ 189 | if (j == 0){ 190 | recommend[rcmd_len++] = star_xm_gua[which_self][3]; 191 | recommend[rcmd_len++] = star_xm_gua[which_self][4]; 192 | }else{ 193 | recommend[rcmd_len++] = star_xm_gua[which_self][j+2]; 194 | } 195 | break; 196 | } 197 | } 198 | } 199 | 200 | if (which_opp != which_self){ 201 | recommend[rcmd_len++] = star_xm_gua[which_opp][3]; 202 | recommend[rcmd_len++] = star_xm_gua[which_opp][4]; 203 | } 204 | 205 | if (rcmd_len == 0){ 206 | for (int j=0 ;j<3; ++j){ 207 | recommend[rcmd_len++] = star_xm_gua[(which_opp+1)%4][j]; 208 | recommend[rcmd_len++] = star_xm_gua[(which_opp-1)%4][j]; 209 | } 210 | } 211 | 212 | }else { 213 | int last_self = last_point2_bu; 214 | if (is_star_point(last_self)){ 215 | int which = star_xm_which(last_self); 216 | recommend[rcmd_len++] = star_xm_gua[which][3]; 217 | recommend[rcmd_len++] = star_xm_gua[which][4]; 218 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][0]; 219 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][0]; 220 | }else{ 221 | assert(is_point_3_4(last_self)); 222 | int which = star_xm_which(last_self); 223 | if (last_self == star_xm_gua[which][1]) 224 | recommend[rcmd_len++] = star_xm_gua[which][3]; 225 | else recommend[rcmd_len++] = star_xm_gua[which][4]; 226 | for (int j=0; j<3; ++j){ 227 | recommend[rcmd_len++] = star_xm_gua[(which+1)%4][j]; 228 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][j]; 229 | } 230 | } 231 | } 232 | } 233 | 234 | 235 | 236 | 237 | 238 | for (int i = 0; i < empty_points.length(); i++) { 239 | int point = empty_points[i]; 240 | if (is_in_set(point, recommend, rcmd_len) && is_legal(point, side) && !is_true_eye(point,side)) { 241 | moves[nlegal++] = point; 242 | } 243 | } 244 | moves[nlegal++] = PASS; 245 | } else if (step<=5) { 246 | 247 | int rcmd_len = 0; 248 | int recommend[MAXSIZE2]; 249 | int tmp[40] = recommend_3; 250 | 251 | if (get_side() == 0){ 252 | int last_self2 = game_history[0]; 253 | int last_self = last_point2_bu; 254 | assert(last_self2&&last_self); 255 | if (is_star_point(last_self) && is_star_point(last_self2)){ 256 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][3]; 257 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][4]; 258 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][3]; 259 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][4]; 260 | }else if(is_point_3_4(last_self2) && is_star_point(last_self)){ 261 | if (star_xm_which(last_self2) != star_xm_which(last_self)){ 262 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][3]; 263 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][4]; 264 | 265 | int which = star_xm_which(last_self2); 266 | if (star_xm_gua[which][1] == last_self2){ 267 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][3]; 268 | }else recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][4]; 269 | } 270 | }else if(is_point_3_4(last_self) && is_star_point(last_self2)){ 271 | if (star_xm_which(last_self2) != star_xm_which(last_self)){ 272 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][3]; 273 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][4]; 274 | 275 | int which = star_xm_which(last_self); 276 | if (star_xm_gua[which][1] == last_self){ 277 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][3]; 278 | }else recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][4]; 279 | } 280 | }else if(is_point_3_4(last_self2) && is_point_3_4(last_self)){ 281 | int which = star_xm_which(last_self); 282 | if (star_xm_gua[which][1] == last_self){ 283 | if (belongedGroup[star_xm_gua[star_xm_which(last_self)][3]] == 0) 284 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][3]; 285 | }else if (belongedGroup[star_xm_gua[star_xm_which(last_self)][4]] == 0) 286 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self)][4]; 287 | if (which != star_xm_which(last_self2)){ 288 | which = star_xm_which(last_self2); 289 | if (star_xm_gua[which][1] == last_self2){ 290 | if (belongedGroup[star_xm_gua[star_xm_which(last_self2)][3]] == 0) 291 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][3]; 292 | }else if (belongedGroup[star_xm_gua[star_xm_which(last_self2)][4]] == 0) 293 | recommend[rcmd_len++] = star_xm_gua[star_xm_which(last_self2)][4]; 294 | } 295 | 296 | }else if (is_point_3_4(last_self2) && is_point_3_5(last_self)){ 297 | int which = star_xm_which(last_self2); 298 | for (int j=0; j<3; ++j) recommend[rcmd_len++] = star_xm_gua[(which+1)%4][j], 299 | recommend[rcmd_len++] = star_xm_gua[(which-1)%4][j]; 300 | } 301 | 302 | if (rcmd_len <= 2){ 303 | for (int i=0; i<4; ++i) 304 | for (int j=0; j<3; ++j){ 305 | recommend[rcmd_len++] = star_xm_gua[i][j]; 306 | } 307 | } 308 | 309 | } 310 | 311 | 312 | 313 | else 314 | for (int i=0; i<40; ++i)recommend[rcmd_len++] = tmp[i]; 315 | for (int i = 0; i < empty_points.length(); i++) { 316 | int point = empty_points[i]; 317 | if (is_in_set(point, recommend, rcmd_len) && is_legal(point, side) && !is_true_eye(point,side)) { 318 | moves[nlegal++] = point; 319 | } 320 | } 321 | moves[nlegal++] = PASS; 322 | } else if (step<=7) { 323 | int recommend[72] = recommend_4; 324 | for (int i = 0; i < empty_points.length(); i++) { 325 | int point = empty_points[i]; 326 | if (is_in_set(point, recommend, 72) && is_legal(point, side) && !is_true_eye(point,side)) { 327 | moves[nlegal++] = point; 328 | } 329 | } 330 | moves[nlegal++] = PASS; 331 | } else { 332 | for (int i = 0; i < empty_points.length(); i++) { 333 | int point = empty_points[i]; 334 | if (is_legal(point, side) && !is_true_eye(point,side)) { 335 | moves[nlegal++] = point; 336 | } 337 | } 338 | moves[nlegal++] = PASS; 339 | } 340 | return nlegal; 341 | } 342 | 343 | int Board::legal_moves_origin(int moves[]) const 344 | { 345 | int nlegal = 0; 346 | for (int i = 0; i < empty_points.length(); i++) { 347 | int point = empty_points[i]; 348 | if (is_legal(point, side) && !is_true_eye(point,side)) { 349 | moves[nlegal++] = point; 350 | } 351 | } 352 | moves[nlegal++] = PASS; 353 | return nlegal; 354 | } 355 | 356 | 357 | 358 | /**special positions 359 | * tengen 天元 360 | * star_position 星位 361 | * 3-3 point 三三 362 | * 5-5 point 五五 363 | * 3-4 point 小目 364 | * 4-5 point 高目 365 | * 3-5 point 目外 366 | * 4-6 point 超高目 367 | * 368 | */ 369 | bool Board::is_tengen(int point) const 370 | { 371 | return point==(size2/2+1); 372 | } 373 | 374 | bool Board::is_star_point(int point) const 375 | { 376 | int x=4; 377 | int set[4] = {set_4(x)}; 378 | return is_in_set(point, set, 4); 379 | } 380 | 381 | bool Board::is_point_3_3(int point) const 382 | { 383 | int x=3; 384 | int set[4] = {set_4(x)}; 385 | return is_in_set(point, set, 4); 386 | } 387 | 388 | bool Board::is_point_5_5(int point) const 389 | { 390 | int x=5; 391 | int set[4] = {set_4(x)}; 392 | return is_in_set(point, set, 4); 393 | } 394 | 395 | bool Board::is_point_3_4(int point) const 396 | { 397 | int a=3, b=4; 398 | int set[8] = {set_8(a,b)}; 399 | return is_in_set(point, set, 8); 400 | } 401 | 402 | bool Board::is_point_4_5(int point) const 403 | { 404 | int a=4, b=5; 405 | int set[8] = {set_8(a,b)}; 406 | return is_in_set(point, set, 8); 407 | } 408 | 409 | bool Board::is_point_3_5(int point) const 410 | { 411 | int a=3, b=5; 412 | int set[8] = {set_8(a,b)}; 413 | return is_in_set(point, set, 8); 414 | } 415 | 416 | bool Board::is_point_4_6(int point) const 417 | { 418 | int a=4, b=6; 419 | int set[8] = {set_8(a,b)}; 420 | return is_in_set(point, set, 8); 421 | } 422 | 423 | -------------------------------------------------------------------------------- /badukGo-0.1.5/tree.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #include "tree.h" 22 | #include 23 | const double BIAS = 0.00033333333333, UCTK = 0.3, K=2000.0; 24 | const double discount = 0.0; 25 | #ifdef CHANGE_BEST_POLICY 26 | const double CHANGE_POLICY_WINRATE_THERESHOLD = 0.85; 27 | const double CHANGE_POLICY_WINRATE_THERESHOLD2 = 0.4; 28 | const double CHANGE_POLICY_WINRATE_DIFF_THERESHOLD = 0.98; 29 | const double CHANGE_POLICY_VISIT_DIFF_THERESHOLD = 0.25; 30 | const double CHANGE_POLICY_R_VISIT_DIFF_THERESHOLD = 0.3; 31 | #endif 32 | 33 | FastLog flog(10); 34 | 35 | void Node::reset() 36 | { 37 | child = 0; 38 | sibling = 0; 39 | visits = 0; 40 | results = 0; 41 | r_visits = 0; 42 | r_results = 0; 43 | move = 0; 44 | is_expand = 0; 45 | is_pruned = 0; 46 | node_score = 0; 47 | } 48 | 49 | void Node::copy_values(const Node *orig) 50 | { 51 | child = 0; 52 | sibling = 0; 53 | is_expand = orig->is_expand; 54 | is_pruned = 0; 55 | visits = orig->visits; 56 | results = orig->results; 57 | r_visits = orig->r_visits; 58 | r_results = orig->r_results; 59 | p_visits = orig->p_visits; 60 | p_results = orig->p_results; 61 | move = orig->move; 62 | node_score = orig->node_score; 63 | } 64 | 65 | void Node::add_child(Node *child) 66 | { 67 | if (!this->child) this->child = child; 68 | else { 69 | Node *next; 70 | for (next = this->child; next->sibling; next = next->sibling) { 71 | } 72 | next->sibling = child; 73 | } 74 | } 75 | 76 | void Node::set_move(int mv, const Prior &prior) 77 | { 78 | move = mv; 79 | r_results = prior.prior; 80 | r_visits = prior.equiv; 81 | p_results = prior.prior; 82 | p_visits = prior.equiv; 83 | } 84 | 85 | void Node::set_results(int result) 86 | { 87 | visits++; 88 | results += result; 89 | } 90 | 91 | void Node::set_amaf(int result, const AmafBoard &amaf, bool side, int depth) 92 | { 93 | for (Node *next = child; next; next = next->sibling) { 94 | next->r_results += result * amaf.value(next->move, depth, side, discount); 95 | next->r_visits += amaf.value(next->move, depth, side, discount); 96 | } 97 | } 98 | void Node::set_amaf(int result, AmafBoard * amaf, bool side, int depth) 99 | { 100 | for (Node *next = child; next; next = next->sibling) { 101 | next->r_results += result * amaf->value(next->move, depth, side, discount); 102 | next->r_visits += amaf->value(next->move, depth, side, discount); 103 | } 104 | } 105 | 106 | double Node::get_value(int parent_visits) const 107 | { 108 | if(is_pruned != 0) return -1; 109 | 110 | if (visits) { 111 | if (r_visits) { 112 | double beta = r_visits/(r_visits + visits + r_visits*visits*BIAS); 113 | return (1.0-beta)*results/visits + beta*r_results/r_visits; 114 | } else { 115 | return ((double)results)/visits; 116 | } 117 | } 118 | else if (r_visits) { 119 | 120 | return r_results/r_visits; 121 | } 122 | return (rand()*1000+10000); 123 | } 124 | 125 | Node *Node::select_child() const 126 | { 127 | double best = -100,tmp; 128 | int bestnum = 0; 129 | Node *bestarray[MAXSIZE2]; 130 | for (Node *next = child; next; next = next->sibling){ 131 | if ((tmp = next->get_value(visits)) > best){ 132 | best = tmp; 133 | bestnum = 1; 134 | bestarray[0] = next; 135 | }else if(tmp == best){ 136 | bestarray[bestnum++] = next; 137 | } 138 | } 139 | return bestnum == 1?bestarray[0]:(bestarray[rand()%bestnum]); 140 | } 141 | 142 | Node *Node::get_best_child() const 143 | { 144 | Node *best = NULL; 145 | double best_v = 0; 146 | double best_w; 147 | double cur_v; 148 | double cur_w; 149 | for (Node * next = child; next; next = next->sibling){ 150 | cur_v = next->r_visits+next->visits; 151 | cur_w = next->r_results + results; 152 | if (cur_v > best_v || (cur_v == best_v && cur_w > best_w)){ 153 | best_v = cur_v; 154 | best_w = cur_w; 155 | best = next; 156 | } 157 | } 158 | return best; 159 | } 160 | 161 | Node *Node::get_best_child(double winrate) const 162 | { 163 | Node *best = NULL; 164 | // best = this->select_child(); 165 | double best_v = 0; 166 | double best_w; 167 | double cur_v; 168 | double cur_w; 169 | for (Node * next = child; next; next = next->sibling){ 170 | if (next->visits<50) continue; 171 | cur_v = next->r_visits+next->visits; 172 | cur_w = next->r_results + results; 173 | if (cur_v > best_v || (cur_v == best_v && cur_w > best_w)){ 174 | best_v = cur_v; 175 | best_w = cur_w; 176 | best = next; 177 | } 178 | } 179 | #ifdef CHANGE_BEST_POLICY 180 | if (winrate < CHANGE_POLICY_WINRATE_THERESHOLD 181 | && winrate > CHANGE_POLICY_WINRATE_THERESHOLD2) return best; 182 | #ifdef STD_ERR_PRINT 183 | std::cerr << "Winrate: " << winrate << std::endl; 184 | #endif 185 | Node *pre_best =best; 186 | 187 | const double best_visit = (double)best->visits; 188 | const double best_r_visit = best->r_visits; 189 | const double best_winrate = ((double)best->results/best_visit); 190 | bool flag = 0; 191 | float best_score = best_visit>0?(best->node_score/best_visit):0,tmp_score; 192 | #ifdef STD_ERR_PRINT 193 | std::cerr << "best_visit: " << best_visit << " best_winrate: "<sibling){ 196 | if (next == pre_best || next->move == 0) continue; 197 | if ((next->visits > CHANGE_POLICY_VISIT_DIFF_THERESHOLD*best_visit) 198 | && ((tmp_score = (next->node_score/next->visits)) > best_score) 199 | && (next->r_visits > best_r_visit*CHANGE_POLICY_R_VISIT_DIFF_THERESHOLD) 200 | &&(((double)next->results)/next->visits>best_winrate*CHANGE_POLICY_WINRATE_DIFF_THERESHOLD)) 201 | { 202 | #ifdef STD_ERR_PRINT 203 | std::cerr << "NOW_BEST: "; 204 | std::string _mv; 205 | coord_to_char(next->move,_mv,13); 206 | std::cerr << _mv<<": " << next->visits << " " <<((double)next->results)/next->visits<<" "<move,mv,13); 219 | std::cerr<move,mv,13); 223 | std::cerr << mv<<"\n"; 224 | 225 | } 226 | #endif 227 | 228 | #endif 229 | return best; 230 | } 231 | 232 | double Node::get_r_prun_winrate(double alpha) const 233 | { 234 | return visits?(1- alpha*(1-(double(results))/(visits))):( 235 | r_visits?(1- alpha*(1-R_PRUN_RAVE_DISCOUNT*r_results/r_visits)):0 236 | ); 237 | } 238 | 239 | void Tree::do_r_prun(int ttl_visits,double alpha) 240 | { 241 | Node *root = get_root(); 242 | double miu[MAXSIZE2]; 243 | double max_miu = -1.0; 244 | int max_miu_id = -1; 245 | int max_visits = -1; 246 | int n_childs = 0; 247 | for (Node *next = root->get_child();next;next = next->get_sibling()){ 248 | miu[n_childs] = next->get_r_prun_winrate(alpha); 249 | if (next->get_visits() > max_visits){ 250 | max_miu_id = n_childs; 251 | max_visits = next->get_visits(); 252 | } 253 | ++n_childs; 254 | } 255 | #ifdef STD_ERR_PRINT 256 | std::cerr << "num_child: " << n_childs << std::endl; 257 | #endif 258 | max_miu = miu[max_miu_id]; 259 | int i=0; 260 | Node *pre = 0; 261 | 262 | for (Node *next = root->get_child();next;next = next->get_sibling(),++i){ 263 | if (next->is_pruned) { 264 | pre = next; 265 | continue; 266 | } 267 | if (max_miu > miu[i] && next->get_visits() + 8/(pow(max_miu-miu[i],2)*log(ttl_visits)) < max_visits){ 268 | next->is_pruned = 1; 269 | ++relative_prun_num; 270 | if (pre != 0){ 271 | pre->set_sibling(next->get_sibling()); 272 | continue; 273 | } 274 | 275 | } 276 | pre = next; 277 | } 278 | } 279 | 280 | 281 | 282 | void Node::print(int boardsize) const 283 | { 284 | #ifdef STD_ERR_PRINT 285 | std::string mv; 286 | coord_to_char(move, mv, boardsize); 287 | std::cerr.precision(4); 288 | std::cerr << std::right << std::setw(4) << mv 289 | << " score: " << std::left << std::setw(6) << ((double)node_score)/visits 290 | << ": " << std::right << std::setw(6) << ((double)results)/visits 291 | << "/" << std::left << std::setw(5) << visits 292 | << "[ RAVE: " << std::right<< std::setw(6) << r_results/r_visits 293 | << "/" << std::left << std::setw(5) << r_visits 294 | << " Prior: " << std::right << std::setw(6) << p_results/p_visits 295 | << "/" << std::left << std::setw(5) << p_visits << "]\n"; 296 | #endif 297 | } 298 | 299 | Tree::Tree(int maxsize, Board *board) 300 | { 301 | cur_root = 0; 302 | relative_prun_num = 0; 303 | this->maxsize = maxsize; 304 | this->board = board; 305 | root[0] = new Node[maxsize]; 306 | root[1] = new Node[maxsize]; 307 | root[0]->reset(); 308 | root[1]->reset(); 309 | size[0] = 1; 310 | size[1] = 1; 311 | } 312 | 313 | Tree::~Tree() 314 | { 315 | delete[] root[0]; 316 | delete[] root[1]; 317 | 318 | } 319 | 320 | void Tree::clear() 321 | { 322 | cur_root = 0; 323 | relative_prun_num = 0; 324 | root[0]->reset(); 325 | root[1]->reset(); 326 | size[0] = 1; 327 | size[1] = 1; 328 | } 329 | 330 | void Tree::clear_cur_root() 331 | { 332 | relative_prun_num = 0; 333 | size[cur_root] = 1; 334 | root[cur_root]->reset(); 335 | } 336 | 337 | Node *Tree::insert(Node *parent, int move, const Prior &prior) 338 | { 339 | if (size[cur_root] < maxsize) { 340 | Node *child = root[cur_root] + size[cur_root]++; 341 | child->reset(); 342 | parent->add_child(child); 343 | child->set_move(move, prior); 344 | return child; 345 | } else { 346 | std::cerr << "WARNING: Out of memory!\n"; 347 | return 0; 348 | } 349 | } 350 | 351 | Node *Tree::insert(Node *parent, const Node *orig) 352 | { 353 | if (size[1-cur_root] < maxsize) { 354 | Node *child = root[1-cur_root] + size[1-cur_root]++; 355 | child->copy_values(orig); 356 | parent->add_child(child); 357 | return child; 358 | } else { 359 | std::cerr << "WARNING: Out of memory!\n"; 360 | return 0; 361 | } 362 | } 363 | 364 | void Tree::copy_all(Node *parent, const Node *orig) 365 | { 366 | for (Node *node = orig->get_child(); node; node = node->get_sibling()) { 367 | Node *child = insert(parent, node); 368 | if (child) copy_all(child, node); 369 | } 370 | } 371 | 372 | int Tree::promote(int new_root,int step) 373 | { 374 | if (step >= START_REUSE_SUBTREE){ 375 | for (Node *node = root[cur_root]->get_child(); node; node = node->get_sibling()) { 376 | if (node->get_move() == new_root) { 377 | root[1-cur_root]->copy_values(node); 378 | copy_all(root[1-cur_root], node); 379 | clear_cur_root(); 380 | cur_root = 1-cur_root; 381 | // std::cerr << "reuse subtree" <"; 405 | node->print(board->get_size()); 406 | 407 | Node *childs[MAXSIZE2] = {0}; 408 | int len = 0; 409 | for (Node *child = node->get_child(); child; child=child->get_sibling()) { 410 | if (child->get_visits() >= threshold) childs[len++] = child; 411 | } 412 | 413 | while (true) { 414 | int best = -1, visits = 0; 415 | for (int i = 0; i < len; i++) { 416 | if (childs[i] && childs[i]->get_visits() > visits) { 417 | best = i; 418 | visits = childs[best]->get_visits(); 419 | } 420 | } 421 | if (best < 0) break; 422 | if (childs[best]->get_move()) print(childs[best], threshold, depth+1); 423 | childs[best] = 0; 424 | } 425 | #endif 426 | } 427 | 428 | void Tree::print(double winrate) const 429 | { 430 | #ifdef STD_ERR_PRINT 431 | int threshold = root[cur_root]->get_visits()/30; 432 | std::string sp = " "; 433 | std::cerr << "Active tree: " << cur_root << " " << get_size() <<" nodes.\n"; 434 | 435 | print(root[cur_root], threshold, 0); 436 | 437 | Node *best = get_best(winrate); 438 | std::cerr << "#Expected: " << best->get_value(1) << ", visits " 439 | << best->get_visits() << " PV:\n"; 440 | 441 | bool side = !board->get_side(); 442 | for (Node *n = root[cur_root]->get_best_child(winrate); n; n = n->get_best_child()) { 443 | side ? std::cerr << "B" : std::cerr << "W"; 444 | n->print(board->get_size()); 445 | side = !side; 446 | } 447 | 448 | std::cerr << "\nscore:\n" ; 449 | 450 | for (Node *n = root[cur_root]->get_child(); n ; n=n->get_sibling()){ 451 | n->print(board->get_size()); 452 | } 453 | std::cerr << "\n"; 454 | #endif 455 | } 456 | 457 | -------------------------------------------------------------------------------- /badukGo-0.1.5/tree.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Copyright (C) 2016 * 3 | * All rights reserved * 4 | * * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of * 6 | * this software and associated documentation files (the “Software”), to deal in the Software * 7 | * without restriction, including without limitation the rights to use, copy, modify, merge, * 8 | * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons * 9 | * to whom the Software is furnished to do so, subject to the following conditions: * 10 | * * 11 | * The above copyright notice and this permission notice shall be included in all copies or * 12 | * substantial portions of the Software. * 13 | * * 14 | * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * 15 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * 16 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * 17 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * 19 | * DEALINGS IN THE SOFTWARE. * 20 | **********************************************************************************************/ 21 | #ifndef __TREE_H__ 22 | #define __TREE_H__ 23 | #include "amaf.h" 24 | #include "Board.h" 25 | 26 | #include 27 | #define RELATE_PRUNE 28 | #ifdef RELATE_PRUNE 29 | #define BEGIN_PRUN 15 30 | #define END_PRUN 130 31 | #define AGRESSIVE_R_PRUN_ALPHA 0.8 32 | #define SOFT_R_PRUN_ALPHA 0.75 33 | #define LAZY_R_PRUN_ALPHA 0.7 34 | #define SOFT_THERESHOLD 0.75 35 | #define LAZY_THERESHOLD 0.8 36 | #define STOP_THERESHOLD 0.9 37 | #define R_PRUN_RAVE_DISCOUNT 0.99 38 | #endif 39 | 40 | #define CHANGE_BEST_POLICY 41 | 42 | class Node{ 43 | private: 44 | int move; 45 | int visits, results; 46 | double r_visits, r_results; 47 | double p_visits, p_results; 48 | 49 | Node *child, *sibling; 50 | float node_score; 51 | public: 52 | int is_expand; 53 | int is_pruned; 54 | 55 | void update_score(const float score){node_score += score;} 56 | float get_score() const {return node_score/visits;} 57 | void reset(); 58 | void copy_values(const Node *orig); 59 | void add_child(Node *child); 60 | void set_move(int, const Prior &prior); 61 | void set_results(int result); 62 | void set_amaf(int result, const AmafBoard &amaf, bool side, int depth); 63 | void set_amaf(int result, AmafBoard * amaf, bool side, int depth); 64 | int get_move() const{ return move; } 65 | int get_results() const{ return results; }; 66 | int get_visits() const{ return visits; }; 67 | double get_r_results() const{ return r_results; }; 68 | double get_r_visits() const{ return r_visits; }; 69 | Node *get_child() const{ return child; } 70 | Node *get_sibling() const{ return sibling; } 71 | void print(int boardsize) const; 72 | 73 | bool has_childs() const{ return child != 0; }; 74 | double get_value(int parent_visits) const; 75 | Node *select_child() const; 76 | Node *get_best_child(double winrate) const; 77 | Node *get_best_child() const; 78 | void set_child(Node *chd){child = chd;} 79 | void set_sibling(Node *sib){sibling = sib;} 80 | 81 | inline double get_r_prun_winrate(double alpha) const; 82 | void do_r_prun(int ttl_visits); 83 | 84 | 85 | 86 | 87 | }; 88 | 89 | class Tree{ 90 | private: 91 | Node *root[2]; 92 | int size[2], maxsize, cur_root; 93 | const Board *board; 94 | public: 95 | int relative_prun_num; 96 | 97 | Tree(int maxsize, Board *board); 98 | ~Tree(); 99 | void clear(); 100 | void clear_cur_root(); 101 | int promote(int new_root,int step); 102 | Node *insert(Node *parent, int move, const Prior &prior); 103 | Node *insert(Node *parent, const Node *orig); 104 | void copy_all(Node *parent, const Node *orig); 105 | int expand(Node *parent, const int *moves, int nmoves, const Prior[]); 106 | Node *get_best() const{ return root[cur_root]->get_best_child(); } 107 | Node *get_best(double winrate) const{ return root[cur_root]->get_best_child(winrate); } 108 | Node *get_root() const{ return root[cur_root]; } 109 | int get_size() const{ return size[cur_root];} 110 | void print(double winrate) const; 111 | void print(Node *node, int threshold, int depth) const; 112 | void do_r_prun(int ttl_visits, double alpha); 113 | 114 | }; 115 | #endif 116 | --------------------------------------------------------------------------------