/** * 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; }
bool CPanelLabNameStrings::TransferDataFromWindow() { bool bRtn = (m_pData != NULL); if(bRtn) { wxString s; wxTextCtrl *ptext[3] = {m_pTextLadder, m_pTextPos, m_pTextNeg}; CLabSynonym *pSyn[3] = { &(m_pData->m_vsSynonymLadder), &(m_pData->m_vsSynonymPosCtrl), &(m_pData->m_vsSynonymNegCtrl) }; size_t i; bool bRtn = true; for(i = 0; i < 3; i++) { s = ptext[i]->GetValue(); vector<wxString> *pvs(pSyn[i]->GetVectorPtr()); if(!nwxString::SplitLines(s.c_str(),pvs,true,true)) { mainApp::ShowError( _T("Please enter at least one identifier"),this); nwxBookCtrlFocus::Focus(ptext[i]); i = 3; // loop exit bRtn = false; } } m_pData->SetUseSampleName(!!m_pRadioNameType->GetSelection()); m_pData->m_sStdCtrlName = m_pTextStdCtrlName->GetValue(); // Specimen Category size_t nTYPES = CLabSpecimenCategory::TypeCount(); CLabSetSpecimenCategory &setSpec(m_pData->m_setSpecimenCategory); for(i = 0; i < nTYPES; i++) { s = m_pvTextSpecimenTypes.at(i)->GetValue(); setSpec.SetSynonyms(i,s); } } return bRtn; }
/** * Get a score for every legal move */ void search_t::book_calc() { const int count = init_root_moves(); std::string fen = brd.to_string(); uci::out("book_calc start"); for (int i = 0; i < count; i++) { root_move_t * rmove = &root.moves[i]; move_t * move = &rmove->move; forward(move, rmove->gives_check); int score = 0; U64 nodes_before = nodes; for (int depth = 1; depth <= game->max_depth; depth++) { score = -pvs(-score::INF, score::INF, depth - 1); } backward(move); uci::out("book_calc fen " + fen + " move " + move->to_string() + " depth " + uci::itoa(game->max_depth) + " score " + uci::itoa(score) + " nodes " + uci::itoa(nodes - nodes_before) + " variant " + uci::itoa(wild)); } uci::out("book_calc ready"); }
bool CPanelLabNameStrings::TransferDataFromWindow() { bool bRtn = (m_pData != NULL); if(bRtn) { NAME_STRING_ARRAYS size_t i; for(i = 0; i < COUNT; i++) { s = ptext[i]->GetValue(); vector<wxString> *pvs(pSyn[i]->GetVectorPtr()); if(nwxString::SplitLines(s.utf8_str(),pvs,true,true)) {} else if(!ALLOW_EMPTY(i)) { mainApp::ShowError( "Please enter at least one identifier",this); nwxBookCtrlFocus::Focus(ptext[i]); i = COUNT; // loop exit bRtn = false; } } m_pData->SetUseSampleName(!!m_pRadioNameType->GetSelection()); m_pData->m_sStdCtrlName = m_pTextStdCtrlName->GetValue(); // Specimen Category size_t nTYPES = CLabSpecimenCategory::TypeCount(); CLabSetSpecimenCategory &setSpec(m_pData->m_setSpecimenCategory); for(i = 0; i < nTYPES; i++) { s = m_pvTextSpecimenTypes.at(i)->GetValue(); setSpec.SetSynonyms(i,s); } } return bRtn; }
int maxPathSum(int n, const std::vector<int>& path) { if((n*(n+1))/2!= path.size()) { std::cerr<<n<<' '<<path.size()<<std::endl; throw std::invalid_argument("wrong argument"); return -1; } std::vector<int> vs (n,0) , pvs(n,0); int k = 1; pvs[0] = path[0]; for(int i = 1 ; i < n ; ++ i) { vs[0] = path[k] + pvs[0]; vs[i] = path[k+i] + pvs[i-1]; for(int j = 1 ; j <= i - 1; ++ j) { vs[j] = std::max(pvs[j],pvs[j-1]) + path[k+j]; } pvs = vs; k += (i+1); } return *std::max_element(vs.begin(),vs.end()); }
/** * Principle Variation Search (fail-soft) * @param alpha lowerbound value * @param beta upperbound value * @param depth remaining search depth * @return score for the current node */ int search_t::pvs(int alpha, int beta, int depth) { assert(alpha < beta); assert(alpha >= -score::INF); assert(beta <= score::INF); stack->pv_count = 0; sel_depth = MAX(brd.ply, sel_depth); stack->best_move.clear(); /* * If no more depth remaining, return quiescence value */ if (depth < 1) { const int score = qsearch(alpha, beta, 0); return score; } /* * Stop conditions */ //time nodes++; if (abort()) { return alpha; } //ceiling if (brd.ply >= (MAX_PLY - 1)) { return evaluate(this); } assert(depth > 0 && depth <= MAX_PLY); int alpha1 = alpha; //mate distance pruning: if mate(d) in n don't search deeper if ((score::MATE - brd.ply) < beta) { beta = score::MATE - brd.ply; if (alpha >= beta) { return beta; } } if ((-score::MATE + brd.ply) > alpha) { alpha = -score::MATE + brd.ply; if (beta <= alpha) { return alpha; } } //draw by lack of material or fifty quiet moves if (is_draw()) { return draw_score(); } /* * Transposition table lookup */ const bool pv = alpha + 1 < beta; stack->tt_key = brd.stack->tt_key; //needed for testing repetitions int tt_move = 0, tt_flag = 0, tt_score; if (trans_table::retrieve(stack->tt_key, brd.ply, depth, tt_score, tt_move, tt_flag)) { if (pv && tt_flag == score::EXACT) { return tt_score; } else if (!pv && tt_score >= beta && tt_flag == score::LOWERBOUND) { return tt_score; } else if (!pv && tt_score <= alpha && tt_flag == score::UPPERBOUND) { return tt_score; } } stack->tt_move.set(tt_move); /* * Node pruning */ const bool in_check = stack->in_check; const int eval = evaluate(this); const bool do_prune_node = eval >= beta && !in_check && !pv && !score::is_mate(beta) && brd.has_pieces(brd.us()); // beta pruning if (do_prune_node && depth < 4 && beta_pruning) { int bp_score = eval - 50 * depth; if (bp_score >= beta) { return bp_score; } } //null move pruning if (do_prune_node && null_enabled) { int R = 3; forward(); int null_score = -pvs(-beta, -alpha, depth - 1 - R); backward(); if (stop_all) { return alpha; } else if (null_score >= beta) { const int RV = 5; if (null_verify && depth > RV && material::is_eg(this)) { //verification int verified_score = pvs(alpha, beta, depth - 1 - RV); if (verified_score >= beta) { return verified_score; } } else { //no verification return null_score; } } } /* * Internal iterative deepening (IID) */ if (pv && depth > 2 && tt_move == 0) { int iid_score = pvs(alpha, beta, depth - 2); if (score::is_mate(iid_score)) { return iid_score; } else if (stack->best_move.piece) { stack->tt_move.set(&stack->best_move); } } /* * Moves loop */ //if there is no first move, it's checkmate or stalemate move_t * move = move::first(this, depth); if (!move) { return in_check ? -score::MATE + brd.ply : draw_score(); } //set futility pruning delta value bool do_ffp = false; int delta = score::INVALID; if (depth <= 8 && !in_check && !score::is_mate(alpha) && !material::is_eg(this) && ffp_enabled) { int ffp_score = eval + 40 * depth; if (ffp_score <= alpha) { do_ffp = true; delta = ffp_score + 50; } } //prepare and do the loop int best = -score::INF; int searched_moves = 0; const int score_max = score::MATE - brd.ply - 1; stack->best_move.clear(); do { assert(brd.valid(move) && brd.legal(move)); assert(stack->best_move.equals(move) == false); assert(in_searched(move, searched_moves) == false); const int gives_check = brd.gives_check(move); assert(gives_check == 0 || gives_check == 1 || gives_check == 2); /* * Move pruning: skip all futile moves */ const bool is_dangerous = in_check || gives_check || move->capture || move->promotion || move->castle || is_advanced_passed_pawn(move); bool pruned = false; if (do_ffp && searched_moves > 0) { pruned = !is_dangerous; pruned |= gives_check == 0 && (move->capture || move->promotion) && brd.max_gain(move) + delta <= alpha; if (pruned) { pruned_nodes++; continue; } } /* * Move extensions */ int extend = extension(move, depth, pv, gives_check); /* * Move Reductions (Late Move Reductions, LMR) */ int reduce = reduction(depth, searched_moves, is_dangerous); /* * Go forward and search next node */ forward(move, gives_check); int score; if (searched_moves == 0) { score = -pvs(-beta, -alpha, depth - 1 + extend); } else { score = -pvs(-alpha - 1, -alpha, depth - 1 - reduce + extend); if (score > alpha && (pv || reduce > 0)) { //open window research without reductions score = -pvs(-beta, -alpha, depth - 1 + extend); } } backward(move); /* * Handle results: update the best value / do a beta cutoff */ if (stop_all) { return alpha; } else if (score > best) { stack->best_move.set(move); if (score >= beta) { trans_table::store(stack->tt_key, brd.root_ply, brd.ply, depth, score, move->to_int(), score::LOWERBOUND); if (!move->capture && !move->promotion && !move->castle) { update_killers(move); update_history(move); for (int i = 0; i < searched_moves; i++) { move_t * m = &stack->searched[i]; if (!m->capture && !m->promotion && !m->castle) { history[m->piece][m->tsq] >>= searched_moves; } } }