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; }
void Player::PlayerUCT::walk_tree(Board & board, Node * node, int depth){ int toplay = board.toplay(); if(!node->children.empty() && node->outcome < 0){ //choose a child and recurse Node * child; do{ int remain = board.movesremain(); child = choose_move(node, toplay, remain); if(child->outcome < 0){ movelist.addtree(child->move, toplay); if(!board.move(child->move, (player->minimax == 0), (player->locality || player->weightedrandom) )){ logerr("move failed: " + child->move.to_s() + "\n" + board.to_s(false)); assert(false && "move failed"); } child->exp.addvloss(); //balanced out after rollouts walk_tree(board, child, depth+1); child->exp.addv(movelist.getexp(toplay)); if(!player->do_backup(node, child, toplay) && //not solved player->ravefactor > min_rave && //using rave node->children.num() > 1 && //not a macro move 50*remain*(player->ravefactor + player->decrrave*remain) > node->exp.num()) //rave is still significant update_rave(node, toplay); return; } }while(!player->do_backup(node, child, toplay)); return; } if(player->profile && stage == 0){ stage = 1; timestamps[1] = Time(); } int won = (player->minimax ? node->outcome : board.won()); //if it's not already decided if(won < 0){ //create children if valid if(node->exp.num() >= player->visitexpand+1 && create_children(board, node, toplay)){ walk_tree(board, node, depth); return; } if(player->profile){ stage = 2; timestamps[2] = Time(); } //do random game on this node for(int i = 0; i < player->rollouts; i++){ Board copy = board; rollout(copy, node->move, depth); } }else{ movelist.finishrollout(won); //got to a terminal state, it's worth recording } treelen.add(depth); movelist.subvlosses(1); if(player->profile){ timestamps[3] = Time(); if(stage == 1) timestamps[2] = timestamps[3]; stage = 3; } return; }