int NegamaxAlphaBetaSearcher::SearchBestPlay(const GameState& state, int depth)
{
    std::vector<int> bestCell;
    int bestValue = -INFINITY;
    int bestPos = 0;
#ifdef _DEBUG
    _searcherCounter = 0;
#endif

    ResetTranspositionTable();

    GameState tryState = state;
    int player_id = state.GetCurrentPlayer();

    std::vector<MOVES_LIST> moves;
    int mc = tryState.FindMoves(player_id, moves);
    if(mc == 0) //遇到无路可走的情况,比如被对方逼着走禁手,可放弃一步
    {
        return -1;
    }
    SortMoves(moves);
    for(int i = 0; i < mc; i++)
    {
        tryState.DoPutChess(moves[i].cell, player_id);
        int value = NegaMax(tryState, depth - 1, -INFINITY, INFINITY, player_id);
        tryState.UndoPutChess(moves[i].cell);
        if(value > bestValue)
        {
            bestValue = value;
            bestCell.clear();
            bestCell.push_back(moves[i].cell);
        }
        else if(value == bestValue)
        {
            bestCell.push_back(moves[i].cell);
        }
    }

    if(bestCell.size() > 0)
        bestPos = rand() % bestCell.size();

#ifdef _DEBUG
    std::cout << "NegamaxSearcher " << _searcherCounter << " (with Alpha-Beta)" << std::endl;
#endif

    return bestCell[bestPos];
}
Пример #2
0
int Search (int ply, int depth, int alpha, int beta, int nodetype)
/**************************************************************************
 *
 *  The basic algorithm for this search routine came from Anthony 
 *  Marsland.  It is a PVS (Principal Variation Search) algorithm.
 *  The fail-soft alpha-beta technique is also used for improved
 *  pruning.
 *
 **************************************************************************/
{
   int best, score, nullscore, savealpha;
   int side, xside;
   int rc, t0, t1, firstmove;
   int fcut, fdel, donull, savenode, nullthreatdone, extend;
   leaf *p, *pbest;
   int g0, g1;
   int upperbound;

   /* Check if this position is a known draw */
   if (EvaluateDraw ())
      return (DRAWSCORE);
   if (GameCnt >= Game50+3 && Repeat())
   {
      RepeatCnt++;
      return (DRAWSCORE); 
   }

   side = board.side;
   xside = 1^side;
   donull = true;

/*************************************************************************
 *
 *  Perform some basic search extensions.
 *  1.  One reply extensions.  
 *  2.  If in check, extend (maximum of Idepth-1).
 *  3.  If there is a threat to the King, extend (not beyond 2*Idepth)
 *  4.  If recapture to same square and not beyond Idepth+2
 *  5.  If pawn move to 7th rank at the leaf node, extend.
 *
 *************************************************************************/
   extend = false;
   InChk[ply] = SqAtakd (board.king[side], xside);
   if (InChk[ply])
   {
      TreePtr[ply+1] = TreePtr[ply];
      GenCheckEscapes (ply);
      if (TreePtr[ply] == TreePtr[ply+1])
         return (-MATE+ply-2);
      if (TreePtr[ply]+1 == TreePtr[ply+1])
      {
         depth += DEPTH;
	 extend = true;
         OneRepCnt++;
      }
   }

/*
   We've already found a mate at the next ply.  If we aren't being mated by 
   a shorter line, so just return the current material value.
*/
   if (rootscore + ply >= MATE)
      return (MATERIAL);

   g0 = Game[GameCnt].move;
   g1 = GameCnt > 0 ? Game[GameCnt-1].move : 0;
   t0 = TOSQ(g0); 
   t1 = TOSQ(g1);
   ChkCnt[ply+1] = ChkCnt[ply];
   ThrtCnt[ply+1] = ThrtCnt[ply];
   KingThrt[white][ply] = MateScan (white);
   KingThrt[black][ply] = MateScan (black);
   if (InChk[ply]  && /* ChkCnt[ply] < Idepth-1*/ ply <= 2*Idepth/DEPTH)
   {
      ChkExtCnt++;
      ChkCnt[ply+1]++;
      depth += DEPTH;
      extend = true;
   }
   else if (!KingThrt[side][ply-1] && KingThrt[side][ply] && ply <= 2*Idepth/DEPTH)
   {
      KingExtCnt++;
      extend = true;
      depth += DEPTH;
      extend = true;
      donull = false;
   }
   /* Promotion extension */
   else if (g0 & PROMOTION)
   {
      PawnExtCnt++;
      depth += DEPTH;
      extend = true;
   }
   /* Recapture extension */
   else if ((g0 & CAPTURE) && (board.material[computer] - 
	board.material[1^computer] == RootMaterial))
   {
      RcpExtCnt++;
      depth += DEPTH;
      extend = true;
   }
   /* 6th or 7th rank extension */
   else if (depth <= DEPTH && cboard[t0] == pawn && (RANK(t0) == rank7[xside] || RANK(t0) == rank6[xside]))
   {
      PawnExtCnt++;
      depth += DEPTH;
      extend = true;
   }

/**************************************************************************** 
 *
 *  The following extension is to handle cases when the opposing side is 
 *  delaying the mate by useless interposing moves. 
 *
 ****************************************************************************/
   if (ply > 2 && InChk[ply-1] && cboard[t0] != king && t0 != t1 && 
	 !SqAtakd (t0, xside))
   {
      HorzExtCnt++;
      depth += DEPTH;
      extend = true;
   }

/***************************************************************************
 *
 *  This is a new code to perform search reductiion.  We introduce some
 *  form of selectivity here.
 *
 **************************************************************************/

   if (depth <= 0)
      return (Quiesce (ply, alpha, beta)); 

/**************************************************************************** 
 *
 *  Probe the transposition table for a score and a move.
 *  If the score is an upperbound, then we can use it to improve the value
 *  of beta.  If a lowerbound, we improve alpha.  If it is an exact score,
 *  if we now get a cut-off due to the new alpha/beta, return the score.
 *
 ***************************************************************************/
   Hashmv[ply] = 0;
   upperbound = INFINITY;
   if (flags & USEHASH)
   {
      rc = TTGet (side, depth, ply, alpha, beta, &score, &g1);
      if (rc)
      {
         Hashmv[ply] = g1 & MOVEMASK;
         switch (rc)
         {
            case POORDRAFT  :  break;
	    case EXACTSCORE :  return (score);
            case UPPERBOUND :  beta = MIN (beta, score);
			       upperbound = score;
			       donull = false;
	                       break;
            case LOWERBOUND :  /*alpha = MAX (alpha, score);*/
			       alpha = score;
	                       break;
	    case QUIESCENT  :  Hashmv[ply] = 0;
	                       break;
	    default : break;
         }
	 if (alpha >= beta)
	    return (score);
      }
   }

/*****************************************************************************
 *
 *  Perform the null move here.  There are certain cases when null move
 *  is not done.  
 *  1.  When the previous move is a null move.
 *  2.  At the frontier (depth == 1)
 *  3.  At a PV node.
 *  4.  If side to move is in check.
 *  5.  If the material score + pawn value is still below beta.
 *  6.  If we are being mated at next ply.
 *  7.  If hash table indicate the real score is below beta (UPPERBOUND).
 *  8.  If side to move has less than or equal to a bishop in value.
 *  9.  If Idepth <= 3.  This allows us to find mate-in 2 problems quickly.
 *  10. We are looking for a null threat.
 *
 *****************************************************************************/
   if (ply > 4 && InChk[ply-2] && InChk[ply-4])
      donull = false;
   if (flags & USENULL && g0 != NULLMOVE && depth > DEPTH && nodetype != PV &&
       !InChk[ply] && MATERIAL+ValueP > beta && beta > -MATE+ply && donull &&
	board.pmaterial[side] > ValueB && !threatply)
   {
      TreePtr[ply+1] = TreePtr[ply];
      MakeNullMove (side);
      nullscore = -Search (ply+1, depth-DEPTH-R, -beta, -beta+1, nodetype);
      UnmakeNullMove (xside); 
      if (nullscore >= beta)
      {
         NullCutCnt++;
         return (nullscore);
      }
      if ( depth-DEPTH-R >= 1 && MATERIAL > beta && nullscore <= -MATE+256)
      {
         depth += DEPTH;
	 extend = true;
      }
   }

   if (InChk[ply] && TreePtr[ply]+1 < TreePtr[ply+1])
      SortMoves (ply);

   pickphase[ply] = PICKHASH;
   GETNEXTMOVE;

/*************************************************************************
 *
 *  Razoring + Futility.
 *  At depth 3, if there is no extensions and we are really bad, decrease
 *  the search depth by 1.
 *  At depth 2, if there is no extensions and we are quite bad, then we
 *  prune all non checking moves and capturing moves that don't bring us up
 *  back to alpha.
 *  Caveat: Skip all this if we are in the ending.
 *
 *************************************************************************/
   fcut = false;
   fdel = MAX (ValueQ, maxposnscore[side]);
   if (!extend && nodetype != PV && depth == 3*DEPTH && FUTSCORE <= alpha)
   {
      depth = 2*DEPTH;
      RazrCutCnt++;
   }
   fdel = MAX (ValueR, maxposnscore[side]);
   fcut = (!extend && nodetype != PV && depth == 2*DEPTH && FUTSCORE <= alpha);
   if (!fcut)
   {
      fdel = MAX (3*ValueP, maxposnscore[side]);
      fcut = (nodetype != PV && depth == DEPTH && FUTSCORE <= alpha);
   }

   MakeMove (side, &p->move);
   NodeCnt++;
   g0 = g1 = 0;
   while ((g0 = SqAtakd (board.king[side], xside)) > 0 ||
      	 (fcut && FUTSCORE < alpha && !SqAtakd (board.king[xside], side) &&
	  !MateScan (xside)))
   {
      if (g0 == 0) g1++;
      UnmakeMove (xside, &p->move);
      if (GETNEXTMOVE == false)
         return (g1 ? Evaluate(alpha,beta) : DRAWSCORE);
      MakeMove (side, &p->move);
      NodeCnt++;
   }
   firstmove = true;
   pbest = p;
   best = -INFINITY;
   savealpha = alpha;
   nullthreatdone = false;
   nullscore = INFINITY;
   savenode = nodetype;
   if (nodetype != PV)
      nodetype = (nodetype == CUT) ? ALL : CUT;

   while (1)
   {
      /* We have already made the move before the loop. */
      if (firstmove)
      {
         firstmove = false;
         score = -Search (ply+1, depth-DEPTH, -beta, -alpha, nodetype);
      }

      /* Zero window search for rest of moves */
      else
      {
	 if (GETNEXTMOVE == false)
	    break;

#ifdef THREATEXT
/****************************************************************************
 *
 *  This section needs to be explained.  We are doing a null threat search
 *  and the previous ply was the null move.  Inhibit any move which captures
 *  the fail-high moving piece.  Also inhibit any move by the piece which is 
 *  captured by the fail-high move.  Both these moves cannot be executed in
 *  the actual threat, so.....
 *  Also 3 plies later, inhibit moves out of the target square of the PV/fail
 *  high move as this is also not possible.
 *
 ****************************************************************************/
	 if (threatply+1 == ply)
	 { 
	    if ((TOSQ(p->move) == FROMSQ(threatmv)) ||
			 (FROMSQ(p->move) == TOSQ(threatmv)))
	       continue; 
	 }
         if (threatply && threatply+3 == ply && FROMSQ(p->move)==TOSQ(threatmv))
            continue;
#endif

         MakeMove (side, &p->move);
         NodeCnt++;
         if (SqAtakd (board.king[side], xside)) 
         {
            UnmakeMove (xside, &p->move);
            continue;
         }

/*****************************************************************************
 *
 *  Futility pruning.  The idea is that at the frontier node (depth == 1),
 *  if the side on the move is materially bad, then if the move doesn't win
 *  back material or the move isn't a check or doesn't threatened the king, 
 *  then there is no point in searching this move.  So skip it.  
 *  Caveat:  However if the node is a PV, we skip this test.
 *
 *****************************************************************************/
      	 if (fcut && FUTSCORE <= alpha && !SqAtakd (board.king[xside], side) &&
		!MateScan (xside))
		
         {
            UnmakeMove (xside, &p->move);
	    FutlCutCnt++;
	    NodeCnt--;
            continue;
         }
         NodeCnt++;

         if (nodetype == PV)
            nodetype = CUT;
         alpha = MAX (best, alpha);                /* fail-soft condition */
         score = -Search (ply+1, depth-DEPTH, -alpha-1, -alpha, nodetype);
         if (score > best)
         {
	    if (savenode == PV)
	       nodetype = PV;
            if (alpha < score && score < beta)
	    {
               score = -Search (ply+1, depth-DEPTH, -beta, -score, nodetype);
	    } 
	    if (nodetype == PV && score <= alpha &&
		Game[GameCnt+1].move == NULLMOVE)
	    {
               score = -Search (ply+1, depth-DEPTH, -alpha, INFINITY, nodetype);
	    }
         }
      }
      UnmakeMove (xside, &p->move);

/*  Perform threat extensions code */
#ifdef THREATEXT
      if ((score >= beta || nodetype == PV) && !InChk[ply] && g0 != NULLMOVE &&
	!threatply && depth == 4 && ThrtCnt[ply] < 1)
      {
	 if (!nullthreatdone)
	 {
	    threatply = ply;
	    threatmv  = p->move;
            MakeNullMove (side);
            nullscore = -Search(ply+1, depth-1-R, -alpha+THREATMARGIN, 
			-alpha+THREATMARGIN+1, nodetype);
            UnmakeNullMove (xside); 
	    nullthreatdone = true;
	    threatply = 0;
	 }
	 if (nullscore <= alpha-THREATMARGIN)
	 {
	    ThrtExtCnt++;
            ThrtCnt[ply+1]++;
            MakeMove (side, &p->move);
            score = -Search (ply+1, depth, -beta, -alpha, nodetype);
            UnmakeMove (xside, &p->move);
            ThrtCnt[ply+1]--;
         }
      }	
#endif
      
      if (score > best)
      {
         best = score;
         pbest = p;
	 if (best >= beta)
	    goto done;
      }

      if (flags & TIMEOUT)
      {
         best = (ply & 1 ? rootscore : -rootscore);
	 return (best);
      }

      if (SearchDepth == 0 && (NodeCnt & TIMECHECK) == 0)
      {
         GetElapsed ();
         if ((et >= SearchTime && (rootscore == -INFINITY-1 || 
		ply1score > lastrootscore - 25 || flags & SOLVE)) ||
	     et >= maxtime)
	    SET (flags, TIMEOUT);        
      }

/*  The following line should be explained as I occasionally forget too :) */
/*  This code means that if at this ply, a mating move has been found,     */
/*  then we can skip the rest of the moves!  				   */
      if (MATE+1 == best+ply)
         goto done;
   } 

/*****************************************************************************
 *
 *  Out of main search loop.
 *
 *****************************************************************************/
done:

/*
   if (upperbound < best)
      printf ("Inconsistencies %d %d\n", upperbound, best);
*/

   /*  Save the best move inside the transposition table  */
   if (flags & USEHASH)
      TTPut (side, depth, ply, savealpha, beta, best, pbest->move); 

   /*  Update history  */
   if (best > savealpha)
      history[side][pbest->move & 0x0FFF] += HISTSCORE(depth/DEPTH);

   /*  Don't store captures as killers as they are tried before killers */
   if (!(pbest->move & (CAPTURE | PROMOTION)) && best > savealpha)
   {
      if (killer1[ply] == 0)
         killer1[ply] = pbest->move & MOVEMASK;
      else if ((pbest->move & MOVEMASK) != killer1[ply])
         killer2[ply] = pbest->move & MOVEMASK;
   }

   return (best);
}
Пример #3
0
static int AlphaBeta(BOARD *board, unsigned int depth, int alpha, int beta,
               int root, CONTROL *control, char skip_null, MOVE killers[][2])
{
    int nmoves, nlegal = 0;
    MOVE moves[MAXMOVES];
    MOVE best_move = 0;
    char str_mov[MVLEN];
    int val = ERRORVALUE;
    char hash_flag = HASH_ALPHA;
    int reduce = 0, LMR = 0;

    if(depth){
        if(root > 0){
            val = GetHashEval(&hash_table, board->zobrist_key, depth, alpha, beta);
            if(val != ERRORVALUE) return val; 
        }
        if(depth > 2 && !InCheck(board, 0)){

            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;
            }
            reduce = 1;	/*Try Late Move reductions.*/
        }
        nmoves = MoveGen(board, moves, 1);
        int good = SortMoves(board, moves, nmoves, killers[root]);
        for(int i = 0; i < nmoves; i++){
            MakeMove(board, &moves[i]);
            control->node_count++;
            if(!LeftInCheck(board)){
                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 hashfull %i currmove %s currmovenumber %i\n",
                            depth, hash_table.full/(hash_table.size/1000), str_mov, i+1);
                    }
                }
                nlegal++;
                val = AssesDraw(board);
                if(val) {
                    if(best_move){
                        LMR = (reduce && i > good && !CAPTMASK(moves[i]) && !InCheck(board, 0)) ? 1 : 0;
                        val = -AlphaBeta(board, depth-LMR-1, -alpha-1, -alpha, root+1, control, 0, killers);
                        if(val > alpha){
                            val = -AlphaBeta(board, depth-1, -alpha-1, -alpha, root+1, control, 0, killers);
                            if(val > alpha && val < beta){
                                val = -AlphaBeta(board, depth-1, -beta, -alpha, root+1, control, 0, killers);
                            }
                        }
                    }else val = -AlphaBeta(board, depth-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;
                }
            }else Takeback(board, moves[i]);
        }
        if(nlegal == 0){
            if(InCheck(board, 0)){
/*UpdateTable(&hash_table, board->zobrist_key, MATE_VALUE+root, 0, depth, HASH_EXACT, hash_table.entries);*/
                return MATE_VALUE;
            }else{
/*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);
        
    }else if(InCheck(board, 0)){
        alpha = AlphaBeta(board, 1, alpha, beta, root+1, control, 1, killers);
    }else{
        alpha = Quiescent(board, alpha, beta, root, control, killers);
    }
    return alpha;
}
int NegamaxAlphaBetaSearcher::NegaMax(GameState& state, int depth, int alpha, int beta, int max_player_id)
{
    int alphaOrig = alpha;
#if 0
    unsigned int state_hash = state.GetHash();

    //查询置换表
    TT_ENTRY ttEntry = { 0 };
    if(LookupTranspositionTable(state_hash, ttEntry) && (ttEntry.depth >= depth))
    {
        if(ttEntry.flag == TT_FLAG_EXACT)
            return ttEntry.value;
        else if(ttEntry.flag == TT_FLAG_LOWERBOUND)
            alpha = std::max(alpha, ttEntry.value);
        else// if(ttEntry.flag == TT_FLAG_UPPERBOUND)
            beta = std::min(beta, ttEntry.value);

        if(beta <= alpha)
            return ttEntry.value;
    }
#endif
    if(state.IsGameOver() || (depth == 0))
    {
#ifdef _DEBUG
        _searcherCounter++;
#endif
        return EvaluateNegaMax(state, max_player_id);
    }
    
    state.SwitchPlayer();
    int score = -INFINITY;
    int player_id = state.GetCurrentPlayer();

    std::vector<MOVES_LIST> moves;
    int mc = state.FindMoves(player_id, moves);
    SortMoves(moves);
    for(int i = 0; i < mc; i++)
    {
        state.DoPutChess(moves[i].cell, player_id);
        int value = -NegaMax(state, depth - 1, -beta, -alpha, max_player_id);
        state.UndoPutChess(moves[i].cell);
        score = std::max(score, value);
        alpha = std::max(alpha, value);
        if(beta <= alpha)
            break;
    }

    state.SwitchPlayer();
#if 0
    //写入置换表
    ttEntry.value = score;
    if(score <= alphaOrig)
        ttEntry.flag = TT_FLAG_UPPERBOUND;
    else if(score >= beta)
        ttEntry.flag = TT_FLAG_LOWERBOUND;
    else
        ttEntry.flag = TT_FLAG_EXACT;

    ttEntry.depth = depth;
    StoreTranspositionTable(state_hash, ttEntry);
#endif
    return score;
}
Пример #5
0
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;
}
Пример #6
0
int Quiesce (uint8_t ply, int alpha, int beta)
/**************************************************************************
 *
 *  Our quiescent search.  This quiescent search is able to recognize
 *  mates.
 *
 **************************************************************************/
{
   uint8_t side, xside;
   int best, delta, score, savealpha;
   leaf *p, *pbest;

   if (EvaluateDraw ())
      return (DRAWSCORE);

   side = board.side;
   xside = 1^side;
   InChk[ply] = SqAtakd (board.king[side], xside);
   best = Evaluate (alpha, beta);
   if (best >= beta && !InChk[ply])
      return (best);
   TreePtr[ply+1] = TreePtr[ply];
   if (InChk[ply])
   {
      GenCheckEscapes (ply);
      if (TreePtr[ply] == TreePtr[ply+1])
         return (-MATE+ply-2);
      if (best >= beta)
         return (best);
      SortMoves (ply);
   }
   else
   {
      GenCaptures (ply);
      if (TreePtr[ply] == TreePtr[ply+1])
         return (best);
      SortCaptures (ply); 
   }

   savealpha = alpha;
   pbest = NULL;
   alpha = MAX(best, alpha);
   delta = MAX (alpha - 150 - best, 0);

   for (p = TreePtr[ply]; p < TreePtr[ply+1]; p++)
   {
      pick (p, ply);

      /* We are in check or capture cannot bring score near alpha, give up */
      if (!InChk[ply] && SwapOff (p->move) < delta)
         continue;

      /* If capture cannot bring score near alpha, give up */
      if (p->score == -INFINITY)
	 continue;

#ifdef THREATEXT
/*  See search.c for an explanation of the code below  */
      if (threatply+1 == ply) 
      {
         if ((TOSQ(p->move) == FROMSQ(threatmv)) || 
		(FROMSQ(p->move) == TOSQ(threatmv)))
	    continue;
      }
      if (threatply && threatply+3 == ply && FROMSQ(p->move) == TOSQ(threatmv))
	 continue;
#endif

      MakeMove (side, &p->move);
      QuiesCnt++;
      if (SqAtakd (board.king[side], xside))
      {
         UnmakeMove (xside, &p->move);
         continue;
      }
      score = -Quiesce (ply+1, -beta, -alpha);
      UnmakeMove (xside, &p->move);
      if (score > best)
      {
         best = score;
	 pbest = p;
         if (best >= beta)
	    goto done;
         alpha = MAX (alpha, best);
      }
   }

done:
   if (flags & USEHASH && pbest != NULL)
      TTPut (side, 0, ply, savealpha, beta, best, pbest->move);

   return (best);
}