예제 #1
0
파일: search.c 프로젝트: phenri/Claudia
static int Quiescent(BOARD *board, int alpha, int beta, int root, CONTROL *control, MOVE killers[][2])
{
    int nmoves, nlegal = 0;
    int val;
    MOVE moves[MAXMOVES];
    
    if(!control->ponder && clock() - control->init_time >= control->max_time*CPMS){
        control->stop = 1;
    }
    
    val = LazyEval(board);
    if(val-LAZYBETA >= beta) return beta;
    if(val+LAZYALPHA < alpha) return alpha;

    val = StaticEval(board);
    UpdateTable(&hash_table, board->zobrist_key, val, 0, 0, HASH_EXACT);

    if (val >= beta) return beta;
    if (val > alpha) alpha = val;
    
    nmoves = CaptureGen(board, moves);
    nmoves = FilterWinning(board, moves, nmoves); 
//   nmoves = SortMoves(board, moves, nmoves, killers[root]);

    for(int i = 0; i < nmoves; i++){
        control->node_count++;
        MakeMove(board, &moves[i]);
        if(!LeftInCheck(board)){
            nlegal++;
            val = -Quiescent(board, -beta, -alpha, root+1, control, killers);
            Takeback(board, moves[i]);
            if(val >= beta){
                return beta;
            }
            if(val > alpha){
                alpha = val;
            }
        }else Takeback(board, moves[i]);
    }
    return alpha;
}
예제 #2
0
파일: search.c 프로젝트: raimarHD/lcec
static int AlphaBeta (BOARD *board, int depth, int alpha, int beta,
               int root, CONTROL *control, char skip_null, MOVE killers[][2])
{
  int nmoves, good = 0, nlegal = 0;
  MOVE moves[MAXMOVES];
  MOVE best_move = 0;
  char str_mov[MVLEN];
  int val = ERRORVALUE;
  char hash_flag = HASH_ALPHA;
  
  int in_check = InCheck(board, 0);

  if (root > control->seldepth) control->seldepth = root;

  if (depth > 0 || in_check) {
    if (root > 0) {
      val = GetHashEval(&hash_table, board->zobrist_key, depth, alpha, beta);
      if (val != ERRORVALUE) return val;
    }
    if (depth > 2 && !in_check) {    
      if (!skip_null && board->piece_material[board->white_to_move] != 0) {
        MOVE null_mv = NULL_MOVE;
        MakeMove(board, &null_mv);
        val = -AlphaBeta(board, depth-3, -beta, -beta+1, root+1, control, 1, killers);
        Takeback(board, null_mv);
        if (val >= beta) return beta;
      }
    }
    nmoves = MoveGen(board, moves, 1);
    good = SortMoves(board, moves, nmoves, killers[root]);
  } else {
    if (!control->ponder && clock() - control->init_time >= control->max_time*CPMS) {
      control->stop = 1;
    }
    val = LazyEval(board);
    if (val-LAZYBETA >= beta) return beta;
    if (val+LAZYALPHA < alpha) return alpha;

    val = StaticEval(board);
    UpdateTable(&hash_table, board->zobrist_key, val, 0, 0, HASH_EXACT);
    if (val >= beta) return beta;
    if (val > alpha) alpha = val;
    
    nmoves = CaptureGen(board, moves);
    nmoves = FilterWinning(board, moves, nmoves);
  }
        
  for (int i = 0; i < nmoves; i++) {
    MakeMove(board, &moves[i]);
    control->node_count++;
    if (LeftInCheck(board)) {
      Takeback(board, moves[i]);
      continue;
    }
    if (root == 0) {
      if (!control->best_move) control->best_move = moves[i];    /* Better than nothing. */
      if (depth > 6 && !control->ponder) {
        MoveToAlgeb(moves[i], str_mov);
        printf("info depth %i seldepth %i hashfull %i currmove %s currmovenumber %i\n",
               depth, control->seldepth, hash_table.full/(hash_table.size/1000), str_mov, i+1);
      }
    }
    nlegal++;
    val = AssessDraw(board, control->contempt);
    if (val == ERRORVALUE) {
      int ext = 0; //InCheck(board, 0) ? 1 : 0;
      if (best_move) {
        int LMR = (depth > 2 && !in_check && i > good &&
                   !CAPTMASK(moves[i]) && !InCheck(board, 0)) ? 1 : 0;
        val = -AlphaBeta(board, depth+ext-LMR-1, -alpha-1, -alpha, root+1, control, 0, killers);
        if (val > alpha) {
          val = -AlphaBeta(board, depth+ext-1, -alpha-1, -alpha, root+1, control, 0, killers);
          if (val > alpha && val < beta) {
            val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers);
          }
        }
      } else {
        val = -AlphaBeta(board, depth+ext-1, -beta, -alpha, root+1, control, 0, killers);
      }
    }
    Takeback(board, moves[i]);
    if (!control->ponder && control->stop) return alpha;
    if (val >= beta) {
      UpdateTable(&hash_table, board->zobrist_key, val, moves[i], depth, HASH_BETA);
      if (CAPTMASK(moves[i]) == 0 && killers[root][0] != moves[i] && killers[root][1] != moves[i]) {
        killers[root][1] = killers[root][0];
        killers[root][0] = moves[i];
      }
      return beta;
    }
    if (val > alpha) {
      alpha = val;
      hash_flag = HASH_EXACT;
      best_move = moves[i];
      if (root == 0) control->best_move = best_move;
    }
    if (root == 0 && ((clock() - control->init_time) > control->wish_time*CPMS)) {
    /* if short of time, don't search anymore after current move */
      control->stop = 1;
      return alpha;
    }
  }
  if (nlegal == 0) {
    if (in_check) {
      /*UpdateTable(&hash_table, board->zobrist_key, MATE_VALUE+root, 0, depth, HASH_EXACT, hash_table.entries);*/
      return MATE_VALUE;
    } else if (depth > 0) {
      /*UpdateTable(&hash_table, board->zobrist_key, DRAW_VALUE, 0, depth, HASH_EXACT, hash_table.entries);*/
      return DRAW_VALUE;    /*Stalemate*/
    }
  } else {
    UpdateTable(&hash_table, board->zobrist_key, alpha, best_move, depth, hash_flag);
  }
  return alpha;
}
예제 #3
0
/* Evaluate the current board position for the side stored in the board
 * structure. Score for white.  (Score for black = -1* this.)  We also pass the values
 * of alpha and beta to this routine on the expectation that we might be able to get a
 * cutoff if the score is particularly high or low without having to do the time consuming
 * part of the eval().  */
int EvalMain(Board *B, int alpha, int beta) {
  int sq,p,npw=0,tpts=B->WPts+B->BPts,sq2,def, score=0;
  int *SpDef, *SpWon, lazyscore;
  BITBOARD pieces = B->All;
  BOOL one_sided;
#ifdef DEBUG_EVAL
  int control = 0, oldscore = 0, contestcount = 0;
#endif
  
  /* Check for a drawn position */
  if (IsDrawnMaterial(B))
    return ((Current_Board.side == WHITE) ? (DRAW_SCORE) : -(DRAW_SCORE));
  
  /* Check if the game is theoretically won/lost */
  score = IsWonGame(B);
#ifdef DEBUG_EVAL
  if (score != 0) fprintf(stdout,"\nPosition Theoretically Won : %d\n\n",score);
#endif

  /* Check to see if we can just cutoff here - this score is so good that
   * we needn't bother working it out exactly - it's going to cause a cutoff. 
   * We have to be very careful because the score difference gained by doing
   * a proper eval here might be huge, therefore we only cutoff if this
   * position is theoretically won, and beta isn't, or it is theoretically
   * lost and alpha isn't. We can't just use standard futility cutoffs like
   * we do below, because in theoretically won positions, the score returned
   * by LazyEval() will almost always be much larger than EVAL_FUTILITY. */
  if (USE_EVAL_SC && score!=0 && ((score > 0 && beta<T_WIN_BOUND) ||
                                  (score < 0 && alpha>-(T_WIN_BOUND)))) {
    EvalCuts++;
#ifdef DEBUG_EVAL
    fprintf(stdout,"Early Cut [1] %d  (A=%d,B=%d)\n",score,alpha,beta);
#endif
    return score;
  }
  
   /* Get a lazy score evaluation
    * (material score & simple positional terms plus passed pawns) */
  lazyscore = LazyEval(B) + score;

   /* Check to see if we can just cutoff here.  The expectation is that the LazyEval
    * is alway within EVAL_FUTILITY of the true score.  Of course this isn't always
    * true, but we hope that it is true most of the time. */
  if (USE_EVAL_SC && (lazyscore > (beta+EVAL_FUTILITY) || lazyscore < (alpha-EVAL_FUTILITY))) {
    EvalCuts++;
#ifdef DEBUG_EVAL
    fprintf(stdout,"Early Cut [2] %d  (A=%d,B=%d)\n",lazyscore,alpha,beta);
#endif
    return lazyscore;
  } 

   /* We didn't get a cutoff so we have to be more careful and evaluate the board properly.
    * Begin with the LazyEval() score we obtained BEFORE any possible truncation due to lack
    * of mating material (we don't want to do this twice!). */
  score += prematscore;

#ifdef DEBUG_EVAL
  fprintf(stdout,"\nFull Eval\n---------\n");
#endif

   /* Generate arrays storing how many times each side attacks each square on the board.
    * This takes quite some time, but it is worth the effort! */
  GenerateAttacks(B);

   /* Now loop through all the pieces on the board and sum their contributions.
    * Also include the contributions of the empty spaces, measuring board
    * domination and territorial control.
    * There is the specialised version for the endgame below. */
  if (B->Gamestage < Endgame) {

     /* Work out how much square possession is worth */
    SpWon = SpaceWon[B->Gamestage];
    SpDef = SpaceDefended[B->Gamestage];
     /* Loop through the board */
    for (sq=0;sq<64;sq++) {
      p = B->pieces[sq];
      
#ifdef DEBUG_EVAL
      fprintf(stdout,"Square %c%d  [",File(sq)+97,8-Rank(sq));
      PrintPiece(p);
      fprintf(stdout,"] : ");
#endif
      switch(p) {
        /* White Piece */
      case (wpawn)  : score += TactPawn(sq,B,WHITE);
                      npw += SquareColour[sq]; break;
      case (wrook)  : score += TactRook(sq,B,WHITE); break;
      case (wknight): score += TactKnight(sq,B,WHITE); break;
      case (wbishop): score += TactBishop(sq,B,WHITE); break;
      case (wqueen) : score += TactQueen(sq,B,WHITE); break;
      case (wking)  : score += TactKing(sq,B,WHITE); break;
        /* Black Piece */
      case (bpawn)  : score -= TactPawn(sq,B,BLACK);
                      npw += SquareColour[sq]; break;
      case (brook)  : score -= TactRook(sq,B,BLACK); break;
      case (bknight): score -= TactKnight(sq,B,BLACK); break;
      case (bbishop): score -= TactBishop(sq,B,BLACK); break;
      case (bqueen) : score -= TactQueen(sq,B,BLACK); break;
      case (bking)  : score -= TactKing(sq,B,BLACK); break;
        /* Empty square - reward for possession by one side */
      case (empty)  : sq2=ConvertSq[sq];
#ifdef DEBUG_EVAL
        oldscore = score;
#endif
	    /* If only one side is attacking a square, then it is won
	     * by that side.  Otherwise it can only be defended. */
        one_sided = (!(B->WAttacks[sq2]) || !(B->BAttacks[sq2]));
        def = B->WAttacks[sq2] - B->BAttacks[sq2];
        if (one_sided) {
          if (def>0) score += SpWon[sq];
          else if (def<0) score -= SpWon[Flip[sq]];
        }
        else {
		      /* We have no clear winner, so evaluate the ownership of the square (slow!!) */
          def = EvaluateOwnership(B,sq);
          if (def > 0) score += SpDef[sq];
          else if (def < 0) score -= SpDef[Flip[sq]];
#ifdef DEBUG_EVAL
		  contestcount++;
#endif
        }
        
#ifdef DEBUG_EVAL
        control += score-oldscore;
        fprintf(stdout,"%d", score-oldscore);
#endif
        break;
      }
#ifdef DEBUG_EVAL
      fprintf(stdout,"\n");
#endif
    }
  }
    /* If we're in the endgame then use this simpler version */
  else {
     /* Loop through the pieces */
    while (pieces) {     
      sq = FirstPiece(pieces);
      p = B->pieces[sq];
#ifdef DEBUG_EVAL
      fprintf(stdout,"Square %c%d  [",File(sq)+97,8-Rank(sq));
      PrintPiece(p);
      fprintf(stdout,"] : ");
#endif

      switch(p) {
        /* White Piece */
      case (wpawn)  : score += TactPawn(sq,B,WHITE); break;
      case (wrook)  : score += TactRook(sq,B,WHITE); break;
      case (wknight): score += TactKnight(sq,B,WHITE); break;
      case (wbishop): score += TactBishop(sq,B,WHITE); break;
      case (wqueen) : score += TactQueen(sq,B,WHITE); break;
      case (wking)  : score += TactKing(sq,B,WHITE); break;
        /* Black Piece */
      case (bpawn)  : score -= TactPawn(sq,B,BLACK); break;
      case (brook)  : score -= TactRook(sq,B,BLACK); break;
      case (bknight): score -= TactKnight(sq,B,BLACK); break;
      case (bbishop): score -= TactBishop(sq,B,BLACK); break;
      case (bqueen) : score -= TactQueen(sq,B,BLACK); break;
      case (bking)  : score -= TactKing(sq,B,BLACK); break;
      }
      RemoveFirst(pieces);
#ifdef DEBUG_EVAL
    fprintf(stdout,"\n");
#endif
    }
  }
#ifdef DEBUG_EVAL
  fprintf(stdout,"After Piece Tactics : %d\n",score);
  fprintf(stdout,"Control Balance = %d\n",control);
  fprintf(stdout,"Contested Empty Squares : %d\n\n",contestcount);
#endif 
  
  /* Add on general positional score */
  if (B->Gamestage <= Middle) score += TacticsPositional(B);
  
  /* -- General score modifiers -- */
  
  /* Modifiers for pawns blocking bishops.  Your pawns should be on different squares to your
   * own bishops, but the same as your opponent's */

  /* White Bishops */
  if (B->WhiteBishops) {
    /* Only black square bishops */
    if (!(B->WhiteBishops & WhiteMask)) score += npw*PAWN_BLOCK;
    /* Only white square bishops */
    else if (!(B->WhiteBishops & BlackMask)) score -= npw*PAWN_BLOCK;
    /* Bonus for having two bishops (or more) on opposite colours */
    else score += TWO_BISHOPS;
#ifdef DEBUG_EVAL
    if (npw!=0) {
      if (!(B->WhiteBishops & WhiteMask)) fprintf(stdout,"White has only black square bishops : Pawn Block = %d\n",-npw*PAWN_BLOCK);
      else if (!(B->WhiteBishops & BlackMask)) fprintf(stdout,"White has only white square bishops : Pawn Block = %d\n",npw*PAWN_BLOCK);
    }
    if ((B->WhiteBishops & WhiteMask) && (B->WhiteBishops & BlackMask)) fprintf(stdout,"White has a bishop pair [+%d]\n",TWO_BISHOPS);
#endif
  }

  /* Black Bishops */
  if (B->BlackBishops) {
    /* Only black square bishops */
    if (!(B->BlackBishops & WhiteMask)) score -= npw*PAWN_BLOCK;
    /* Only white square bishops */
    else if (!(B->BlackBishops & BlackMask)) score += npw*PAWN_BLOCK;
    /* Penalty for opponent having two bishops (or more) on opposite colours */
    else score -= TWO_BISHOPS;
#ifdef DEBUG_EVAL
    if (npw!=0) {
      if (!(B->BlackBishops & WhiteMask)) fprintf(stdout,"Black has only black square bishops : Pawn Block = %d\n",npw*PAWN_BLOCK);
      else if (!(B->BlackBishops & BlackMask)) fprintf(stdout,"Black has only white square bishops : Pawn Block = %d\n",-npw*PAWN_BLOCK);
    }
    if ((B->BlackBishops & WhiteMask) && (B->BlackBishops & BlackMask)) fprintf(stdout,"Black has a bishop pair [-%d]\n",TWO_BISHOPS);
#endif
  }
  
  /* Penalty for having no pawns */
  if (!B->WhitePawns) score -= NO_PAWNS;
  if (!B->BlackPawns) score += NO_PAWNS;

  /* If there is no mating material for one side then the score cannot favour that side
   * (Note - we calculated this in the LazyEval and retained the results) */
  if (!wmat) score = min(0,score);
  if (!bmat) score = max(0,score); 
#ifdef DEBUG_EVAL
  if (!wmat) fprintf(stdout,"No mating material for white\n");
  if (!bmat) fprintf(stdout,"No mating material for black\n");
#endif 
#ifdef DRAWISH_ENDINGS
  /* Test for a 'drawish' ending, and reduce the score if so */
  if (Drawish(B)) score = (score * (50+tpts)) / 100;
#ifdef DEBUG_EVAL
  if (Drawish(B)) fprintf(stdout,"Drawish Position (score reduced)\n");
#endif
#endif  

#ifdef DEBUG_EVAL
  fprintf(stdout,"Final Score : %d   [Delta %d]\n",score,score-lazyscore);
#endif

   // Return score, possibly altered by the skill level
  if (Skill == 10) return score;
  return score + Random(((10-Skill) * 4) + 1) + 2 * Skill - 20;
}