Example #1
0
int Perft(POS *p, int ply, int depth) {

  int move = 0;
  int fl_mv_type;
  MOVES m[1];
  UNDO u[1];
  int mv_cnt = 0;

  InitMoves(p, m, 0, 0, ply);

  while (move = NextMove(m, &fl_mv_type)) {

  p->DoMove(move, u);

  if (Illegal(p)) { p->UndoMove(move, u); continue; }

  if (depth == 1) mv_cnt++;
    else          mv_cnt += Perft(p, ply + 1, depth - 1);
    p->UndoMove(move, u);
  }

  return mv_cnt;
}
Example #2
0
// Algorithme de recherche MinMax avec des coupes Alpha-Beta.
int Search(int depth, int ply, int wtm, int alpha, int beta, bool do_null)
{
  register int Valeur, AlphaInitiale, check_ext = 0, extension = 0,
           MoveCherche, danger = 0;
  if ( ply >= MAXPLY-1 )
    return beta;

  iNodes++;

  // Si on n'est pas en mode Analyse, Reste-t-il du temps?
  if ( interrupted || (timeabort && !g_bModeAnalyse) ) {
    return beta;
  }

  AlphaInitiale = alpha;

  // Calculer le temps restant.
  if ( (iNodes & 0xFF ) == 0xFF ) {
	  if ( TimeCheck() ) {
		  timeabort = true;
	  }
      // Verifier si il y a quelque chose dans le tampon
      // d'entree.
	 
      if ( inter() ) {
		char buf[10];
		int c = fgetc(stdin);
		if (c == 10)
		{
			c = fgetc(stdin);
			ungetc(c, stdin);
			if (c == '.')
			{
				scanf("%s", &buf);
			    printf( "stat01: %d %d %d %d %d\n", (TempsCenti()-timestamp),
				  iNodes, iProfondeurIteration, cb.MoveList[1].nbmove - cb.MoveList[1].currmove-1,
				  cb.MoveList[1].nbmove );
				journal.Log("received a dot\n");
			}
			else
			{
				interrupted = true;
			}
		}
		else
		{
			ungetc(c, stdin);
			interrupted = true;
		}
	  }
  }


  // Verifier si ce n'est pas une nulle.
  if (Repetition(wtm)) {
	  //if ( 0 < beta ) {
//		pv[ply-1][ply-1] = cb.CurrentPath.moves[ply-1];
		return 0;
//		if ( wtm ) {
//			return DRAWSCORE;
//		}
//		else {
//			return -DRAWSCORE;
//		}
	  //}
  }

  // Regarder dans la table de transposition pour voir si cette position
  // n'a pas deja ete calculer.
#ifdef TRANSPOSITION
  switch( TableTrans->Lookup( cb, ply, depth,
                              wtm, alpha, beta, danger ) ) {
    case SCORE_EXACTE:

      return alpha;
    case BORNE_SUPERIEUR:

      return alpha;
    case BORNE_INFERIEUR:

      return beta;
    case EVITER_NULL:
      do_null = false;
  }

#endif

#ifdef NULL_MOVE

  // En premier, on essai le NULL MOVE.
  if ( do_null ) {
    int nbPiece = wtm?cb.TotalMaterielBlanc:cb.TotalMaterielNoir;
    if ( !cb.inCheck[ply] && nbPiece > 5 && depth > 3 && alpha == beta-1) {
      int EnPassantB = cb.EnPassantB[ply+1];
      int EnPassantN = cb.EnPassantN[ply+1];
      cb.EnPassantB[ply+1] = -1;
      cb.EnPassantN[ply+1] = -1;
      Valeur = -Search(depth-3, ply+1, !wtm, -beta, -beta+1, false);
      cb.EnPassantB[ply+1] = EnPassantB;
      cb.EnPassantN[ply+1] = EnPassantN;
      if ( Valeur >= beta ) {
#ifdef TRANSPOSITION
      TableTrans->StoreRefutation( cb, ply, depth,
                                   wtm, Valeur, alpha, beta, danger );
#endif
        return Valeur;
      }
      if ( Valeur <= -MATE+50 )
        danger = 1;
    }
  }
#endif
  // Internal Iterative Deepening.
/*  if ( depth > 2 && ((!(ply&1) && alpha==root_alpha && beta==root_beta) ||
    ((ply&1) && alpha==-root_beta && beta==-root_alpha)) &&
      cb.HashMove[ply].From == 0 && cb.HashMove[ply].To == 0 ) {
      Valeur = ABSearch( cb, depth-2, ply, wtm, alpha, beta, true );

    if ( Valeur <= alpha ) {
      Valeur = ABSearch( cb, depth-2, ply, wtm, -MATE, beta, true );
    }
    else {
      if ( Valeur < beta ) {
        cb.HashMove[ply] = pv[ply-1][ply];
      }
      else cb.HashMove[ply] = cb.CurrentPath.moves[ply];
    }
  }*/

#ifdef TRANSPOSITION
  Phase[ply] = HASH_MOVE;
#else
//  if ( ((!(ply&1) && alpha==root_alpha && beta==root_beta) ||
//     ( (ply&1) && alpha==-root_beta && beta==-root_alpha)) )
    Phase[ply] = PV_MOVE;
//  else
//    Phase[ply] = GENERATE_CAPTURE_MOVES;
#endif

  // Maintenant, evaluer chaque coup.
  MoveCherche = 0;
  while( Phase[ply]  != NO_MORE_MOVES && !interrupted ) {

    if ( NextMove( cb, ply, wtm ) ) {

      // Si

      // 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)) {
        MoveCherche++;

        // Si le coup met en echec etendre la recherche d'une profondeur
        // pour qu'il puisse en sortir.
        if (Check(!wtm) ) {
          cb.inCheck[ply+1] = true;
          extension = 1;
          cb.RaisonExtension[ply] = EXTENSION_ECHEC;
        }
        else {
          extension = 0;
          cb.inCheck[ply+1] = false;
          cb.RaisonExtension[ply] = PAS_EXTENSION;
        }

        // Si le coup est une recapture
        // etendre la recherche d'une profondeur.
        if ( cb.CurrentPath.moves[ply].Capture &&
			abs(ValeurPiece[cb.CurrentPath.moves[ply-1].Capture] - ValeurPiece[cb.CurrentPath.moves[ply].Capture]) <= 20 &&
             (cb.CurrentPath.moves[ply-1].To ==
              cb.CurrentPath.moves[ply].To) &&
              cb.RaisonExtension[ply-1] != EXTENSION_RECAPTURE) {
          extension = 1;
          cb.RaisonExtension[ply] = EXTENSION_RECAPTURE;
        }

		// Si on est sur le point de promouvoir un pion, étendre la recherche
		// pour voir si c'est une menace.
		if ( extension == 0 && cb.CurrentPath.moves[ply].Piece == 1 &&
			PromoteExtension[ cb.CurrentPath.moves[ply].To ] ) {
			extension = 1;
			cb.RaisonExtension[ply] = EXTENSION_PROMOTION;
		}

		// Si on pousse un pion passe, pousser la recherche plus
        // loin pour voir si c'est un danger.
        if ( cb.CurrentPath.moves[ply].Piece == pion )
          if ( wtm ) {
            if ( cb.CurrentPath.moves[ply].To <= H5 )
              if ( cb.PionPasseB[cb.CurrentPath.moves[ply].To&7]  ) {
                extension = 1;
                cb.RaisonExtension[ply] = EXTENSION_PIONPASSE;
              }
          }
          else {
            if ( cb.CurrentPath.moves[ply].To >= A4 )
              if ( cb.PionPasseN[cb.CurrentPath.moves[ply].To&7] ) {
                extension = 1;
                cb.RaisonExtension[ply] = EXTENSION_PIONPASSE;
              }
          }


        // Razoring trick. Idee prise dans Crafty.
        if ( depth == 2 && !cb.inCheck[ply] && extension == 0 ) {
          int valeur;
          if ( wtm )
            valeur = Eval(ply, wtm, alpha, beta);
          else
            valeur = -Eval(ply, wtm, alpha, beta);
          if ( valeur+50 < alpha )
            extension = -1;
        }

        // On l'explore.
        // Si c'est la variation principale, Fenetre normale, sinon,
        // fenetre est n et n+1.
		int inpv = 1;
		if (ply&1) {
			if ( alpha != root_alpha || beta != root_beta ) inpv = 0;
		}
		else {
			if ( alpha != -root_beta || beta != -root_alpha ) inpv = 0;
		}
        if ( inpv ) {
          Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -beta, -alpha, true);
        }
        else {
          Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -alpha-1, -alpha, true);
          if ( Valeur > alpha && Valeur < beta ) {
			pvsresearch++;
            Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -beta, -alpha, true);
          }
        }
      }
      else {
        Valeur = -INFINI;
      }

      cb.MoveList[ply].CurrentMove().Score = Valeur;

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

	  if (interrupted)
		  return Valeur;

#ifdef DEBUG
      Consistence( cb, cb.MoveList[ply].CurrentMove() );
#endif
      // Est-il meilleur que notre valeur actuelle?
      if ( Valeur > alpha ) {
        if ( Valeur >= beta ) {
#ifdef TRANSPOSITION
          TableTrans->StoreRefutation( cb, ply, depth,
                                       wtm, Valeur, alpha, beta, check_ext );
#endif
		  g_iRefutation++;
          // Verifier si on peu l'utiliser comme killer move.
          if ( Phase[ply] == NON_CAPTURE_MOVES ) {
            cb.AddKiller( &cb.CurrentPath.moves[ply-1], ply-1 );
          }
          else {
            if ( Phase[ply] == KILLER_MOVE_2 )
              cb.Killers[ply-1][0].Score++;
            else if ( Phase[ply] == GENERATE_NON_CAPTURE_MOVES )
              cb.Killers[ply-1][1].Score++;
          }
          return Valeur;
        }
        pv[ply][ply] = cb.CurrentPath.moves[ply];
		pv_length[ply] = pv_length[ply+1];
		memcpy(&pv[ply][ply+1], &pv[ply+1][ply+1], sizeof(TMove)*(pv_length[ply]-ply));
        alpha = Valeur;
      }
    } // if
  }

  // Verifier si il y a mat ou pat.
  if ( MoveCherche == 0 ) {
    if (!Check(wtm)) {
		pv[ply][ply] = cb.CurrentPath.moves[ply];
		return 0;
//		if ( wtm ) {
//			return DRAWSCORE;
//		}
//		else {
//			return -DRAWSCORE;
//		}
    }
    else {
      if ( ply < iMateInPly )
        iMateInPly = ply;
      alpha = -MATE+iMateInPly;
    }
  }

#ifdef TRANSPOSITION
  TableTrans->StoreBest( cb, ply, depth, wtm,
                         alpha, AlphaInitiale, danger );
#endif

  return alpha;
}
Example #3
0
static int negascout(struct SearchData *sd,
                     int alpha,
                     int beta,
                     const int depth,
                     int node_type
#if MP
                     ,int exclusiveP
#endif /* MP  */
                    ) {
    struct Position *p = sd->position;
    struct SearchStatus *st;
    int best = -INF;
    int bestm = M_NONE;
    int tmp;
    int talpha;
    int incheck;
    int lmove;
    int move;
    int extend = 0;
    int threat = FALSE;
    int reduce_extensions;
    int next_type;
    int was_futile = FALSE;
#if FUTILITY
    int is_futile;
    int optimistic = 0;
#endif

#if MP
    int deferred_cnt = 0;
    int deferred_list[MAX_DEFERRED];
    int deferred_depth[MAX_DEFERRED];
#endif

    EnterNode(sd);

    Nodes++;

    /* check for search termination */
    if (sd->master && TerminateSearch(sd)) {
        AbortSearch = TRUE;
        goto EXIT;
    }

    /* max search depth reached */
    if (sd->ply >= MaxDepth) goto EXIT;

    /*
     * Check for insufficent material or theoretical draw.
     */

    if ( /* InsufMat(p) || CheckDraw(p) || */  Repeated(p, FALSE)) {
        best = 0;
        goto EXIT;
    }

    /*
     * check extension
     */

    incheck = InCheck(p, p->turn);
    if (incheck && p->material[p->turn] > 0) {
        extend += CheckExtend(p);
        ChkExt++;
    }

    /*
     * Check the hashtable
     */

    st = sd->current;

    HTry++;
#if MP
    switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply,
                    exclusiveP, sd->localHashTable))
#else
    switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply))
#endif /* MP */
    {
    case ExactScore:
        HHit++;
        best = tmp;
        goto EXIT;
    case UpperBound:
        if (tmp <= alpha) {
            HHit++;
            best = tmp;
            goto EXIT;
        }
        break;
    case LowerBound:
        if (tmp >= beta) {
            HHit++;
            best = tmp;
            goto EXIT;
        }
        break;
    case Useless:
        threat = !incheck && MateThreat(p, OPP(p->turn));
        break;
#if MP
    case OnEvaluation:
        best = -ON_EVALUATION;
        goto EXIT;
#endif
    }

    /*
     * Probe EGTB
     */

    if (depth > EGTBDepth && ProbeEGTB(p, &tmp, sd->ply)) {
        best = tmp;
        goto EXIT;
    }

    /*
     * Probe recognizers
     */

    switch (ProbeRecognizer(p, &tmp)) {
    case ExactScore:
        best = tmp;
        goto EXIT;
    case LowerBound:
        if (tmp >= beta) {
            best = tmp;
            goto EXIT;
        }
        break;
    case UpperBound:
        if (tmp <= alpha) {
            best = tmp;
            goto EXIT;
        }
        break;
    }

#if NULLMOVE

    /*
     * Null move search.
     * See Christian Donninger, "Null Move and Deep Search"
     * ICCA Journal Volume 16, No. 3, pp. 137-143
     */

    if (!incheck && node_type == CutNode && !threat) {
        int next_depth;
        int nms;

        next_depth = depth - ReduceNullMove;

        if (next_depth > 0) {
            next_depth = depth - ReduceNullMoveDeep;
        }

        DoNull(p);
        if (next_depth < 0) {
            nms = -quies(sd, -beta, -beta+1, 0);
        } else {
#if MP
            nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode, 0);
#else
            nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode);
#endif
        }
        UndoNull(p);

        if (AbortSearch) goto EXIT;
        if (nms >= beta) {
            if (p->nonPawn[p->turn] >= Value[Queen]) {
                best = nms;
                goto EXIT;
            } else {
                if (next_depth < 0) {
                    nms = quies(sd, beta-1, beta, 0);
                } else {
#if MP
                    nms = negascout(sd, beta-1, beta, next_depth, CutNodeNoNull,
                                    0);
#else
                    nms = negascout(sd, beta-1, beta, next_depth,
                                    CutNodeNoNull);
#endif
                }

                if (nms >= beta) {
                    best = nms;
                    goto EXIT;
                } else {
                    extend += ExtendZugzwang;
                    ZZExt++;
                }
            }
        } else if (nms <= -CMLIMIT) {
            threat = TRUE;
        }
    }
#endif /* NULLMOVE */

    lmove = (p->actLog-1)->gl_Move;
    reduce_extensions = (sd->ply > 2*sd->depth);
    talpha = alpha;

    switch (node_type) {
    case AllNode:
        next_type = CutNode;
        break;
    case CutNode:
    case CutNodeNoNull:
        next_type = AllNode;
        break;
    default:
        next_type = PVNode;
        break;
    }

#if FUTILITY
    is_futile = !incheck && !threat && alpha < CMLIMIT && alpha > -CMLIMIT;
    if (is_futile) {
        if (p->turn == White) {
            optimistic = MaterialBalance(p) + MaxPos;
        } else {
            optimistic = -MaterialBalance(p) + MaxPos;
        }
    }
#endif /* FUTILITY */

    /*
     * Internal iterative deepening. If we do not have a move, we try
     * a shallow search to find a good candidate.
     */

    if (depth > 2*OnePly && ((alpha + 1) != beta) && !LegalMove(p, st->st_hashmove)) {
        int useless;
#if MP
        useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode, 0);
#else
        useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode);
#endif
        st->st_hashmove = sd->pv_save[sd->ply+1];
    }

    /*
     * Search all legal moves
     */

    while ((move = incheck ? NextEvasion(sd) : NextMove(sd)) != M_NONE) {
        int next_depth = extend;

        if (move & M_CANY && !MayCastle(p, move)) continue;

        /*
         * recapture extension
         */

        if ((move & M_CAPTURE) && (lmove & M_CAPTURE) &&
                M_TO(move) == M_TO(lmove) &&
                IsRecapture(p->piece[M_TO(move)], (p->actLog-1)->gl_Piece)) {
            RCExt += 1;
            next_depth += ExtendRecapture[TYPE(p->piece[M_TO(move)])];
        }

        /*
         * passed pawn push extension
         */

        if (TYPE(p->piece[M_FROM(move)]) == Pawn &&
                p->nonPawn[OPP(p->turn)] <= Value[Queen]) {

            int to = M_TO(move);

            if (((p->turn == White && to >= a7)
                    || (p->turn == Black && to <= h2))
                    && IsPassed(p, to, p->turn) && SwapOff(p, move) >= 0) {
                next_depth += ExtendPassedPawn;
                PPExt += 1;
            }
        }

        /*
         * limit extensions to sensible range.
         */

        if (reduce_extensions) next_depth /= 2;

        next_depth += depth - OnePly;

#if FUTILITY

        /*
         * Futility cutoffs
         */

        if (is_futile) {
            if (next_depth < 0 && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move);
                if (tmp <= alpha) {
                    if (tmp > best) {
                        best = tmp;
                        bestm = move;
                        was_futile = TRUE;
                    }
                    continue;
                }
            }
#if EXTENDED_FUTILITY

            /*
             * Extended futility cutoffs and limited razoring.
             * See Ernst A. Heinz, "Extended Futility Pruning"
             * ICCA Journal Volume 21, No. 2, pp 75-83
             */

            else if (next_depth >= 0 && next_depth < OnePly
                     && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move) + (3*Value[Pawn]);
                if (tmp <= alpha) {
                    if (tmp > best) {
                        best = tmp;
                        bestm = move;
                        was_futile = TRUE;
                    }
                    continue;
                }
            }
#if RAZORING
            else if (next_depth >= OnePly && next_depth < 2*OnePly
                     && !IsCheckingMove(p, move)) {
                tmp = optimistic + ScoreMove(p, move) + (6*Value[Pawn]);
                if (tmp <= alpha) {
                    next_depth -= OnePly;
                }
            }
#endif /* RAZORING */
#endif /* EXTENDED_FUTILITY */
        }

#endif /* FUTILITY */

        DoMove(p, move);
        if (InCheck(p, OPP(p->turn))) {
            UndoMove(p, move);
        } else {
            /*
             * Check extension
             */

            if (p->material[p->turn] > 0 && InCheck(p, p->turn)) {
                next_depth += (reduce_extensions) ?
                              ExtendInCheck>>1 : ExtendInCheck;
            }

            /*
             * Recursively search this position. If depth is exhausted, use
             * quies, otherwise use negascout.
             */

            if (next_depth < 0) {
                tmp = -quies(sd, -beta, -talpha, 0);
            } else if (bestm != M_NONE && !was_futile) {
#if MP
                tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type,
                                 bestm != M_NONE);
                if (tmp != ON_EVALUATION && tmp > talpha && tmp < beta) {
                    tmp = -negascout(sd, -beta, -tmp, next_depth,
                                     node_type == PVNode ? PVNode : AllNode,
                                     bestm != M_NONE);
                }
#else
                tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type);
                if (tmp > talpha && tmp < beta) {
                    tmp = -negascout(sd, -beta, -tmp, next_depth,
                                     node_type == PVNode ? PVNode : AllNode);
                }
#endif /* MP */
            } else {
#if MP
                tmp = -negascout(sd, -beta, -talpha, next_depth, next_type,
                                 bestm != M_NONE);
#else
                tmp = -negascout(sd, -beta, -talpha, next_depth, next_type);
#endif /* MP */
            }

            UndoMove(p, move);

            if (AbortSearch) goto EXIT;

#if MP
            if (tmp == ON_EVALUATION) {

                /*
                 * This child is ON_EVALUATION. Remember move and
                 * depth.
                 */

                deferred_list[deferred_cnt] = move;
                deferred_depth[deferred_cnt] = next_depth;
                deferred_cnt++;

            } else {
#endif /* MP */

                /*
                 * beta cutoff, enter move in Killer/Countermove table
                 */

                if (tmp >= beta) {
                    if (!(move & M_TACTICAL)) {
                        PutKiller(sd, move);
                        sd->counterTab[p->turn][lmove & 4095] = move;
                    }
                    StoreResult(sd, tmp, alpha, beta, move, depth, threat);
                    best = tmp;
                    goto EXIT;
                }

                /*
                 * Improvement on best move to date
                 */

                if (tmp > best) {
                    best = tmp;
                    bestm = move;
                    was_futile = FALSE;

                    if (best > talpha) {
                        talpha = best;
                    }
                }

                next_type = CutNode;
#if MP
            }
#endif /* MP */
        }
    }
Example #4
0
/*
********************************************************************************
*                                                                              *
*   Search() is the recursive routine used to implement the alpha/beta         *
*   negamax search (similar to minimax but simpler to code.)  Search() is      *
*   called whenever there is "depth" remaining so that all moves are subject   *
*   to searching, or when the side to move is in check, to make sure that this *
*   side isn't mated.  Search() recursively calls itself until depth is ex-    *
*   hausted, at which time it calls Quiesce() instead.                         *
*                                                                              *
********************************************************************************
*/
int Search(int alpha, int beta, int wtm, int depth, int ply, int do_null)
{
  register int first_move=1;
  register BITBOARD save_hash_key;
  register int initial_alpha, value;
  register int extensions;
/*
 ----------------------------------------------------------
|                                                          |
|   check to see if we have searched enough nodes that it  |
|   is time to peek at how much time has been used, or if  |
|   is time to check for operator keyboard input.  this is |
|   usually enough nodes to force a time/input check about |
|   once per second, except when the target time per move  |
|   is very small, in which case we try to check the time  |
|   at least 10 times during the search.                   |
|                                                          |
 ----------------------------------------------------------
*/
  if (ply >= MAXPLY-2) return(beta);
  nodes_searched++;
  if (--next_time_check <= 0) {
    next_time_check=nodes_between_time_checks;
    if (CheckInput()) Interrupt(ply);
    time_abort+=TimeCheck(0);
    if (time_abort) {
      abort_search=1;
      return(0);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   check for draw by repetition.                          |
|                                                          |
 ----------------------------------------------------------
*/
  if (RepetitionCheck(ply,wtm)) {
    value=(wtm==root_wtm) ? DrawScore() : -DrawScore();
    if (value < beta) SavePV(ply,value,0);
#if !defined(FAST)
    if(ply <= trace_level) printf("draw by repetition detected, ply=%d.\n",ply);
#endif
    return(value);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now call LookUp() to see if this position has been     |
|   searched before.  if so, we may get a real score,      |
|   produce a cutoff, or get nothing more than a good move |
|   to try first.  there are four cases to handle:         |
|                                                          |
|   1. LookUp() returned "EXACT_SCORE" if this score is    |
|   greater than beta, return beta.  otherwise, return the |
|   score.  In either case, no further searching is needed |
|   from this position.  note that lookup verified that    |
|   the table position has sufficient "draft" to meet the  |
|   requirements of the current search depth remaining.    |
|                                                          |
|   2.  LookUp() returned "LOWER_BOUND" which means that   |
|   when this position was searched previously, every move |
|   was "refuted" by one of its descendents.  as a result, |
|   when the search was completed, we returned alpha at    |
|   that point.  we simply return alpha here as well.      |
|                                                          |
|   3.  LookUp() returned "UPPER_BOUND" which means that   |
|   when we encountered this position before, we searched  |
|   one branch (probably) which promptly refuted the move  |
|   at the previous ply.                                   |
|                                                          |
|   4.  LookUp() returned "AVOID_NULL_MOVE" which means    |
|   the hashed score/bound was no good, but it indicated   |
|   that trying a null-move in this position will be a     |
|   waste of time.                                         |
|                                                          |
 ----------------------------------------------------------
*/
  switch (LookUp(ply,depth,wtm,&alpha,beta)) {
    case EXACT_SCORE:
      if(alpha >= beta) return(beta);
      else {
        SavePV(ply,alpha,1);
        return(alpha);
      }
    case LOWER_BOUND:
      return(alpha);
    case UPPER_BOUND:
      return(beta);
    case AVOID_NULL_MOVE:
      do_null=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now it's time to try a probe into the endgame table-   |
|   base files.  this is done if (a) the previous move was |
|   a capture or promotion, unless we are at very shallow  |
|   plies (<4) in the search; (b) there are less than 5    |
|   pieces left (currently all interesting 4 piece endings |
|   are available.)                                        |
|                                                          |
 ----------------------------------------------------------
*/
#if defined(TABLEBASES)
  if (TotalPieces < 5) do {
    register int wpawn, bpawn;
    int tb_value;
    if (TotalWhitePawns && TotalBlackPawns) {
      wpawn=FirstOne(WhitePawns);
      bpawn=FirstOne(BlackPawns);
      if (FileDistance(wpawn,bpawn) == 1) {
        if(((Rank(wpawn)==1) && (Rank(bpawn)>2)) ||
           ((Rank(bpawn)==6) && (Rank(wpawn)<5)) || 
           EnPassant(ply)) break;
      }
    }
    tb_probes++;
    if (EGTBScore(ply, wtm, &tb_value)) {
      tb_probes_successful++;
      alpha=tb_value;
      if (abs(alpha) > MATE-100) alpha+=(alpha > 0) ? -(ply-1) : +(ply-1);
      else if (alpha == 0) alpha=(wtm==root_wtm) ? DrawScore() : -DrawScore();
      if(alpha >= beta) return(beta);
      else {
        SavePV(ply,alpha,2);
        return(alpha);
      }
    }
  } while(0);
# endif
/*
 ----------------------------------------------------------
|                                                          |
|   initialize.                                            |
|                                                          |
 ----------------------------------------------------------
*/
  in_check[ply+1]=0;
  extended_reason[ply+1]=no_extension;
  initial_alpha=alpha;
  last[ply]=last[ply-1];
  killer_count1[ply+1]=0;
  killer_count2[ply+1]=0;
/*
 ----------------------------------------------------------
|                                                          |
|  first, we try a null move to see if we can get a quick  |
|  cutoff with only a little work.  this operates as       |
|  follows.  instead of making a legal move, the side on   |
|  move 'passes' and does nothing.  the resulting position |
|  is searched to a shallower depth than normal (usually   |
|  one ply less but settable by the operator) this should  |
|  result in a cutoff or at least should set the lower     |
|  bound better since anything should be better than not   |
|  doing anything.                                         |
|                                                          |
|  this is skipped for any of the following reasons:       |
|                                                          |
|  1.  the side on move is in check.  the null move        |
|      results in an illegal position.                     |
|  2.  no more than one null move can appear in succession |
|      or else the search will degenerate into nothing.    |
|  3.  the side on move has little material left making    |
|      zugzwang positions more likely.                     |
|                                                          |
 ----------------------------------------------------------
*/
# if defined(NULL_MOVE_DEPTH)
  if (do_null && !in_check[ply] && 
      ((wtm) ? TotalWhitePieces : TotalBlackPieces)>2) {
    current_move[ply]=0;
    current_phase[ply]=NULL_MOVE;
#if !defined(FAST)
    if (ply <= trace_level)
      SearchTrace(ply,depth,wtm,alpha,beta,"Search",0);
#endif
    position[ply+1]=position[ply];
    Rule50Moves(ply+1)++;
    save_hash_key=HashKey;
    if (EnPassant(ply)) {
      HashEP(EnPassant(ply+1),HashKey);
      EnPassant(ply+1)=0;
    }
    if ((depth-NULL_MOVE_DEPTH-INCREMENT_PLY) >= INCREMENT_PLY)
      value=-Search(-beta,-alpha,ChangeSide(wtm),depth-NULL_MOVE_DEPTH-INCREMENT_PLY,ply+1,NO_NULL);
    else 
      value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
    HashKey=save_hash_key;
    if (abort_search) return(0);
    if (value >= beta) {
      StoreRefutation(ply,depth,wtm,beta);
      return(beta);
    }
  }
# endif
/*
 ----------------------------------------------------------
|                                                          |
|   if there is no best move from the hash table, and this |
|   is a PV node, then we need a good move to search       |
|   first.  while killers and history moves are good, they |
|   are not "good enough".  the simplest action is to try  |
|   a shallow search (depth-2) to get a move.  note that   |
|   when we call Search() with depth-2, it, too, will      |
|   not have a hash move, and will therefore recursively   |
|   continue this process, hence the name "internal        |
|   iterative deepening."                                  |
|                                                          |
 ----------------------------------------------------------
*/
  next_status[ply].phase=FIRST_PHASE;
  if (hash_move[ply]==0 && (depth > 2*INCREMENT_PLY) &&
      (((ply & 1) && alpha == root_alpha && beta == root_beta) ||
      (!(ply & 1) && alpha == -root_beta && beta == -root_alpha))) {
    current_move[ply]=0;
    value=Search(alpha,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL);
    if (abort_search) return(0);
    if (value <= alpha) {
      value=Search(-MATE,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL);
      if (abort_search) return(0);
    }
    else if (value < beta) {
      if ((int) pv[ply-1].path_length >= ply) hash_move[ply]=pv[ply-1].path[ply];
    }
    else hash_move[ply]=current_move[ply];
    last[ply]=last[ply-1];
    next_status[ply].phase=FIRST_PHASE;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now iterate through the move list and search the       |
|   resulting positions.  note that Search() culls any     |
|   move that is not legal by using Check().  the special  |
|   case is that we must find one legal move to search to  |
|   confirm that it's not a mate or draw.                  |
|                                                          |
 ----------------------------------------------------------
*/
  while ((current_phase[ply]=(in_check[ply]) ? NextEvasion(ply,wtm) : 
                                               NextMove(depth,ply,wtm))) {
    extended_reason[ply]&=check_extension;
#if !defined(FAST)
    if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",current_phase[ply]);
#endif
/*
 ----------------------------------------------------------
|                                                          |
|   if two successive moves are capture / re-capture so    |
|   that the material score is restored, extend the search |
|   by one ply on the re-capture since it is pretty much   |
|   forced and easy to analyze.                            |
|                                                          |
 ----------------------------------------------------------
*/
    extensions=-INCREMENT_PLY;
    if (Captured(current_move[ply]) && Captured(current_move[ply-1]) &&
        To(current_move[ply-1]) == To(current_move[ply]) &&
        (p_values[Captured(current_move[ply-1])+7] == 
         p_values[Captured(current_move[ply])+7] ||
         Promote(current_move[ply-1])) &&
        !(extended_reason[ply-1]&recapture_extension)) {
      extended_reason[ply]|=recapture_extension;
      recapture_extensions_done++;
      extensions+=RECAPTURE;
    }
/*
 ----------------------------------------------------------
|                                                          |
|   if we push a passed pawn, we need to look deeper to    |
|   see if it is a legitimate threat.                      |
|                                                          |
 ----------------------------------------------------------
*/
    if (Piece(current_move[ply])==pawn && !FutileAhead(wtm) &&
         ((wtm && To(current_move[ply])>H5 && TotalBlackPieces<16 &&
          !And(mask_pawn_passed_w[To(current_move[ply])],BlackPawns)) ||
         (!wtm && To(current_move[ply])<A4 && TotalWhitePieces<16 &&
          !And(mask_pawn_passed_b[To(current_move[ply])],WhitePawns)) ||
         push_extensions[To(current_move[ply])]) &&
         Swap(From(current_move[ply]),To(current_move[ply]),wtm) >= 0) {
      extended_reason[ply]|=passed_pawn_extension;
      passed_pawn_extensions_done++;
      extensions+=PASSED_PAWN_PUSH;
    }
/*
 ----------------------------------------------------------
|                                                          |
|   now make the move and search the resulting position.   |
|   if we are in check, the current move must be legal     |
|   since NextEvasion ensures this, otherwise we have to   |
|   make sure the side-on-move is not in check after the   |
|   move to weed out illegal moves and save time.          |
|                                                          |
 ----------------------------------------------------------
*/
    MakeMove(ply,current_move[ply],wtm);
    if (in_check[ply] || !Check(wtm)) {
/*
 ----------------------------------------------------------
|                                                          |
|   if the move to be made checks the opponent, then we    |
|   need to remember that he's in check and also extend    |
|   the depth by one ply for him to get out.               |
|                                                          |
 ----------------------------------------------------------
*/
      if (Check(ChangeSide(wtm))) {
        in_check[ply+1]=1;
        extended_reason[ply+1]=check_extension;
        check_extensions_done++;
        extensions+=IN_CHECK;
      }
      else {
        in_check[ply+1]=0;
        extended_reason[ply+1]=no_extension;
      }
/*
 ----------------------------------------------------------
|                                                          |
|   now we toss in the "razoring" trick, which simply says |
|   if we are doing fairly badly, we can reduce the depth  |
|   an additional ply, if there was nothing at the current |
|   ply that caused an extension.                          |
|                                                          |
 ----------------------------------------------------------
*/
      if (depth < 3*INCREMENT_PLY && !in_check[ply] &&
          extensions == -INCREMENT_PLY) {
        register int val=(wtm) ? Material : -Material;
        if (val+1500 < alpha) extensions-=INCREMENT_PLY;
      }
/*
 ----------------------------------------------------------
|                                                          |
|   if there's only one legal move, extend the search one  |
|   additional ply since this node is very easy to search. |
|                                                          |
 ----------------------------------------------------------
*/
      if (first_move) {
        if (last[ply]-last[ply-1] == 1) {
          extended_reason[ply]|=one_reply_extension;
          one_reply_extensions_done++;
          extensions+=ONE_REPLY_TO_CHECK;
        }
        if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
          value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
        else {
          value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
        }
        if (abort_search) {
          UnMakeMove(ply,current_move[ply],wtm);
          return(0);
        }
        first_move=0;
      }
      else {
        if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
          value=-Search(-alpha-1,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
        else {
          value=-Quiesce(-alpha-1,-alpha,ChangeSide(wtm),ply+1);
        }
        if (abort_search) {
          UnMakeMove(ply,current_move[ply],wtm);
          return(0);
        }
        if (value>alpha && value<beta) {
          if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
            value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
          else 
            value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
          if (abort_search) {
            UnMakeMove(ply,current_move[ply],wtm);
            return(0);
          }
        }
      }
      if (value > alpha) {
        if(value >= beta) {
          HistoryRefutation(ply,depth,wtm);
          UnMakeMove(ply,current_move[ply],wtm);
          StoreRefutation(ply,depth,wtm,beta);
          return(beta);
        }
        alpha=value;
      }
    }
    UnMakeMove(ply,current_move[ply],wtm);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   all moves have been searched.  if none were legal,     |
|   return either MATE or DRAW depending on whether the    |
|   side to move is in check or not.                       |
|                                                          |
 ----------------------------------------------------------
*/
  if (first_move == 1) {
    value=(Check(wtm)) ? -(MATE-ply) :
                         ((wtm==root_wtm) ? DrawScore() : -DrawScore());
    if(value > beta) value=beta;
    else if (value < alpha) value=alpha;
    if (value >=alpha && value <beta) {
      SavePV(ply,value,0);
#if !defined(FAST)
      if (ply <= trace_level) printf("Search() no moves!  ply=%d\n",ply);
#endif
    }
    return(value);
  }
  else {
    if (alpha != initial_alpha) {
      memcpy(&pv[ply-1].path[ply],&pv[ply].path[ply],(pv[ply].path_length-ply+1)*4);
      memcpy(&pv[ply-1].path_hashed,&pv[ply].path_hashed,3);
      pv[ply-1].path[ply-1]=current_move[ply-1];
      HistoryBest(ply,depth,wtm);
    }
    StoreBest(ply,depth,wtm,alpha,initial_alpha);
/*
 ----------------------------------------------------------
|                                                          |
|   if the 50-move rule is drawing close, then adjust the  |
|   score to reflect the impending draw.                   |
|                                                          |
 ----------------------------------------------------------
*/
    if (Rule50Moves(ply) > 99) {
      value=(wtm==root_wtm) ? DrawScore() : -DrawScore();
      if (value < beta) SavePV(ply,value,0);
#if !defined(FAST)
      if(ply <= trace_level) printf("draw by 50-move rule detected, ply=%d.\n",ply);
#endif
      return(value);
    }
    return(alpha);
  }
}
Example #5
0
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc1;
	HDC hdc2;

	int iSpeed = 500;
	static int ** field_array;

	RECT rcClientRect;

	rcClientRect.top = 20;
	rcClientRect.left = 200;
	rcClientRect.bottom = rcClientRect.top + 25 * Rows;
	rcClientRect.right = rcClientRect.left + 25 * Columns;

	switch (message)
	{

	case WM_CREATE:
		{
			field_array = new int*[Rows];
			for (int i = 0; i < Rows; i++)
			{
				field_array[i] = new int[Columns];
				for (int j = 0; j < Columns; j++)
				{
					field_array[i][j] = 0;
				}
			}

			field_array[0][0] = 1;

			SetTimer(hWnd, ID_TIMER, iSpeed, NULL);
		}
		break;

	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		
		switch (wmId)
		{
			case IDM_ABOUT:
				DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
				break;

			case IDM_EXIT:
				DestroyWindow(hWnd);
				break;

			default:
				return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;

	case WM_TIMER:

		NextMove(field_array);

		InvalidateRect(hWnd, &rcClientRect, true);

		break;

	case WM_PAINT:
		//hdc2 = GetDC(hWnd);

		hdc1 = BeginPaint(hWnd, &ps);
		DrawSquare(hdc1, rcClientRect, field_array);
		EndPaint(hWnd, &ps);
		break;


	case WM_DESTROY:
		PostQuitMessage(0);
		break;


	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
// the window callback function 
// which we passed a pointer to on the CreateMasterX method, this callback function contains a variable called
// msg that we switch and have different case 's for different messages windows sends are program
// like the WM_DESTROY message, this is were we post the quit message to break the while loop
// that we initilized in the InitLoop method.
LRESULT APIENTRY WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
	case WM_DESTROY:// called when the window is destroyed
		PostQuitMessage(0);// breaks the while loop
		break;
	case WM_ACTIVATEAPP:
		mxhwnd.activeapp = wParam;// sets the app as active
		break;
	case WM_KEYDOWN:// is sent when a key is pressed
		{
			switch(wParam) // contains the key that was pressed
			{
			case VK_ESCAPE:// when the escape key is pressed
				{
					mxhwnd.Kill();// break the while loop
				}
				break;
			}

			switch(mxhwnd.GetScreen())
			{
			case ID_GAME:
				{
					switch(wParam)
					{
					case VK_RETURN:
						{
							mxhwnd.SetScreen(ID_ABOUT);
						}
						break;
					case VK_SPACE:
						{
							if(GameOver == true)// if the Game is Over then when they press space
							{                   // we wanna Clear the Board, Initilize the Players
								ClearBoard();   // and set GameOver to false
								InitPlayers();
								GameOver = false;
							}
						}
						break;
					}

				}
				break;
			case ID_ABOUT:
				{
					switch(wParam)
					{
					case VK_SPACE:
					case VK_RETURN:
						{
							mxhwnd.SetScreen(ID_GAME);
						}
						break;
					}
				}
				break;
			}

		}
		break;
	case WM_LBUTTONDOWN:// the WM_LBUTTONDOWN, when the left mouse button is clicked
		{
			int x = LOWORD(lParam), y = HIWORD(lParam);

			if(GameOver == false)
			{


			// a if statement to check and see if they clicked within a rectangle
			// if they did then set the Board[0][0] to the Player thats turn it is
			if(x > 50 && x < 160 && y > 130 && y < 200)
			{
				// switch of the Player thats turn it is
				switch(Player)
				{
				case 1:
					{
						if(Board[0][0] == EMPTY)
						{
						Board[0][0] = Player1; // set Board[0][0] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[0][0] == EMPTY)
						{
						Board[0][0] = Player2;// set Board[0][0] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}
			}

			// a if statement to check and see if they clicked within a rectangle
			// if they did then set Board[0][1] to Player thats turn it is
			if(x > 175 && x < 440 && y > 100 && y < 200)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[0][1] == EMPTY)
						{
						Board[0][1] = Player1;// set Board[0][1] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[0][1] == EMPTY)
						{
						Board[0][1] = Player2;// set Board[0][1] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}


			// a if statement to see if they clicked within a specific rectangle
			// this rectangle is the upper left hand corner of the screen
			// and is were Board[0][2] is drawn 
			if(x > 460 && x < 580 && y > 100 && y < 200)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[0][2] == EMPTY)
						{
						Board[0][2] = Player1;// set Board[0][2] to Player1's value
						NextMove(); // do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[0][2] == EMPTY)
						{
						Board[0][2] = Player2;// set Board[0][2] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}
			}

			// a if statement to see if they clicked within a rectangle
			// its checking to see if they clicked in the the right middle 
			if(x > 50 && x < 160 && y > 215 && y < 335)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[1][0] == EMPTY)
						{
						Board[1][0] = Player1;// set Board[1][0] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[1][0] == EMPTY)
						{
						Board[1][0] = Player2;// set Board[1][0] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}

			// a if statement to see if they clicked within a rectangle
			// the rectangle is the center of the screen the center sqaure
			if(x > 175 && x < 445 && y > 220 && y < 335)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[1][1] == EMPTY)
						{
						Board[1][1] = Player1;// set Board[1][1] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[1][1] == EMPTY)
						{
						Board[1][1] = Player2;// set Board[1][1] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}

			// a if statement to see if they clicked within a rectangle
			// the rectangle is near the middle right of the screen
			if(x > 450 && x < 585 && y > 220 && y < 335)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[1][2] == EMPTY)
						{
						Board[1][2] = Player1;// set Board[1][2] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[1][2] == EMPTY)
						{
						Board[1][2] = Player2;// set Board[1][2] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}


			}

			// a if statment to see if they clicked within a rectangle
			// the rectangle is near the lower left hand corner of the screen
			if(x > 50 && x < 160 && y > 350 && y < 445)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[2][0] == EMPTY)
						{
						Board[2][0] = Player1;// set Board[2][0] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[2][0] == EMPTY)
						{
						Board[2][0] = Player2;// set Board[2][0] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}

			// a if statement to see if they clicked within a rectangle
			// the rectangle is near the bottom middle of the screen
			if(x > 175 && x < 445 && y > 350 && y < 430)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[2][1] == EMPTY)
						{
						Board[2][1] = Player1;//set Board[2][1] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[2][1] == EMPTY)
						{
						Board[2][1] = Player2;// set Board[2][1] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}

			// a if statement to see if they clicked within a rectangle
			// this is to see if they clicked the square in the bottom right hand corner
			if(x > 450 && x < 585 && y > 350 && y < 445)
			{
				switch(Player)
				{
				case 1:
					{
						if(Board[2][2] == EMPTY)
						{
						Board[2][2] = Player1;// set Board[2][2] to Player1's value
						NextMove();// do the NextMove
						}
					}
					break;
				case 2:
					{
						if(Board[2][2] == EMPTY)
						{
						Board[2][2] = Player2;// set Board[2][2] to Player2's value
						NextMove();// do the NextMove
						}
					}
					break;
				}

			}

			}

		}
		break;
	default:
		return DefWindowProc(hwnd,msg,wParam,lParam);// call the default window proccess
	}
	return (0);
}
int QuiesceFlee(POS *p, int ply, int alpha, int beta, int *pv) {

  int best, score, move, new_pv[MAX_PLY];
  int fl_check, mv_type;
  int is_pv = (beta > alpha + 1);

  MOVES m[1];
  UNDO u[1];

  // Periodically check for timeout, ponderhit or stop command

  nodes++;
  CheckTimeout();

  // Quick exit on a timeout or on a statically detected draw

  if (abort_search) return 0;
  if (ply) *pv = 0;
  if (IsDraw(p) ) return DrawScore(p);

  // Retrieving data from transposition table. We hope for a cutoff
  // or at least for a move to improve move ordering.

  move = 0;
  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, 0, ply))
    return score;

  // Safeguard against exceeding ply limit

  if (ply >= MAX_PLY - 1)
    return Eval.Return(p, 1);

  // Are we in check? Knowing that is useful when it comes 
  // to pruning/reduction decisions

  fl_check = InCheck(p);

  // Init moves and variables before entering main loop

  best = -INF;
  InitMoves(p, m, move, -1, ply);

  // Main loop

  while ((move = NextMove(m, &mv_type))) {
    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }
    
    score = -Quiesce(p, ply, -beta, -alpha, new_pv);

    
    p->UndoMove(move, u);
    if (abort_search) return 0;

    // Beta cutoff

    if (score >= beta) {
      TransStore(p->hash_key, move, score, LOWER, 0, ply);
      return score;
    }

    // Updating score and alpha

    if (score > best) {
      best = score;
      if (score > alpha) {
        alpha = score;
        BuildPv(pv, new_pv, move);
      }
    }

  } // end of the main loop

  // Return correct checkmate/stalemate score

  if (best == -INF)
    return InCheck(p) ? -MATE + ply : DrawScore(p);

  // Save score in the transposition table

  if (*pv) TransStore(p->hash_key, *pv, best, EXACT, 0, ply);
  else     TransStore(p->hash_key, 0, best, UPPER, 0, ply);

  return best;
}
Example #8
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;
}
int Search(POS *p, int ply, int alpha, int beta, int depth, int was_null, int last_move, int last_capt_sq, int *pv) {

  int best, score, null_score, move, new_depth, new_pv[MAX_PLY];
  int fl_check, fl_prunable_node, fl_prunable_move, mv_type, reduction;
  int is_pv = (beta > alpha + 1);
  int mv_tried = 0, quiet_tried = 0, fl_futility = 0;

  int mv_played[MAX_MOVES];
  int mv_hist_score;
  int victim, last_capt;

  MOVES m[1];
  UNDO u[1];

  assert(ply > 0);

  // Quiescence search entry point

  if (depth <= 0)
    return QuiesceChecks(p, ply, alpha, beta, pv);

  // Periodically check for timeout, ponderhit or stop command

  nodes++;
  CheckTimeout();

  // Quick exit on a timeout or on a statically detected draw
  
  if (abort_search) return 0;
  if (ply) *pv = 0;
  if (IsDraw(p)) return DrawScore(p);

  // Mate distance pruning

  int checkmatingScore = MATE - ply;
  if (checkmatingScore < beta) {
    beta = checkmatingScore;
    if (alpha >= checkmatingScore)
    return alpha;
  }

  int checkmatedScore = -MATE + ply;
  if (checkmatedScore > alpha) {
    alpha = checkmatedScore;
    if (beta <= checkmatedScore)
    return beta;
  }

  // Retrieving data from transposition table. We hope for a cutoff
  // or at least for a move to improve move ordering.

  move = 0;
  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply)) {
    
    // For move ordering purposes, a cutoff from hash is treated
    // exactly like a cutoff from search

    if (score >= beta) UpdateHistory(p, last_move, move, depth, ply);

    // In pv nodes only exact scores are returned. This is done because
    // there is much more pruning and reductions in zero-window nodes,
    // so retrieving such scores in pv nodes works like retrieving scores
    // from slightly lower depth.

    if (!is_pv || (score > alpha && score < beta))
      return score;
  }

  // Safeguard against exceeding ply limit
  
  if (ply >= MAX_PLY - 1)
    return Eval.Return(p, 1);

  // Are we in check? Knowing that is useful when it comes 
  // to pruning/reduction decisions

  fl_check = InCheck(p);

  // INTERNAL ITERATIVE DEEPENING - we try to get a hash move to improve move ordering

  if (!move && is_pv && depth >= 6 && !fl_check) {
    Search(p, ply, alpha, beta, depth - 2, 0, 0, -1, new_pv);
    if (abort_search) return 0;
    TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply);
  }

  // Can we prune this node?

  fl_prunable_node = !fl_check 
                   && !is_pv 
                   && alpha > -MAX_EVAL
                   && beta < MAX_EVAL;

  // Beta pruning / static null move

  if (use_beta_pruning
  && fl_prunable_node
  && depth <= 3
  && !was_null) {
    int sc = Eval.Return(p, 1) - 120 * depth; // TODO: Tune me!
    if (sc > beta) return sc;
  }

  // Null move

  if (use_nullmove
  && fl_prunable_node
  && depth > 1
  && !was_null
  && MayNull(p)
  ) {
    int eval = Eval.Return(p, 1);
    if (eval > beta) {

      new_depth = depth - ((823 + 67 * depth) / 256); // simplified Stockfish formula

      // omit null move search if normal search to the same depth wouldn't exceed beta
      // (sometimes we can check it for free via hash table)

      if (TransRetrieve(p->hash_key, &move, &null_score, alpha, beta, new_depth, ply)) {
        if (null_score < beta) goto avoid_null;
      }

      p->DoNull(u);
      if (new_depth > 0) score = -Search(p, ply + 1, -beta, -beta + 1, new_depth, 1, 0, -1, new_pv);
      else               score = -QuiesceChecks(p, ply + 1, -beta, -beta + 1, new_pv);
      p->UndoNull(u);

      // Verification search (nb. immediate null move within it is prohibited)

      if (new_depth > 6 && score >= beta && use_null_verification)
         score = Search(p, ply, alpha, beta, new_depth - 5, 1, move, -1, new_pv);

      if (abort_search ) return 0;
      if (score >= beta) return score;
    }
  } 
  
  avoid_null:

  // end of null move code

  // Razoring based on Toga II 3.0

  if (use_razoring
  && fl_prunable_node
  && !move
  && !was_null
  && !(p->Pawns(p->side) & bbRelRank[p->side][RANK_7]) // no pawns to promote in one move
  && depth <= 3) {
    int threshold = beta - razor_margin[depth];
    int eval = Eval.Return(p, 1);

    if (eval < threshold) {
      score = QuiesceChecks(p, ply, alpha, beta, pv);
      if (score < threshold) return score;
    }
  }

  // end of razoring code 

  // Init moves and variables before entering main loop
  
  best = -INF;
  InitMoves(p, m, move, Refutation(last_move), ply);
  
  // Main loop
  
  while ((move = NextMove(m, &mv_type))) {

    // Gather data about the move

    mv_hist_score = history[p->pc[Fsq(move)]][Tsq(move)];
	victim = TpOnSq(p, Tsq(move));
	if (victim != NO_TP) last_capt = Tsq(move);
	else last_capt = -1;

    // Set futility pruning flag before the first applicable move is tried

    if (mv_type == MV_NORMAL && quiet_tried == 0) {
      if (use_futility
      && fl_prunable_node
      && depth <= 6) {
        if (Eval.Return(p, 1) + fut_margin[depth] < beta) fl_futility = 1;
      }
    }

    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }

  // Update move statistics 
  // (needed for reduction/pruning decisions and for updating history score)

  mv_played[mv_tried] = move;
  mv_tried++;
  if (mv_type == MV_NORMAL) quiet_tried++;

  // Can we prune this move?

  fl_prunable_move = !InCheck(p)
                  && (mv_type == MV_NORMAL)
                  && (mv_hist_score < hist_limit);

  // Set new search depth

  new_depth = depth - 1;

  // Check extension (pv node or low depth)

  if (is_pv || depth < 9) {
	  new_depth += InCheck(p);
	  if (is_pv && Tsq(move) == last_capt_sq) new_depth += 1;
  }

  // Futility pruning

  if (fl_futility
  &&  fl_prunable_move
  &&  mv_tried > 1) {
    p->UndoMove(move, u); continue;
  }

  // Late move pruning

  if (use_lmp
  && fl_prunable_node
  && fl_prunable_move
  && quiet_tried > lmp_limit[depth]
  && depth <= 3
  && MoveType(move) != CASTLE ) {
    p->UndoMove(move, u); continue;
  }

  // Late move reduction

  reduction = 0;

  if (use_lmr 
  && depth >= 2
  && mv_tried > 3
  && alpha > -MAX_EVAL && beta < MAX_EVAL
  && !fl_check 
  &&  fl_prunable_move
  && lmr_size[is_pv][depth][mv_tried] > 0
  && MoveType(move) != CASTLE ) {
    
    // read reduction size from the table

    reduction = lmr_size[is_pv][depth][mv_tried];

    // increase reduction on bad history score

    if (mv_hist_score < 0
    && new_depth - reduction > 2
    && lmr_hist_adjustement)
       reduction++;

    // reduce search depth

    new_depth -= reduction;
  }

  // a place to come back if reduction looks suspect

  re_search:
   
  // PVS

  if (best == -INF)
    score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  else {
    score = -Search(p, ply + 1, -alpha - 1, -alpha, new_depth, 0, move, last_capt, new_pv);
    if (!abort_search && score > alpha && score < beta)
      score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  }

  // Reduced move scored above alpha - we need to re-search it

  if (reduction
  && score > alpha) {
    new_depth += reduction;
    reduction = 0;
    goto re_search;
  }

  // Undo move

  p->UndoMove(move, u);
  if (abort_search) return 0;

  // Beta cutoff

    if (score >= beta) {
      if (!fl_check) {
        UpdateHistory(p, last_move, move, depth, ply);
        for (int mv = 0; mv < mv_tried; mv++)
          DecreaseHistory(p, mv_played[mv], depth);
      }
      TransStore(p->hash_key, move, score, LOWER, depth, ply);

      return score;
    }

  // Updating score and alpha

    if (score > best) {
      best = score;
      if (score > alpha) {
        alpha = score;
        BuildPv(pv, new_pv, move);
      }
    }

  } // end of the main loop

  // Return correct checkmate/stalemate score

  if (best == -INF)
    return InCheck(p) ? -MATE + ply : DrawScore(p);

  // Save score in the transposition table

  if (*pv) {
    if (!fl_check) {
      UpdateHistory(p, last_move, *pv, depth, ply);
      for (int mv = 0; mv < mv_tried; mv++)
        DecreaseHistory(p, mv_played[mv], depth);
    }
    TransStore(p->hash_key, *pv, best, EXACT, depth, ply);
  } else
    TransStore(p->hash_key, 0, best, UPPER, depth, ply);

  return best;
}
Example #10
0
int SearchRoot(POS *p, int ply, int alpha, int beta, int depth, int *pv) {

  int best, score, move, new_depth, new_pv[MAX_PLY];
  int fl_check, fl_prunable_move, mv_type, reduction;
  int mv_tried = 0, quiet_tried = 0;
  int mv_played[MAX_MOVES];
  int mv_hist_score;
  int victim, last_capt;
  int move_change = 0;
  
  fl_has_choice = 0;
  
  MOVES m[1];
  UNDO u[1];

  // Periodically check for timeout, ponderhit or stop command

  nodes++;
  CheckTimeout();

  // Quick exit
  
  if (abort_search) return 0;

  // Retrieving data from transposition table. We hope for a cutoff
  // or at least for a move to improve move ordering.

  move = 0;
  if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, depth, ply)) {
    
    // For move ordering purposes, a cutoff from hash is treated
    // exactly like a cutoff from search

    if (score >= beta) UpdateHistory(p, -1, move, depth, ply);

    // Root node is a pv node, so we return only exact scores

    if (score > alpha && score < beta)
      return score;
  }
  
  // Are we in check? Knowing that is useful when it comes 
  // to pruning/reduction decisions

  fl_check = InCheck(p);

  // Init moves and variables before entering main loop
  
  best = -INF;
  InitMoves(p, m, move, Refutation(-1), ply);
  
  // Main loop
  
  while ((move = NextMove(m, &mv_type))) {

    mv_hist_score = history[p->pc[Fsq(move)]][Tsq(move)];
	victim = TpOnSq(p, Tsq(move));
	if (victim != NO_TP) last_capt = Tsq(move);
	else last_capt = -1;

    p->DoMove(move, u);
    if (Illegal(p)) { p->UndoMove(move, u); continue; }

    // Update move statistics (needed for reduction/pruning decisions)

    mv_played[mv_tried] = move;
    mv_tried++;
    if (mv_tried > 1) fl_has_choice = 1; // we have a choice between at least two root moves
    if (depth > 16 && verbose) DisplayCurrmove(move, mv_tried);
    if (mv_type == MV_NORMAL) quiet_tried++;
    fl_prunable_move = !InCheck(p) && (mv_type == MV_NORMAL);

    // Set new search depth

    new_depth = depth - 1 + InCheck(p);

    // Late move reduction
  
    reduction = 0;
  
    if (use_lmr
    && depth >= 2
    && mv_tried > 3
    && mv_hist_score < hist_limit
    && alpha > -MAX_EVAL && beta < MAX_EVAL
    && !fl_check 
    &&  fl_prunable_move
    && lmr_size[1][depth][mv_tried] > 0
    && MoveType(move) != CASTLE ) {

    reduction = lmr_size[1][depth][mv_tried];

    // increase reduction on bad history score

    if (mv_hist_score < 0 
    && new_depth - reduction > 2 
    && lmr_hist_adjustement) 
       reduction++;

    new_depth -= reduction;
  }

  re_search:
   
  // PVS

  if (best == -INF)
    score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  else {
    score = -Search(p, ply + 1, -alpha - 1, -alpha, new_depth, 0, move, last_capt, new_pv);
    if (!abort_search && score > alpha && score < beta)
      score = -Search(p, ply + 1, -beta, -alpha, new_depth, 0, move, last_capt, new_pv);
  }

  // Reduced move scored above alpha - we need to re-search it

  if (reduction && score > alpha) {
    new_depth += reduction;
    reduction = 0;
    goto re_search;
  }

    p->UndoMove(move, u);
    if (abort_search) return 0;

  // Beta cutoff

    if (score >= beta) {
      if (!fl_check) {
        UpdateHistory(p, -1, move, depth, ply);
        for (int mv = 0; mv < mv_tried; mv++)
          DecreaseHistory(p, mv_played[mv], depth);
      }
      TransStore(p->hash_key, move, score, LOWER, depth, ply);

      // Update search time depending on whether the first move has changed

      if (depth > 4) {
        if (pv[0] != move) Timer.OnNewRootMove();
        else               Timer.OnOldRootMove();
      }

	  // Change the best move and show the new pv

      BuildPv(pv, new_pv, move);
      DisplayPv(score, pv);

      return score;
    }

    // Updating score and alpha

    if (score > best) {
      best = score;

      if (score > alpha) {
        alpha = score;

        // Update search time depending on whether the first move has changed

        if (depth > 4) {
          if (pv[0] != move) Timer.OnNewRootMove();
          else               Timer.OnOldRootMove();
        }

	    // Change the best move and show the new pv

        BuildPv(pv, new_pv, move);
        DisplayPv(score, pv);
      }
    }

  } // end of the main loop

  // Return correct checkmate/stalemate score

  if (best == -INF)
    return InCheck(p) ? -MATE + ply : DrawScore(p);

  // Save score in the transposition table

  if (*pv) {
    if (!fl_check) {
      UpdateHistory(p, -1, *pv, depth, ply);
      for (int mv = 0; mv < mv_tried; mv++)
        DecreaseHistory(p, mv_played[mv], depth);
    }
    TransStore(p->hash_key, *pv, best, EXACT, depth, ply);
    
  } else
    TransStore(p->hash_key, 0, best, UPPER, depth, ply);

  return best;
}