int Minimax::Quiescence(Board *board, GameInfo *gameInfo, int depth, int alpha, int beta) {
	// Evaluate the node in its current state. If it causes a beta-cutoff, assume that there will be no move further down the
	//game tree that will result in a better evaluation. Otherwise, set it as the lower bound, alpha.
	int nodeEvaluation = Eval(board, gameInfo);
	if (nodeEvaluation >= beta) return beta;
	if (nodeEvaluation > alpha) alpha = nodeEvaluation;
	MoveList moveList;
	// If the node is in check, consider every move. Otherwise, just consider captures/promotions.
	moveList.generate(gameInfo->turn, board, gameInfo, !MoveList::InCheck(gameInfo->turn, board));
	moveList.prune((Piece::Color)!gameInfo->turn, board);
	for (MoveList::iterator moveItr = moveList.begin(); moveItr != moveList.end(); moveItr++) {
		Move move = *moveItr;
		board->executeMove(move);
		// Save any irreversible game info before making a move.
		GameInfo::Irreversible irreversible(gameInfo);
		gameInfo->executeMove(move);
		int childEval = 0;
		// If we are at depth 0, just get the score of the board (The score is negated as it is measured relative to the opposite color).
		if (depth == 0) childEval = -Eval(board, gameInfo);
		else childEval = -Quiescence(board, gameInfo, depth - 1, -beta, -alpha);
		board->reverseMove(move);
		gameInfo->reverseMove(irreversible);
		if (childEval >= beta) return beta;
		if (childEval > alpha) alpha = childEval;
	}
	return alpha;
}
int Minimax::AlphaBeta(Board *board, GameInfo *gameInfo, Move &move, int depth, const int quiescenceDepth, int alpha, int beta) {
	// If we are at the end of the normal alpha beta search, perform a quiescence search with the given quiescence depth.
	if (depth == 0) return Quiescence(board, gameInfo, quiescenceDepth, alpha, beta);
	MoveList moveList;
	// Generate move list and check game state.
	GameInfo::State state = gameInfo->updateState(board, moveList);
	switch (state) {
		case GameInfo::STALEMATE:
		case GameInfo::FIFTY_MOVE_RULE:
		// Returns a score which will always be disregarded.
		return LARGEST_NUM + 1;
		case GameInfo::CHECKMATE:
		// Return arbitrarily large negative score (But not -LARGEST_NUM, as it would be cut off).
		return -LARGE_NUM;
	}
	MoveList::iterator bestMoveItr = moveList.begin();
	for (MoveList::iterator moveItr = moveList.begin(); moveItr != moveList.end(); moveItr++) {
		Move childMove = *moveItr;
		board->executeMove(childMove);
		// Save any irreversible game info before making a move.
		GameInfo::Irreversible irreversible(gameInfo);
		gameInfo->executeMove(childMove);
		// Here, the child's evaluation is taken to be the negation of its return value, so that seperate if statements for maximising and minimising
		//aren't required.
		int childEval = -AlphaBeta(board, gameInfo, move, depth - 1, quiescenceDepth, -beta, -alpha);
		board->reverseMove(childMove);
		gameInfo->reverseMove(irreversible);
		// If the child evaluates to a score greater than or equal to beta, there is a beta cutoff. This means that there is no further point exploring this
		// node's moves, as it is known that this node will at least be as bad if not worse than another node elsewhere in the game tree.
		if (childEval >= beta) {
			// If a non-capture move caused a beta-cutoff, increase its history weighting. The depth squared is added to the heuristic so that moves near
			//the leaf nodes don't dominate the heuristic (Leaf node score would be 0 * 0).
			if (!move.isCapture()) Move::HistoryHeuristic[move.subject_from][move.subject_to] += depth * depth;
			move = *bestMoveItr;
			return beta;
		}
		// If the child's evaluation is greater than alpha, this is the best move at the moment.
		if (childEval > alpha) {
			alpha = childEval;
			bestMoveItr = moveItr;
		}
	}
	move = *bestMoveItr;
	return alpha;
}
Пример #3
0
// Algorithme de recherche MinMax avec des coupes Alpha-Beta.
// Ici on considere seulement les prises.
int Quiescence(int ply, int wtm, int alpha, int beta )
{
  register int Valeur, AlphaInitiale;

  if ( ply >= MAXPLY-1 )
    return beta;

  iNodes++;

  if ( wtm ) {
    Valeur = Eval(ply, wtm, alpha, beta);
  }
  else {
    Valeur = -Eval(ply, wtm, alpha, beta);
  }

  // Remplace si le score est egal au score pour la NULLE.
  if ( Valeur == DRAWSCORE )
    Valeur = DRAWSCORE+1;

  AlphaInitiale = alpha;

  if ( Valeur > alpha ) {
    if ( Valeur >= beta ) return Valeur;
    alpha = Valeur;
    pv_length[ply] = ply-1;
  }

  // On genere toutes les prises.
  cb.MoveList[ply].nbmove = 0;
  GenMoveAttaque(ply, wtm, cb.MoveList[ply]);

  int keep = -1;
  // Le materiel.
  int iScoreMateriel = cb.ScoreMaterielBlanc-cb.ScoreMaterielNoir;
  iScoreMateriel = wtm?iScoreMateriel:-iScoreMateriel;
  int delta = alpha-100-iScoreMateriel;
  int iScoreGain;
  for( int i=0; i<cb.MoveList[ply].nbmove; i++ ) {
    // Garder le coup.
    bool bGarde = false;

    // On cherche seulement les coups qui ramene le materiel proche de alpha.
    // ex. Si celui qui jouent vient de se faire prendre une dame et que alpha
    // dit que le meilleur score est la perte d'un pion et bien ignorer tout
    // les captures qui ramene pas au moins la dame.
    if ( ValeurPiece[cb.MoveList[ply].moves[i].Capture] >= delta ) {
		if (cb.MoveList[ply].moves[i].Capture == ROI) return beta;
		
#ifdef USE_SEE
    	int iScoreCapture = ValeurPiece[cb.MoveList[ply].moves[i].Capture];
    	iScoreGain = iScoreCapture-ValeurPiece[cb.MoveList[ply].moves[i].Piece];
		if ( iScoreGain > 0 ||
			 iScoreGain >= 0 && 
			 delta <= 0 ) {
				bGarde = true;
		}
		else {
			iScoreGain = Echange(cb.MoveList[ply].moves[i].From, cb.MoveList[ply].moves[i].To, wtm );

      		if ( iScoreGain >= 0 ) {
        		bGarde = true;
    		}
		}
#else
		bGarde = true;
#endif
	}
	

    if ( bGarde ) {
      keep++;
      cb.MoveList[ply].moves[i].Score = iScoreGain;
      memcpy( &cb.MoveList[ply].moves[keep],
              &cb.MoveList[ply].moves[i],
              sizeof( TMove ) );
    }
  }
  cb.MoveList[ply].nbmove = keep+1;

  cb.MoveList[ply].currmove = -1;
  cb.MoveList[ply].Tri();
  Phase[ply] = CAPTURE_MOVES;
  // Maintenant, evaluer chaque coup.
  while( NextMove( cb, ply, wtm ) ) {

    // On execute le coup.
    MakeMove(ply, cb.MoveList[ply].CurrentMove(), wtm);
    // Mettre le coup dans le chemin actuel.
    cb.CurrentPath.moves[ply] = cb.MoveList[ply].moves[cb.MoveList[ply].currmove];
    if (!Check(wtm))
      Valeur = -Quiescence(ply+1, !wtm, -beta, -alpha);
    cb.MoveList[ply].CurrentMove().Score = Valeur;

    // On defait le coup.
    UnmakeMove(ply, cb.MoveList[ply].CurrentMove(), wtm);

    // Est-il meileur que notre valeur actuelle?
    if ( Valeur > alpha ) {
      if ( Valeur >= beta ) return Valeur;
	  pv_length[ply] = pv_length[ply+1];
	  pv[ply][ply] = cb.CurrentPath.moves[ply];
	  memcpy(&pv[ply][ply+1], &pv[ply+1][ply], sizeof(TMove)*(pv_length[ply]-ply));
      alpha = Valeur;
    }
#ifdef DEBUG
    Consistence( cb, cb.MoveList[ply].CurrentMove() );
#endif
  }

  return alpha;
}