Beispiel #1
0
  void init() {

    Weights[Mobility]       = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]);
    Weights[PassedPawns]    = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
    Weights[Space]          = weight_option("Space", "Space", WeightsInternal[Space]);
    Weights[KingDangerUs]   = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
    Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);

    // King safety is asymmetrical. Our king danger level is weighted by
    // "Cowardice" UCI parameter, instead the opponent one by "Aggressiveness".
    // If running in analysis mode, make sure we use symmetrical king safety. We
    // do this by replacing both Weights[kingDangerUs] and Weights[kingDangerThem]
    // by their average.
    if (Options["UCI_AnalyseMode"])
        Weights[KingDangerUs] = Weights[KingDangerThem] = (Weights[KingDangerUs] + Weights[KingDangerThem]) / 2;

    const int MaxSlope = 30;
    const int Peak = 1280;

    for (int t = 0, i = 1; i < 100; i++)
    {
        t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));

        KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
        KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
    }

    if (Options["UCI_AnalyseMode"])
        ContemptFactor = VALUE_ZERO;
    else
        ContemptFactor = Options["Contempt Factor"] * PawnValueMg / 100;
  }
Score Entry::do_king_safety(const Position& pos, Square ksq) {

  kingSquares[Us] = ksq;
  castlingRights[Us] = pos.can_castle(Us);
  int minKingPawnDistance = 0;
#ifdef THREECHECK
  CheckCount checks = pos.is_three_check() ? pos.checks_given(~Us) : CHECKS_0;
#endif

  Bitboard pawns = pos.pieces(Us, PAWN);
  if (pawns)
      while (!(DistanceRingBB[ksq][minKingPawnDistance++] & pawns)) {}

  Value bonus = shelter_storm<Us>(pos, ksq);

  // If we can castle use the bonus after the castling if it is bigger
  if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
      bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));

  if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
      bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));

#ifdef THREECHECK
  // Decrease score when checks have been taken
  return make_score(bonus, (-16 * minKingPawnDistance) + (-2 * checks));
#else
  return make_score(bonus, -16 * minKingPawnDistance);
#endif
}
Beispiel #3
0
  void init() {

    Weights[Mobility]       = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]);
    Weights[PassedPawns]    = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
    Weights[Space]          = weight_option("Space", "Space", WeightsInternal[Space]);
    Weights[KingDangerUs]   = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
    Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);

    const int MaxSlope = 30;
    const int Peak = 1280;

    for (int t = 0, i = 1; i < 100; i++)
    {
        t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope));

        KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
        KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
    }
  }
Beispiel #4
0
  void init() {

    Weights[Mobility]       = weight_option("Mobility (Midgame)", "Mobility (Endgame)", WeightsInternal[Mobility]);
    Weights[PawnStructure]  = weight_option("Pawn Structure (Midgame)", "Pawn Structure (Endgame)", WeightsInternal[PawnStructure]);
    Weights[PassedPawns]    = weight_option("Passed Pawns (Midgame)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]);
    Weights[Space]          = weight_option("Space", "Space", WeightsInternal[Space]);
    Weights[KingDangerUs]   = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]);
    Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]);

    const double MaxSlope = 30;
    const double Peak = 1280;

    for (int t = 0, i = 1; i < 100; ++i)
    {
        t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));

        KingDanger[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]);
        KingDanger[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]);
    }
  }
Beispiel #5
0
void init() {

    const int bonusByFile[] = { 1, 3, 3, 4, 4, 3, 3, 1 };

    for (Rank r = RANK_1; r < RANK_8; ++r)
        for (File f = FILE_A; f <= FILE_H; ++f)
        {
            int bonus = r * (r - 1) * (r - 2) + bonusByFile[f] * (r / 2 + 1);
            Connected[f][r] = make_score(bonus, bonus);
        }
}
Beispiel #6
0
  void init() {

    const double MaxSlope = 30;
    const double Peak = 1280;

    for (int t = 0, i = 1; i < 100; ++i)
    {
        t = int(std::min(Peak, std::min(0.4 * i * i, t + MaxSlope)));
        KingDanger[i] = apply_weight(make_score(t, 0), Weights[KingSafety]);
    }
  }
Beispiel #7
0
  void init() {

    const int MaxSlope = 8700;
    const int Peak = 1280000;
    int t = 0;

    for (int i = 0; i < 400; ++i)
    {
        t = std::min(Peak, std::min(i * i * 27, t + MaxSlope));
        KingDanger[i] = make_score(t / 1000, 0) * Weights[KingSafety];
    }
  }
Beispiel #8
0
void init() {

  const int chainByFile[8] = { 1, 3, 3, 4, 4, 3, 3, 1 };
  int bonus;

  for (Rank r = RANK_1; r < RANK_8; ++r)
      for (File f = FILE_A; f <= FILE_H; ++f)
      {
          bonus = r * (r-1) * (r-2) + chainByFile[f] * (r/2 + 1);
          ChainMember[f][r] = make_score(bonus, bonus);
      }
}
Beispiel #9
0
  void init() {

    const double MaxSlope = 7.5;
    const double Peak = 1280;
    double t = 0.0;

    for (int i = 1; i < 400; ++i)
    {
        t = std::min(Peak, std::min(0.025 * i * i, t + MaxSlope));
        KingDanger[i] = apply_weight(make_score(int(t), 0), Weights[KingSafety]);
    }
  }
Beispiel #10
0
void Eval::init() {

  const int MaxSlope = 322;
  const int Peak = 47410;
  int t = 0;

  for (int i = 0; i < 400; ++i)
  {
      t = std::min(Peak, std::min(i * i - 16, t + MaxSlope));
      KingDanger[i] = make_score(t * 268 / 7700, 0);
  }
}
Beispiel #11
0
Score Entry::do_king_safety(const Position& pos, Square ksq) {

    kingSquares[Us] = ksq;
    castlingRights[Us] = pos.can_castle(Us);
    minKPdistance[Us] = 0;

    Bitboard pawns = pos.pieces(Us, PAWN);
    if (pawns)
        while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {}

    if (relative_rank(Us, ksq) > RANK_4)
        return make_score(0, -16 * minKPdistance[Us]);

    Value bonus = shelter_storm<Us>(pos, ksq);

    // If we can castle use the bonus after the castling if it is bigger
    if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
        bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_G1)));

    if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
        bonus = std::max(bonus, shelter_storm<Us>(pos, relative_square(Us, SQ_C1)));

    return make_score(bonus, -16 * minKPdistance[Us]);
}
Beispiel #12
0
// init() initializes piece square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
void init() {

  for (PieceType pt = PAWN; pt <= KING; ++pt)
  {
      PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
      PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];

      Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);

      for (Square s = SQ_A1; s <= SQ_H8; ++s)
      {
          int edgeDistance = file_of(s) < FILE_E ? file_of(s) : FILE_H - file_of(s);
          psq[BLACK][pt][~s] = -(psq[WHITE][pt][s] = v + Bonus[pt][rank_of(s)][edgeDistance]);
      }
  }
}
Beispiel #13
0
// init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
void init() {

  for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
  {
      PieceValue[MG][~pc] = PieceValue[MG][pc];
      PieceValue[EG][~pc] = PieceValue[EG][pc];

      Score v = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);

      for (Square s = SQ_A1; s <= SQ_H8; ++s)
      {
          File f = std::min(file_of(s), FILE_H - file_of(s));
          psq[ pc][ s] = v + Bonus[pc][rank_of(s)][f];
          psq[~pc][~s] = -psq[pc][s];
      }
  }
}
Beispiel #14
0
// init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
void init() {

  for (PieceType pt = PAWN; pt <= KING; ++pt)
  {
      PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt];
      PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt];

      Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]);

      for (Square s = SQ_A1; s <= SQ_H8; ++s)
      {

          File f = std::min(file_of(s), FILE_H - file_of(s));
          psq[WHITE][pt][ s] = v + Bonus[pt][rank_of(s)][f];
          psq[BLACK][pt][~s] = -psq[WHITE][pt][s];
      }
  }
}
Beispiel #15
0
// init() initializes piece-square tables: the white halves of the tables are
// copied from Bonus[] adding the piece value, then the black halves of the
// tables are initialized by flipping and changing the sign of the white scores.
void init() {

  for (Piece pc = W_PAWN; pc <= W_KING; ++pc)
  {
      PieceValue[MG][~pc] = PieceValue[MG][pc];
      PieceValue[EG][~pc] = PieceValue[EG][pc];

      Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);

      for (Square s = SQ_A1; s <= SQ_H8; ++s)
      {
          File f = std::min(file_of(s), ~file_of(s));
          psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
                                                      : Bonus[pc][rank_of(s)][f]);
          psq[~pc][~s] = -psq[pc][s];
      }
  }
}
Beispiel #16
0
Score Entry::do_king_safety(const Position& pos) {

  Square ksq = pos.square<KING>(Us);
  kingSquares[Us] = ksq;
  castlingRights[Us] = pos.can_castle(Us);
  int minKingPawnDistance = 0;

  Bitboard pawns = pos.pieces(Us, PAWN);
  if (pawns)
      while (!(DistanceRingBB[ksq][++minKingPawnDistance] & pawns)) {}

  Value bonus = evaluate_shelter<Us>(pos, ksq);

  // If we can castle use the bonus after the castling if it is bigger
  if (pos.can_castle(Us | KING_SIDE))
      bonus = std::max(bonus, evaluate_shelter<Us>(pos, relative_square(Us, SQ_G1)));

  if (pos.can_castle(Us | QUEEN_SIDE))
      bonus = std::max(bonus, evaluate_shelter<Us>(pos, relative_square(Us, SQ_C1)));

  return make_score(bonus, -16 * minKingPawnDistance);
}
Beispiel #17
0
void init(OptionsMap& o) {

  o["Write Debug Log"]             = Option(false, on_logger);
  o["Write Search Log"]            = Option(false);
  o["Search Log Filename"]         = Option("SearchLog.txt");
  o["Book File"]                   = Option("book.bin");
  o["Best Book Move"]              = Option(false);
  o["Contempt Factor"]             = Option(0, -50,  50);
  o["Mobility (Midgame)"]          = Option(100, 0, 200, on_eval);
  o["Mobility (Endgame)"]          = Option(100, 0, 200, on_eval);
  o["Pawn Structure (Midgame)"]    = Option(100, 0, 200, on_eval);
  o["Pawn Structure (Endgame)"]    = Option(100, 0, 200, on_eval);
  o["Passed Pawns (Midgame)"]      = Option(100, 0, 200, on_eval);
  o["Passed Pawns (Endgame)"]      = Option(100, 0, 200, on_eval);
  o["Space"]                       = Option(100, 0, 200, on_eval);
  o["Aggressiveness"]              = Option(100, 0, 200, on_eval);
  o["Cowardice"]                   = Option(100, 0, 200, on_eval);
  o["Min Split Depth"]             = Option(0, 0, 12, on_threads);
  o["Max Threads per Split Point"] = Option(5, 4,  8, on_threads);
  o["Threads"]                     = Option(1, 1, MAX_THREADS, on_threads);
  o["Idle Threads Sleep"]          = Option(true);
  o["Hash"]                        = Option(128, 1, 8192, on_hash_size);
  o["Clear Hash"]                  = Option(on_clear_hash);
  o["Ponder"]                      = Option(true);
  o["OwnBook"]                     = Option(false);
  o["MultiPV"]                     = Option(1, 1, 500);
  o["Skill Level"]                 = Option(20, 0, 20);
  o["Emergency Move Horizon"]      = Option(40, 0, 50);
  o["Emergency Base Time"]         = Option(50, 0, 30000);
  o["Emergency Move Time"]         = Option(20, 0, 5000);
  o["Minimum Thinking Time"]       = Option(20, 0, 5000);
  o["Slow Mover"]                  = Option(50, 10, 1000);
  o["UCI_Chess960"]                = Option(false);
  o["UCI_AnalyseMode"]             = Option(false, on_eval);
  o["Piece Structure"]             = Option(100, 0, 200, on_eval);

  typedef Value V;
#define S(mg, eg) make_score(mg, eg)

  //用于产生tuner文件
  //Log log;

  //log<<"name,   init,  max,  min,  c_end,  r_end,  elod"<<std::endl;

  //PAWN, BISHOP, ADVISOR, KNIGHT, CANNON, ROOK, KING
  const Score MobilityBonus[][32] = {
	  {}, {},//Pawn
	  { S( 0, 0), S( 0,  0 ), S( 0,  0), S(0, 0),   S(0, 0)},// Bishops
	  { S( 0, 0), S( 0,  0 ), S( 0,  0), S(0, 0),   S(0, 0)},// Advisor
	  { S(-35,-30), S(-20,-20), S(-20,-20), S( 0,  0), S(0, 0), S(15, 10),S( 15, 10), S( 25, 12), S(25, 12) },//knight
	  { S( -10, -10), S( 2,  4), S( 4,  4), S(6, 6), S(8, 8),S(10, 10),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12),S(12, 12)},// Cannon
	  { S(-20,-20), S(-18,-18), S(-16,-16), S( -10,-10), S( -8,-8), S(-4,-4),S( 0, 0), S( 4, 2), S(8, 4), S(12,6), S(16,8), S(20,10),S( 24,12), S( 24,12), S(24,12), S(24,12), S(24,12), S(24,12)}, // Rooks 
  };
  for (int pt1 = KNIGHT; pt1 <= ROOK; ++pt1)
  {
	  for (int c = 0; c <= 17; ++c)
	  {

		  int min = -40;
		  int max = 40;

		  if (pt1 == KNIGHT)
		  {
              min = -50;
			  max = 50;
		  }
		  if (pt1 == CANNON)
		  {
			  min = 0;
			  max = 20;
		  }
		  if (pt1 == ROOK)
		  {
			  min = -30;
			  max = 30;
		  }

		  int m = (int)mg_value(MobilityBonus[pt1][c]);
		  int e = (int)eg_value(MobilityBonus[pt1][c]);


		  char buf[256] = {0};
		  char text[1024]={0};

		  sprintf(buf, "MobilityBonusM[%d][%d]",pt1,c);
		  o[buf] = Option(m, min, max, on_eval_variables);

		  //sprintf(text, "%s,%d,%d,%d,%d,%d,%d",buf, m, max,min,8, 1, 0);
		  //log<<text<<std::endl;

		  //------

		  sprintf(buf, "MobilityBonusE[%d][%d]",pt1,c);
		  o[buf] = Option(e, min, max, on_eval_variables);		  

		  //sprintf(text, "%s,%d,%d,%d,%d,%d,%d",buf, e, max,min,8, 1, 0);
		  //log<<text<<std::endl;

	  }
  }



  const Score RookPin          = make_score(26, 31);
  const Score CannonPin        = make_score(16, 11);

  const Score RookOnPawn       = make_score(10, 28);
  const Score RookOpenFile     = make_score(53, 21);

  const Score RookPinRook      = make_score(20, 20);

  const Score CannonPinRook    = make_score(10, 10);
  const Score CannonPinKnight  = make_score(10, 10);
  const Score CannonPinBishop  = make_score(5, 3);

  const Score KnightLegPawn    = make_score(16,  0);

  {
	  char buf[256] = {0};
	  char text[1024]={0};

	  int min = -50;
	  int max = 50;

	  int m = 0;
	  int e = 0;

#define GEN_CODE(namem,namee, v, minv, maxv) {\
	  m = (int)mg_value((v));\
	  e = (int)eg_value((v));\
      min = minv;\
      max = maxv;\
	  o[namem]= Option(m, min, max, on_eval_variables);\
	  o[namee]= Option(e, min, max, on_eval_variables);\
	  }
	  //sprintf(text, "%s,%d,%d,%d,%d,%d,%d",(namem), m, max,min,8, 1, 0);\
	  //log<<text<<std::endl;\
	  //sprintf(text, "%s,%d,%d,%d,%d,%d,%d",(namee), e, max,min,8, 1, 0);\
	  //log<<text<<std::endl;\
	  }

	  GEN_CODE("RookPinM","RookPinE", RookPin, 0, 50);
	  GEN_CODE("CannonPinM","CannonPinE", CannonPin, 0, 50);
	  GEN_CODE("RookOnPawnM","RookOnPawnE", RookOnPawn, 0, 50);
	  GEN_CODE("RookOpenFileM","RookOpenFileE", RookOpenFile, 0, 50);
	  GEN_CODE("RookPinRookM","RookPinRookE", RookPinRook, 0, 50);
	  GEN_CODE("CannonPinRookM","CannonPinRookE", CannonPinRook, 0, 50);
	  GEN_CODE("CannonPinKnightM","CannonPinKnightE", CannonPinKnight, 0, 50);
	  GEN_CODE("CannonPinBishopM","CannonPinBishopE", CannonPinBishop, 0, 50);
	  GEN_CODE("KnightLegPawnM","KnightLegPawnE", KnightLegPawn, 0, 50);


  }
Beispiel #18
0
void thread_search(Pos *pos)
{
  Value bestValue, alpha, beta, delta;
  Move pv[MAX_PLY + 1];
  Move lastBestMove = 0;
  Depth lastBestMoveDepth = DEPTH_ZERO;
  double timeReduction = 1.0;

  Stack *ss = pos->st; // At least the seventh element of the allocated array.
  for (int i = -7; i < 3; i++)
    memset(SStackBegin(ss[i]), 0, SStackSize);
  (ss-1)->endMoves = pos->moveList;

  for (int i = -7; i < 0; i++)
    ss[i].history = &(*pos->counterMoveHistory)[0][0]; // Use as sentinel

  for (int i = 0; i <= MAX_PLY; i++)
    ss[i].ply = i;
  ss->pv = pv;

  bestValue = delta = alpha = -VALUE_INFINITE;
  beta = VALUE_INFINITE;
  pos->completedDepth = DEPTH_ZERO;

  if (pos->threadIdx == 0)
    mainThread.bestMoveChanges = 0;

  int multiPV = option_value(OPT_MULTI_PV);
#if 0
  Skill skill(option_value(OPT_SKILL_LEVEL));

  // When playing with strength handicap enable MultiPV search that we will
  // use behind the scenes to retrieve a set of possible moves.
  if (skill.enabled())
      multiPV = std::max(multiPV, (size_t)4);
#endif

  RootMoves *rm = pos->rootMoves;
  multiPV = min(multiPV, rm->size);

  // Iterative deepening loop until requested to stop or the target depth
  // is reached.
  while (   (pos->rootDepth += ONE_PLY) < DEPTH_MAX
         && !Signals.stop
         && !(   Limits.depth
              && pos->threadIdx == 0
              && pos->rootDepth / ONE_PLY > Limits.depth))
  {
    // Age out PV variability metric
    if (pos->threadIdx == 0)
      mainThread.bestMoveChanges *= 0.517;

    // Save the last iteration's scores before first PV line is searched and
    // all the move scores except the (new) PV are set to -VALUE_INFINITE.
    for (int idx = 0; idx < rm->size; idx++)
      rm->move[idx].previousScore = rm->move[idx].score;

    pos->contempt = pos_stm() == WHITE ?  make_score(base_ct, base_ct / 2)
                                       : -make_score(base_ct, base_ct / 2);

    int pvFirst = 0, pvLast = 0;

    // MultiPV loop. We perform a full root search for each PV line
    for (int pvIdx = 0; pvIdx < multiPV && !Signals.stop; pvIdx++) {
      pos->pvIdx = pvIdx;
      if (pvIdx == pvLast) {
        pvFirst = pvLast;
        for (pvLast++; pvLast < rm->size; pvLast++)
          if (rm->move[pvLast].tbRank != rm->move[pvFirst].tbRank)
            break;
        pos->pvLast = pvLast;
      }

      pos->selDepth = 0;

      // Skip the search if we have a mate value from DTM tables.
      if (abs(rm->move[pvIdx].tbRank) > 1000) {
        bestValue = rm->move[pvIdx].score = rm->move[pvIdx].tbScore;
        alpha = -VALUE_INFINITE;
        beta = VALUE_INFINITE;
        goto skip_search;
      }

      // Reset aspiration window starting size
      if (pos->rootDepth >= 5 * ONE_PLY) {
        Value previousScore = rm->move[pvIdx].previousScore;
        delta = 20;
        alpha = max(previousScore - delta, -VALUE_INFINITE);
        beta  = min(previousScore + delta,  VALUE_INFINITE);

        // Adjust contempt based on root move's previousScore
        int ct = base_ct + 88 * previousScore / (abs(previousScore) + 200);
        pos->contempt = pos_stm() == WHITE ?  make_score(ct, ct / 2)
                                           : -make_score(ct, ct / 2);
      }

      // Start with a small aspiration window and, in the case of a fail
      // high/low, re-search with a bigger window until we're not failing
      // high/low anymore.
      int failedHighCnt = 0;
      while (true) {
        Depth adjustedDepth = max(ONE_PLY, pos->rootDepth - failedHighCnt * ONE_PLY);
        bestValue = search_PV(pos, ss, alpha, beta, adjustedDepth);

        // Bring the best move to the front. It is critical that sorting
        // is done with a stable algorithm because all the values but the
        // first and eventually the new best one are set to -VALUE_INFINITE
        // and we want to keep the same order for all the moves except the
        // new PV that goes to the front. Note that in case of MultiPV
        // search the already searched PV lines are preserved.
        stable_sort(&rm->move[pvIdx], pvLast - pvIdx);

        // If search has been stopped, we break immediately. Sorting and
        // writing PV back to TT is safe because RootMoves is still
        // valid, although it refers to the previous iteration.
        if (Signals.stop)
          break;

        // When failing high/low give some update (without cluttering
        // the UI) before a re-search.
        if (   pos->threadIdx == 0
            && multiPV == 1
            && (bestValue <= alpha || bestValue >= beta)
            && time_elapsed() > 3000)
          uci_print_pv(pos, pos->rootDepth, alpha, beta);

        // In case of failing low/high increase aspiration window and
        // re-search, otherwise exit the loop.
        if (bestValue <= alpha) {
          beta = (alpha + beta) / 2;
          alpha = max(bestValue - delta, -VALUE_INFINITE);

          if (pos->threadIdx == 0) {
            failedHighCnt = 0;
            Signals.stopOnPonderhit = 0;
          }
        } else if (bestValue >= beta) {
          beta = min(bestValue + delta, VALUE_INFINITE);
          if (pos->threadIdx == 0)
            failedHighCnt++;
        } else
          break;

        delta += delta / 4 + 5;

        assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
      }

      // Sort the PV lines searched so far and update the GUI
      stable_sort(&rm->move[pvFirst], pvIdx - pvFirst + 1);

skip_search:
      if (    pos->threadIdx == 0
          && (Signals.stop || pvIdx + 1 == multiPV || time_elapsed() > 3000))
        uci_print_pv(pos, pos->rootDepth, alpha, beta);
    }

    if (!Signals.stop)
      pos->completedDepth = pos->rootDepth;

    if (rm->move[0].pv[0] != lastBestMove) {
      lastBestMove = rm->move[0].pv[0];
      lastBestMoveDepth = pos->rootDepth;
    }

    // Have we found a "mate in x"?
    if (   Limits.mate
        && bestValue >= VALUE_MATE_IN_MAX_PLY
        && VALUE_MATE - bestValue <= 2 * Limits.mate)
      Signals.stop = 1;

    if (pos->threadIdx != 0)
      continue;

#if 0
    // If skill level is enabled and time is up, pick a sub-optimal best move
    if (skill.enabled() && skill.time_to_pick(thread->rootDepth))
      skill.pick_best(multiPV);
#endif

    // Do we have time for the next iteration? Can we stop searching now?
    if (    use_time_management()
        && !Signals.stop
        && !Signals.stopOnPonderhit) {
      // Stop the search if only one legal move is available, or if all
      // of the available time has been used.
      double fallingEval = (306 + 9 * (mainThread.previousScore - bestValue)) / 581.0;
      fallingEval = max(0.5, min(1.5, fallingEval));

      // If the best move is stable over several iterations, reduce time
      // accordingly
      timeReduction =  lastBestMoveDepth + 10 * ONE_PLY < pos->completedDepth
                     ? 1.95 : 1.0;
      double reduction = pow(mainThread.previousTimeReduction, 0.528) / timeReduction;

      // Use part of the gained time from a previous stable move for this move
      double bestMoveInstability = 1.0 + mainThread.bestMoveChanges;

      if (   rm->size == 1
          || time_elapsed() > time_optimum() * fallingEval * reduction * bestMoveInstability)
      {
        // If we are allowed to ponder do not stop the search now but
        // keep pondering until the GUI sends "ponderhit" or "stop".
        if (Limits.ponder)
          Signals.stopOnPonderhit = 1;
        else
          Signals.stop = 1;
      }
    }
  }

  if (pos->threadIdx != 0)
    return;

  mainThread.previousTimeReduction = timeReduction;

#if 0
  // If skill level is enabled, swap best PV line with the sub-optimal one
  if (skill.enabled())
    std::swap(rm[0], *std::find(rm.begin(),
              rm.end(), skill.best_move(multiPV)));
#endif
}
Beispiel #19
0
Entry* probe(const Position& pos, Table& entries, Endgames& endgames) {

  Key key = pos.material_key();
  Entry* e = entries[key];

  // If e->key matches the position's material hash key, it means that we
  // have analysed this material configuration before, and we can simply
  // return the information we found the last time instead of recomputing it.
  if (e->key == key)
      return e;

  std::memset(e, 0, sizeof(Entry));
  e->key = key;
  e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;
  e->gamePhase = game_phase(pos);

  // Let's look if we have a specialized evaluation function for this particular
  // material configuration. Firstly we look for a fixed configuration one, then
  // for a generic one if the previous search failed.
  if (endgames.probe(key, e->evaluationFunction))
      return e;

  if (is_KXK<WHITE>(pos))
  {
      e->evaluationFunction = &EvaluateKXK[WHITE];
      return e;
  }

  if (is_KXK<BLACK>(pos))
  {
      e->evaluationFunction = &EvaluateKXK[BLACK];
      return e;
  }

  if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN))
  {
      // Minor piece endgame with at least one minor piece per side and
      // no pawns. Note that the case KmmK is already handled by KXK.
      assert((pos.pieces(WHITE, KNIGHT) | pos.pieces(WHITE, BISHOP)));
      assert((pos.pieces(BLACK, KNIGHT) | pos.pieces(BLACK, BISHOP)));

      if (   pos.count<BISHOP>(WHITE) + pos.count<KNIGHT>(WHITE) <= 2
          && pos.count<BISHOP>(BLACK) + pos.count<KNIGHT>(BLACK) <= 2)
      {
          e->evaluationFunction = &EvaluateKmmKm[pos.side_to_move()];
          return e;
      }
  }

  // OK, we didn't find any special evaluation function for the current
  // material configuration. Is there a suitable scaling function?
  //
  // We face problems when there are several conflicting applicable
  // scaling functions and we need to decide which one to use.
  EndgameBase<ScaleFactor>* sf;

  if (endgames.probe(key, sf))
  {
      e->scalingFunction[sf->color()] = sf;
      return e;
  }

  // Generic scaling functions that refer to more then one material
  // distribution. They should be probed after the specialized ones.
  // Note that these ones don't return after setting the function.
  if (is_KBPsKs<WHITE>(pos))
      e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];

  if (is_KBPsKs<BLACK>(pos))
      e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];

  if (is_KQKRPs<WHITE>(pos))
      e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];

  else if (is_KQKRPs<BLACK>(pos))
      e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];

  Value npm_w = pos.non_pawn_material(WHITE);
  Value npm_b = pos.non_pawn_material(BLACK);

  if (npm_w + npm_b == VALUE_ZERO)
  {
      if (!pos.count<PAWN>(BLACK))
      {
          assert(pos.count<PAWN>(WHITE) >= 2);
          e->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
      }
      else if (!pos.count<PAWN>(WHITE))
      {
          assert(pos.count<PAWN>(BLACK) >= 2);
          e->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
      }
      else if (pos.count<PAWN>(WHITE) == 1 && pos.count<PAWN>(BLACK) == 1)
      {
          // This is a special case because we set scaling functions
          // for both colors instead of only one.
          e->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
          e->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
      }
  }

  // No pawns makes it difficult to win, even with a material advantage. This
  // catches some trivial draws like KK, KBK and KNK
  if (!pos.count<PAWN>(WHITE) && npm_w - npm_b <= BishopValueMg)
  {
      e->factor[WHITE] = (uint8_t)
      (npm_w == npm_b || npm_w < RookValueMg ? 0 : NoPawnsSF[std::min(pos.count<BISHOP>(WHITE), 2)]);
  }

  if (!pos.count<PAWN>(BLACK) && npm_b - npm_w <= BishopValueMg)
  {
      e->factor[BLACK] = (uint8_t)
      (npm_w == npm_b || npm_b < RookValueMg ? 0 : NoPawnsSF[std::min(pos.count<BISHOP>(BLACK), 2)]);
  }

  // Compute the space weight
  if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg)
  {
      int minorPieceCount =  pos.count<KNIGHT>(WHITE) + pos.count<BISHOP>(WHITE)
                           + pos.count<KNIGHT>(BLACK) + pos.count<BISHOP>(BLACK);

      e->spaceWeight = make_score(minorPieceCount * minorPieceCount, 0);
  }

  // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
  // for the bishop pair "extended piece", which allows us to be more flexible
  // in defining bishop pair bonuses.
  const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = {
  { pos.count<BISHOP>(WHITE) > 1, pos.count<PAWN>(WHITE), pos.count<KNIGHT>(WHITE),
    pos.count<BISHOP>(WHITE)    , pos.count<ROOK>(WHITE), pos.count<QUEEN >(WHITE) },
  { pos.count<BISHOP>(BLACK) > 1, pos.count<PAWN>(BLACK), pos.count<KNIGHT>(BLACK),
    pos.count<BISHOP>(BLACK)    , pos.count<ROOK>(BLACK), pos.count<QUEEN >(BLACK) } };

  e->value = (int16_t)((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);

  // Having pawn(s) and ahead at least a piece (npm) ==> Exchange Pieces not Pawns !
  if (npm_w >= (npm_b + 3*PawnValueMg) && pos.count<PAWN>(WHITE) && pos.count<PAWN>(WHITE) > pos.count<PAWN>(BLACK) - 3)
    e->value += (int16_t)((imbalanceWinning<WHITE>(pieceCount) - imbalanceLoosing<BLACK>(pieceCount)) / 16);

  if (npm_b >= (npm_w + 3*PawnValueMg) && pos.count<PAWN>(BLACK) && pos.count<PAWN>(BLACK) > pos.count<PAWN>(WHITE) - 3)
    e->value += (int16_t)((imbalanceWinning<BLACK>(pieceCount) - imbalanceLoosing<WHITE>(pieceCount)) / 16);

  return e;
}