void print_info(int r,int d) { int i,mate; float score; char str[32]; int t; uint64 nps = 0; int seldepth = 0; char pvstring[1024]; double hprm = 0; if(opt->mode == UCI_MODE) { i = pv_to_string(&pvstring[0],d); if(i > d) seldepth = i; t = ((get_time() - opt->startup_time)); if(t) nps = (si->nodes / t) * 1000; hprm = ((double)si->num_hash_saves/(double)opt->tt_numentries) * 1000.0; if(abs(r) >= MATE_VALUE - MAX_PLY) { if(r>0) mate = (MATE_VALUE - r + 1) / 2; else mate = -(MATE_VALUE + r) / 2; printf("info depth %d seldepth %d score mate %d time %d nodes "llufmt" nps "llufmt" hashfull %.0f pv %s",d,seldepth, mate, t,si->nodes,nps,hprm,pvstring); } else printf("info depth %d seldepth %d score cp %d time %d nodes "llufmt" nps "llufmt" hashfull %.0f pv %s",d,seldepth, r, t,si->nodes,nps,hprm,pvstring); #ifdef GTB if(tbhits > 0) printf("tbhits %d", tbhits); #endif printf("\n"); } else { //reversing the score if needed: //+ WHITE, - BLACK if(opt->comp_side == BLACK && r != 0) score = -(r / ((float)100)); else score = (r / ((float)100)); printf("%2d "llufmt,d,si->nodes); //converting the nodes count sprintf(str,llufmt,si->nodes); //formatting the spaces betw. nodes and pv: if(score >= 0) i = (int)(11 - strlen(str)); else i = (int)(10 - strlen(str)); while(i){ printf(" "); i--; } printf(" %.2f ",score); pv_to_string(&pvstring[0],d); printf("%s", pvstring); printf("\n"); } }
/** * Principle Variation Search (root node) * Difference with normal (non-root) search: * - Sending new PVs asap to the interface * - Sort order based on pv and amount of nodes of the subtrees * - No pruning and hash table lookup/store * - Compatible with all supported wild variants */ int search_t::pvs_root(int alpha, int beta, int depth) { assert(root.move_count > 0); int best = -score::INF; const bool is_pv = true; root.sort_moves(&stack->best_move); /* * Moves loop */ for (int i = 0; i < root.move_count; i++) { root_move_t * rmove = &root.moves[i]; move_t * move = &rmove->move; int nodes_before = nodes; //extensions and reductions int extend = extension(move, depth, is_pv, rmove->gives_check); int reduce = reduction(depth, i, rmove->is_dangerous); int score = 0; //go forward and search one level deeper forward(move, rmove->gives_check); if (i == 0) { score = -pvs(-beta, -alpha, depth - 1 + extend); } else { score = -pvs(-alpha - 1, -alpha, depth - 1 - reduce + extend); if (score > alpha) { //open window research w/o reductions score = -pvs(-beta, -alpha, depth - 1 + extend); } } backward(move); //handle results rmove->nodes += nodes - nodes_before; if (stop_all) { return alpha; } else if (score > best) { best = score; result_score = score; rmove->nodes += i; stack->best_move.set(move); bool exact = score::flags(score, alpha, beta) == score::EXACT; if (exact || false == move->equals(&stack->pv_moves[0])) { update_pv(&rmove->move); } uci::send_pv(best, depth, sel_depth, nodes + pruned_nodes, game->tm.elapsed(), pv_to_string().c_str(), score::flags(best, alpha, beta)); if (!exact) { //adjust asp. window return score; } assert(alpha < best); alpha = best; } } return best; }
/** * Iterative deepening - call aspiration search iterating over the depth. * For timed searched, the function decides if a new iteration should be started * or not. */ void search_t::iterative_deepening() { int last_score = -score::INF; const int max_time = game->tm.reserved_max(); const int min_time = game->tm.reserved_min(); bool timed_search = game->white_time || game->black_time; int depth; for (depth = 1; depth <= game->max_depth; depth++) { int score = aspiration(depth, last_score); if (abort(true)) { break; } store_pv(); if (timed_search) { bool score_jump = depth >= 6 && ((ABS(score - last_score) > 20) || score > score::WIN); int elapsed = game->tm.elapsed(); bool do_stop = false; if (root.move_count <= 1 && elapsed > min_time / 8) { //one legal move, still search a bit to get a ponder move do_stop = true; } else if (elapsed > max_time / 2) { //complex position, maximum (emergency) time control do_stop = true; } else if (elapsed > min_time / 2 && !score_jump && root.is_easy()) { //easy position, half time control do_stop = true; } else if (elapsed > min_time && !score_jump && !root.is_complex()) { //neutral position, normal time control do_stop = true; } else if (score::mate_in_ply(score) && depth > score::mate_in_ply(score)) { //mate in N and search depth > N do_stop = true; } //abort search or prepare pondering to abort early if (do_stop && pondering()) { game->tm.set_max(0); } else if (do_stop) { break; } } else if (depth >= 15 && game->target_score && score >= game->target_score && game->target_move.piece && game->target_move.equals(&stack->best_move)) { break; } last_score = score; } if (stack->pv_count > 0) { uci::send_pv(result_score, MIN(depth, game->max_depth), sel_depth, nodes + pruned_nodes, game->tm.elapsed(), pv_to_string().c_str(), score::EXACT); if (stack->pv_count > 1) { ponder_move.set(&stack->pv_moves[1]); } } }
void search_update_best() { int move, value, flags, depth, max_depth; const mv_t * pv; double time; sint64 node_nb; int mate, i, z; bool found; char move_string[256], pv_string[512]; search_update_current(); if (DispBest) { move = SearchBest[SearchCurrent->multipv].move; value = SearchBest[SearchCurrent->multipv].value; flags = SearchBest[SearchCurrent->multipv].flags; depth = SearchBest[SearchCurrent->multipv].depth; pv = SearchBest[SearchCurrent->multipv].pv; max_depth = SearchCurrent->max_depth; time = SearchCurrent->time; node_nb = SearchCurrent->node_nb; move_to_string(move,move_string,256); pv_to_string(pv,pv_string,512); mate = value_to_mate(value); if (SearchCurrent->multipv == 0){ save_multipv[SearchCurrent->multipv].mate = mate; save_multipv[SearchCurrent->multipv].depth = depth; save_multipv[SearchCurrent->multipv].max_depth = max_depth; save_multipv[SearchCurrent->multipv].value = value; save_multipv[SearchCurrent->multipv].time = time*1000.0; save_multipv[SearchCurrent->multipv].node_nb = node_nb; strcpy(save_multipv[SearchCurrent->multipv].pv_string,pv_string); } else{ found = false; for (i = 0; i < SearchCurrent->multipv; i++){ if (save_multipv[i].value < value){ found = true; break; } } if (found){ for (z = SearchCurrent->multipv; z > i; z--){ save_multipv[z].mate = save_multipv[z-1].mate; save_multipv[z].depth = save_multipv[z-1].depth; save_multipv[z].max_depth = save_multipv[z-1].max_depth; save_multipv[z].value = save_multipv[z-1].value; save_multipv[z].time = save_multipv[z-1].time; save_multipv[z].node_nb = save_multipv[z-1].node_nb; strcpy(save_multipv[z].pv_string,save_multipv[z-1].pv_string); } save_multipv[i].mate = mate; save_multipv[i].depth = depth; save_multipv[i].max_depth = max_depth; save_multipv[i].value = value; save_multipv[i].time = time*1000.0; save_multipv[i].node_nb = node_nb; strcpy(save_multipv[i].pv_string,pv_string); } else{ save_multipv[SearchCurrent->multipv].mate = mate; save_multipv[SearchCurrent->multipv].depth = depth; save_multipv[SearchCurrent->multipv].max_depth = max_depth; save_multipv[SearchCurrent->multipv].value = value; save_multipv[SearchCurrent->multipv].time = time*1000.0; save_multipv[SearchCurrent->multipv].node_nb = node_nb; strcpy(save_multipv[SearchCurrent->multipv].pv_string,pv_string); } } if (depth > 1 || (depth == 1 && SearchCurrent->multipv == SearchInput->multipv)){ for (i = 0; i <= SearchInput->multipv; i++){ if (save_multipv[i].mate == 0) { // normal evaluation if (false) { } else if (flags == SearchExact) { send("info multipv %d depth %d seldepth %d score cp %d time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].value,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } else if (flags == SearchLower) { send("info multipv %d depth %d seldepth %d score cp %d lowerbound time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].value,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } else if (flags == SearchUpper) { send("info multipv %d depth %d seldepth %d score cp %d upperbound time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].value,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } } else { // mate announcement if (false) { } else if (flags == SearchExact) { send("info multipv %d depth %d seldepth %d score mate %d time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].mate,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } else if (flags == SearchLower) { send("info multipv %d depth %d seldepth %d score mate %d lowerbound time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].mate,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } else if (flags == SearchUpper) { send("info multipv %d depth %d seldepth %d score mate %d upperbound time %.0f nodes " S64_FORMAT " pv %s",i+1,save_multipv[i].depth,save_multipv[i].max_depth,save_multipv[i].mate,save_multipv[i].time,save_multipv[i].node_nb,save_multipv[i].pv_string); } } } } } // update time-management info if (SearchBest[SearchCurrent->multipv].depth > 1) { if (SearchBest[SearchCurrent->multipv].value <= SearchRoot->last_value - BadThreshold) { SearchRoot->bad_1 = true; SearchRoot->easy = false; SearchRoot->flag = false; } else { SearchRoot->bad_1 = false; } } }