int search_uct(int color, int node_n) { NODE *pN = &node[node_n]; CHILD *c = NULL; int select, z, err, win, current_depth; for (;;) { select = select_best_ucb(node_n, color); c = &pN->child[select]; z = c->z; err = put_stone(z, color, FILL_EYE_ERR); if ( err == 0 ) break; c->z = ILLEGAL_Z; // select other move } current_depth = depth; path[depth++] = c->z; // playout in first time. <= 10 can reduce node. if ( c->games <= 0 || depth == D_MAX || (c->z == 0 && depth>=2 && path[depth-2]==0) ) { win = -playout(flip_color(color)); } else { if ( c->next == NODE_EMPTY ) c->next = create_node(c->z); win = -search_uct(flip_color(color), c->next); } update_rave(pN, color, current_depth, win); // update winrate c->rate = (c->rate * c->games + win) / (c->games + 1); c->games++; pN->child_games_sum++; return win; }
int main() { int color = 1; int z; srand( (unsigned)time( NULL ) ); for (;;) { z = play_one_move(color); printf("moves=%4d, color=%d, z=%d\n",moves, color, get81(z)); print_board(); record[moves] = z; moves++; if ( moves == MAX_MOVES ) { printf("max moves!\n"); break; } if ( z == 0 && moves >= 2 && record[moves-2] == 0 ) { printf("two pass\n"); break; } color = flip_color(color); } return 0; }
int playout(int turn_color) { int color = turn_color; int previous_z = 0; int loop; int loop_max = B_SIZE*B_SIZE + 200; // for triple ko all_playouts++; for (loop=0; loop<loop_max; loop++) { // all empty points are candidates. int empty[BOARD_MAX][2]; // [0]...z, [1]...probability int empty_num = 0; int prob_sum = 0; int x,y,z,err,pr; for (y=0;y<B_SIZE;y++) for (x=0;x<B_SIZE;x++) { int z = get_z(x+1,y+1); if ( board[z] != 0 ) continue; empty[empty_num][0] = z; pr = 100; // pr = get_prob(z, previous_z, color); empty[empty_num][1] = pr; prob_sum += pr; empty_num++; } for (;;) { int i = 0; if ( empty_num == 0 ) { z = 0; } else { int r = rand() % prob_sum; int sum = 0; for (i=0; i<empty_num; i++) { sum += empty[i][1]; // 0,1,2 [0]=1, [1]=1, [2]=1 if ( sum > r ) break; } if ( i==empty_num ) { prt("Err! prob_sum=%d,sum=%d,r=%d,r=%d\n",prob_sum,sum,r,i); exit(0); } z = empty[i][0]; } err = put_stone(z, color, FILL_EYE_ERR); if ( err == 0 ) break; // pass is ok. prob_sum -= empty[i][1]; empty[i][0] = empty[empty_num-1][0]; // err, delete empty[i][1] = empty[empty_num-1][1]; empty_num--; } if ( flag_test_playout ) record[moves++] = z; if ( depth < D_MAX ) path[depth++] = z; if ( z == 0 && previous_z == 0 ) break; // continuous pass previous_z = z; // prt("loop=%d,z=%s,c=%d,empty_num=%d,ko_z=%d\n",loop,get_char_z(z),color,empty_num,ko_z); color = flip_color(color); } return count_score(turn_color); }
void hexbright::print_number(long number) { // reverse number (so it prints from left to right) BOOL negative = false; if(number<0) { number = 0-number; negative = true; } _color = GLED; _number=1; // to guarantee printing when dealing with trailing zeros (100 can't be stored as 001, use 1001) do { _number = _number * 10 + (number%10); number = number/10; _color = flip_color(_color); } while(number>0); if(negative) { set_led(flip_color(_color), 500); print_wait_time = 600/update_delay; } }
// put stone. success returns 0. in playout, fill_eye_err = 1. int put_stone(int tz, int color, int fill_eye_err) { int around[4][3]; int un_col = flip_color(color); int space = 0; int wall = 0; int mycol_safe = 0; int capture_sum = 0; int ko_maybe = 0; int liberty, stone; int i; if (tz == 0) { ko_z = 0; return 0; } // pass // count 4 neighbor's liberty and stones. for (i = 0; i<4; i++) { int z, c, liberty, stone; around[i][0] = around[i][1] = around[i][2] = 0; z = tz + dir4[i]; c = board[z]; // color if (c == 0) space++; if (c == 3) wall++; if (c == 0 || c == 3) continue; count_liberty(z, &liberty, &stone); around[i][0] = liberty; around[i][1] = stone; around[i][2] = c; if (c == un_col && liberty == 1) { capture_sum += stone; ko_maybe = z; } if (c == color && liberty >= 2) mycol_safe++; } if (capture_sum == 0 && space == 0 && mycol_safe == 0) return 1; // suicide if (tz == ko_z) return 2; // ko if (wall + mycol_safe == 4 && fill_eye_err) return 3; // eye if (board[tz] != 0) return 4; for (i = 0; i<4; i++) { int lib = around[i][0]; int c = around[i][2]; if (c == un_col && lib == 1 && board[tz + dir4[i]]) { take_stone(tz + dir4[i], un_col); } } board[tz] = color; count_liberty(tz, &liberty, &stone); if (capture_sum == 1 && stone == 1 && liberty == 1) ko_z = ko_maybe; else ko_z = 0; return 0; }
int primitive_monte_calro(int color) { int try_num = 30; // number of playout int best_z = 0; double best_value; double win_rate; int x,y,err,i,win_sum,win; int ko_z_copy; int board_copy[BOARD_MAX]; // keep current board ko_z_copy = ko_z; memcpy(board_copy, board, sizeof(board)); best_value = -100; // try all empty point for (y=0;y<B_SIZE;y++) for (x=0;x<B_SIZE;x++) { int z = get_z(x+1,y+1); if ( board[z] != 0 ) continue; err = put_stone(z, color, FILL_EYE_ERR); if ( err != 0 ) continue; win_sum = 0; for (i=0;i<try_num;i++) { int board_copy2[BOARD_MAX]; int ko_z_copy2 = ko_z; memcpy(board_copy2, board, sizeof(board)); win = -playout(flip_color(color)); win_sum += win; ko_z = ko_z_copy2; memcpy(board, board_copy2, sizeof(board)); } win_rate = (double)win_sum / try_num; // print_board(); // prt("z=%d,win=%5.3f\n",get81(z),win_rate); if ( win_rate > best_value ) { best_value = win_rate; best_z = z; // prt("best_z=%d,color=%d,v=%5.3f,try_num=%d\n",get81(best_z),color,best_value,try_num); } ko_z = ko_z_copy; memcpy(board, board_copy, sizeof(board)); // resume board } return best_z; }
void hexbright::update_number() { if(_number>0) { // we have something to do... #ifdef DEBUG if(DEBUG==DEBUG_NUMBER) { static int last_printed = 0; if(last_printed != _number) { last_printed = _number; Serial.print("number remaining (read from right to left): "); Serial.println(_number); } } #endif if(!print_wait_time) { if(_number==1) { // minimum delay between printing numbers print_wait_time = 2500/update_delay; _number = 0; return; } else { print_wait_time = 300/update_delay; } if(_number/10*10==_number) { #if (DEBUG==DEBUG_NUMBER) Serial.println("zero"); #endif // print_wait_time = 500/update_delay; set_led(_color, 400); } else { set_led(_color, 120); _number--; } if(_number && !(_number%10)) { // next digit? print_wait_time = 600/update_delay; _color = flip_color(_color); _number = _number/10; } } } if(print_wait_time) { print_wait_time--; } }
void selfplay() { int color = 1; int z,search; for (;;) { if ( color == 1 ) { search = SEARCH_UCT; //SEARCH_PRIMITIVE; } else { search = SEARCH_UCT; } z = get_computer_move(color, search); add_moves(z, color); if ( z == 0 && moves > 1 && record[moves-2] == 0 ) break; if ( moves > 300 ) break; // too long color = flip_color(color); } print_sgf(); }
static struct npr_rbtree_node * insert(struct npr_rbtree *t, struct npr_rbtree_node *n, npr_rbtree_key_t key, npr_rbtree_value_t v, int *insert_new) { if (n == NULL) { n = alloc_node(t); n->left = NULL; n->right = NULL; n->v = v; n->key = key; n->color = RED; *insert_new = 1; return n; } if (is_red(n->left) && is_red(n->right)) { flip_color(n); } if (key == n->key) { n->v = v; } else if (key < n->key) { n->left = insert(t, n->left, key, v, insert_new); } else { n->right = insert(t, n->right, key, v, insert_new); } if (is_red(n->right)) { n = rotate_left(n); } if (is_red(n->left) && is_red(n->left->left)) { n = rotate_right(n); } return n; }
void update_rave(NODE *pN, int color, int current_depth, double win) { int played_color[BOARD_MAX]; int i,z; int c = color; memset(played_color, 0, sizeof(played_color)); for (i=current_depth; i<depth; i++) { z = path[i]; if ( played_color[z] == 0 ) played_color[z] = c; c = flip_color(c); } played_color[0] = 0; // ignore pass for (i=0; i<pN->child_num; i++) { CHILD *c = &pN->child[i]; if ( c->z == ILLEGAL_Z ) continue; if ( played_color[c->z] != color ) continue; c->rave_rate = (c->rave_games * c->rave_rate + win) / (c->rave_games + 1); c->rave_games++; pN->child_rave_games_sum++; } }
int main() { int color = 1; // 現在の手番の色。黒が1で白が2 int tesuu = 0; // 手数 hama[0] = 0; hama[1] = 0; bool pray_pass = false; srand( (unsigned)time( NULL ) ); char str[256]; char playstr[256]; // stdoutをバッファリングしないように。GTPで通信に失敗するので。 setbuf(stdout, NULL); setbuf(stderr, NULL); // stderrに書くとGoGuiに表示される。 //loop: // 盤面初期化 {int i,x,y; for (i=0;i<BOARD_MAX;i++) board[i] = 3; for (y=0;y<B_SIZE;y++) for (x=0;x<B_SIZE;x++) board[get_z(x,y)] = 0; } // static int score_sum; // static int loop_count; for (;;) { if ( fgets(str, 256, stdin)==NULL ) break; // 標準入力から読む //fprintf(stderr, playstr); //strcpy(playstr,str); if ( strstr(str,"boardsize") ) { send_gtp("= \n\n"); // "boardsize 19" 19路盤 } else if ( strstr(str,"clear_board") ) { for (int i=0;i<BOARD_MAX;i++) board[i] = 3; for (int y=0;y<B_SIZE;y++) for (int x=0;x<B_SIZE;x++) board[get_z(x,y)] = 0; tesuu = 0; color = 1; hama[0] = 0; hama[1] = 0; pray_pass = false; node_num = 0; send_gtp("= \n\n"); } else if ( strstr(str,"name") ) send_gtp("= ayasam\n\n"); else if ( strstr(str,"version") ) send_gtp("= 0.0.1\n\n"); else if ( strstr(str,"genmove w") ) { if (pray_pass) { send_gtp("= pass\n\n"); } else { color = 2; clock_t bt = clock(); all_playouts = 0; // playout回数を初期化 #if 0 // 0 でUCT探索 int z = select_best_move(color); // 原始モンテカルロ #else int z = select_best_uct(color); // UCT #endif int err = move(z,color); // 打ってみる if ( err != 0 ) { show_board(); fprintf( stderr, "Err!\n"); char mvstr[8]; change_z_str(mvstr, z); fprintf(stderr, "%s\n", mvstr); exit(0); } kifu[tesuu] = z; tesuu++; print_board(); char gtstr[12] = "= "; char mvstr[8]; change_z_str(mvstr, z); strcat(gtstr, mvstr); strcat(gtstr, "\n\n"); send_gtp(gtstr); fprintf(stderr,"play_xy = %s,手数=%d,色=%d,all_playouts=%d\n",mvstr,tesuu,color,all_playouts); double t = (double)(clock()+1 - bt) / CLOCKS_PER_SEC; fprintf(stderr,"%.1f 秒, %.0f playout/秒\n",t,all_playouts/t); } } else if ( strstr(str,"genmove b") ) { if (pray_pass) { send_gtp("= pass\n\n"); } else { color = 1; clock_t bt = clock(); all_playouts = 0; // playout回数を初期化 #if 0 // 0 でUCT探索 int z = select_best_move(color); // 原始モンテカルロ #else int z = select_best_uct(color); // UCT #endif int err = move(z,color); // 打ってみる if ( err != 0 ) { show_board(); fprintf( stderr, "Err!\n"); char mvstr[8]; change_z_str(mvstr, z); fprintf(stderr, "%s\n", mvstr); exit(0); } kifu[tesuu] = z; tesuu++; print_board(); char gtstr[12] = "= "; char mvstr[8]; change_z_str(mvstr, z); strcat(gtstr, mvstr); strcat(gtstr, "\n\n"); send_gtp(gtstr); fprintf(stderr,"play_xy = %s,手数=%d,色=%d,all_playouts=%d\n",mvstr,tesuu,color,all_playouts); double t = (double)(clock()+1 - bt) / CLOCKS_PER_SEC; fprintf(stderr,"%.1f 秒, %.0f playout/秒\n",t,all_playouts/t); } } // 相手の手を受信 "play W D17" のように来る else if ( strstr(str,"play") ) { char *tp; tp = strtok(str, " "); tp = strtok(NULL, " "); if (strstr(tp, "W") || strstr(tp, "w")) { color = 2; } else { color = 1; } if (tp) { tp = strtok(NULL, " "); int z = change_str_z(tp); int err = play_move(z,color); // 打ってみる if ( (err != 0) && (err != 3) ) { show_board(); fprintf( stderr, "Err!\n"); char mvstr[8]; change_z_str(mvstr, z); fprintf(stderr, "%s\n", mvstr); strcat(playstr,"Error!:"); if (err == 1) { strcat(playstr,"1"); } else if (err == 2) { strcat(playstr,"2"); } else if (err == 3) { strcat(playstr,"3"); } else if (err == 4) { strcat(playstr,"4"); } strcat(playstr," "); strcat(playstr,tp); strcat(playstr," -> "); strcat(playstr,mvstr); strcat(playstr,"\n"); exit(0); } kifu[tesuu] = z; tesuu++; if (z == 0) { pray_pass = true; } else { pray_pass = false; } print_board(); } send_gtp("= \n\n"); } else if ( strstr(str, "showboard")) { show_board(); send_gtp("= \n\n"); } else if ( strstr(str, "quit")) { send_gtp("= \n\n"); break; } else if ( strstr(str,"test")) { for (int n=0;;n++) { for (int i=0;i<BOARD_MAX;i++) board[i] = 3; for (int y=0;y<B_SIZE;y++) for (int x=0;x<B_SIZE;x++) board[get_z(x,y)] = 0; tesuu = 0; color = 1; hama[0] = 0; hama[1] = 0; pray_pass = false; while (true) { if (pray_pass) { break; } else { clock_t bt = clock(); all_playouts = 0; // playout回数を初期化 #if 0 // 0 でUCT探索 int z = select_best_move(color); // 原始モンテカルロ #else int z = select_best_uct(color); // UCT #endif int err = move(z,color); // 打ってみる if ( err != 0 ) { show_board(); fprintf( stderr, "Err!\n"); char mvstr[8]; change_z_str(mvstr, z); fprintf(stderr, "%s\n", mvstr); exit(0); } //kifu[tesuu] = z; tesuu++; //print_board(); //char gtstr[12] = "= "; char mvstr[8]; change_z_str(mvstr, z); //strcat(gtstr, mvstr); //strcat(gtstr, "\n\n"); //send_gtp(gtstr); fprintf(stderr,"play_xy = %s,手数=%d,色=%d,all_playouts=%d\n",mvstr,tesuu,color,all_playouts); double t = (double)(clock()+1 - bt) / CLOCKS_PER_SEC; fprintf(stderr,"%.1f 秒, %.0f playout/秒\n",t,all_playouts/t); color = flip_color(color); if (z == 0) { pray_pass = true; } } } print_board(); printf("%d end\n", n); } } else { send_gtp("= \n\n"); // それ以外のコマンドにはOKを返す } show_board(); } /* // 自己対戦のテスト用 int score = count_score(1); score_sum += score; loop_count++; FILE *fp = fopen("out.txt","a+"); fprintf(fp,"Last Score=%d,%d,%d,tesuu=%d\n",score,score_sum,loop_count,tesuu); fclose(fp); printf("Last Score=%d,%d,%d,tesuu=%d\n",score,score_sum,loop_count,tesuu); color = 1; tesuu = 0; goto loop; */ // SGFで棋譜を吐き出す /* printf("(;GM[1]SZ[%d]\r\n",B_SIZE); for (int i=0; i<tesuu; i++) { int z = kifu[i]; int y = z / WIDTH; int x = z - y*WIDTH; if ( z == 0 ) x = y = 20; char *sStone[2] = { "B", "W" }; printf(";%s[%c%c]",sStone[i&1], x+'a'-1, y+'a'-1 ); if ( ((i+1)%10)==0 ) printf("\r\n"); } printf("\r\n)\r\n"); */ return 0; }