예제 #1
0
파일: search.cpp 프로젝트: hof/qm2
/**
 * 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;
}
예제 #2
0
파일: qsearch.c 프로젝트: syzygy1/Cfish
Value name_NT_InCheck(qsearch)(Pos* pos, Stack* ss, Value alpha, BETA_ARG
                               Depth depth)
{
  assert(InCheck == !!pos_checkers());
  assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
  assert(PvNode || (alpha == beta - 1));
  assert(depth <= DEPTH_ZERO);

  Move pv[MAX_PLY+1];
  TTEntry *tte;
  Key posKey;
  Move ttMove, move, bestMove;
  Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
  int ttHit, ttPv, givesCheck, evasionPrunable;
  Depth ttDepth;
  int moveCount;

  if (PvNode) {
    oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves
    (ss+1)->pv = pv;
    ss->pv[0] = 0;
  }

  bestMove = 0;
  moveCount = 0;

  // Check for an instant draw or if the maximum ply has been reached
  if (is_draw(pos) || ss->ply >= MAX_PLY)
    return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW;

  assert(0 <= ss->ply && ss->ply < MAX_PLY);

  // Decide whether or not to include checks: this fixes also the type of
  // TT entry depth that we are going to use. Note that in qsearch we use
  // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
  ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
                                                : DEPTH_QS_NO_CHECKS;

  // Transposition table lookup
  posKey = pos_key();
  tte = tt_probe(posKey, &ttHit);
  ttValue = ttHit ? value_from_tt(tte_value(tte), ss->ply) : VALUE_NONE;
  ttMove = ttHit ? tte_move(tte) : 0;
  ttPv = ttHit ? tte_is_pv(tte) : 0;

  if (  !PvNode
      && ttHit
      && tte_depth(tte) >= ttDepth
      && ttValue != VALUE_NONE // Only in case of TT access race
      && (ttValue >= beta ? (tte_bound(tte) &  BOUND_LOWER)
                          : (tte_bound(tte) &  BOUND_UPPER)))
    return ttValue;

  // Evaluate the position statically
  if (InCheck) {
    ss->staticEval = VALUE_NONE;
    bestValue = futilityBase = -VALUE_INFINITE;
  } else {
    if (ttHit) {
      // Never assume anything on values stored in TT
      if ((ss->staticEval = bestValue = tte_eval(tte)) == VALUE_NONE)
         ss->staticEval = bestValue = evaluate(pos);

      // Can ttValue be used as a better position evaluation?
      if (ttValue != VALUE_NONE)
        if (tte_bound(tte) & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))
          bestValue = ttValue;
    } else
      ss->staticEval = bestValue =
      (ss-1)->currentMove != MOVE_NULL ? evaluate(pos)
                                       : -(ss-1)->staticEval + 2 * Tempo;

    // Stand pat. Return immediately if static value is at least beta
    if (bestValue >= beta) {
      if (!ttHit)
        tte_save(tte, posKey, value_to_tt(bestValue, ss->ply), ttPv,
                 BOUND_LOWER, DEPTH_NONE, 0, ss->staticEval,
                 tt_generation());

      return bestValue;
    }

    if (PvNode && bestValue > alpha)
      alpha = bestValue;

    futilityBase = bestValue + 128;
  }

  ss->history = &(*pos->counterMoveHistory)[0][0];

  // Initialize move picker data for the current position, and prepare
  // to search the moves. Because the depth is <= 0 here, only captures,
  // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
  // be generated.
  mp_init_q(pos, ttMove, depth, to_sq((ss-1)->currentMove));

  // Loop through the moves until no moves remain or a beta cutoff occurs
  while ((move = next_move(pos, 0))) {
    assert(move_is_ok(move));

    givesCheck = gives_check(pos, ss, move);

    moveCount++;

    // Futility pruning
    if (   !InCheck
        && !givesCheck
        &&  futilityBase > -VALUE_KNOWN_WIN
        && !advanced_pawn_push(pos, move)) {
      assert(type_of_m(move) != ENPASSANT); // Due to !advanced_pawn_push

      futilityValue = futilityBase + PieceValue[EG][piece_on(to_sq(move))];

      if (futilityValue <= alpha) {
        bestValue = max(bestValue, futilityValue);
        continue;
      }

      if (futilityBase <= alpha && !see_test(pos, move, 1)) {
        bestValue = max(bestValue, futilityBase);
        continue;
      }
    }

    // Detect non-capture evasions that are candidates to be pruned
    evasionPrunable =    InCheck
                     && (depth != DEPTH_ZERO || moveCount > 2)
                     &&  bestValue > VALUE_MATED_IN_MAX_PLY
                     && !is_capture(pos, move);

    // Don't search moves with negative SEE values
    if (  (!InCheck || evasionPrunable)
        &&  !see_test(pos, move, 0))
      continue;

    // Speculative prefetch as early as possible
    prefetch(tt_first_entry(key_after(pos, move)));

    // Check for legality just before making the move
    if (!is_legal(pos, move)) {
      moveCount--;
      continue;
    }

    ss->currentMove = move;
    ss->history = &(*pos->counterMoveHistory)[moved_piece(move)][to_sq(move)];

    // Make and search the move
    do_move(pos, move, givesCheck);
#if PvNode
    value =  givesCheck
           ? -qsearch_PV_true(pos, ss+1, -beta, -alpha, depth - ONE_PLY)
           : -qsearch_PV_false(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
#else
    value =  givesCheck
           ? -qsearch_NonPV_true(pos, ss+1, -beta, depth - ONE_PLY)
           : -qsearch_NonPV_false(pos, ss+1, -beta, depth - ONE_PLY);
#endif
    undo_move(pos, move);

    assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);

    // Check for a new best move
    if (value > bestValue) {
      bestValue = value;

      if (value > alpha) {
        bestMove = move;

        if (PvNode) // Update pv even in fail-high case
          update_pv(ss->pv, move, (ss+1)->pv);

        if (PvNode && value < beta) // Update alpha here!
          alpha = value;
        else
          break; // Fail high
      }
    }
  }

  // All legal moves have been searched. A special case: If we're in check
  // and no legal moves were found, it is checkmate.
  if (InCheck && bestValue == -VALUE_INFINITE)
    return mated_in(ss->ply); // Plies to mate from the root

  tte_save(tte, posKey, value_to_tt(bestValue, ss->ply), ttPv,
           bestValue >= beta ? BOUND_LOWER :
           PvNode && bestValue > oldAlpha  ? BOUND_EXACT : BOUND_UPPER,
           ttDepth, bestMove, ss->staticEval, tt_generation());

  assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);

  return bestValue;
}