Example #1
0
char *PrMove(const int move) {

	static char MvStr[6];

	int ff = FilesBrd[FROMSQ(move)];
	int rf = RanksBrd[FROMSQ(move)];
	int ft = FilesBrd[TOSQ(move)];
	int rt = RanksBrd[TOSQ(move)];

	int promoted = PROMOTED(move);

	if (promoted) {
		char pchar = 'q';
		if (IsKn(promoted)) {
			pchar = 'n';
		}
		else if (IsRQ(promoted) && !IsBQ(promoted))  {
			pchar = 'r';
		}
		else if (!IsRQ(promoted) && IsBQ(promoted))  {
			pchar = 'b';
		}
		sprintf(MvStr, "%c%c%c%c%c", ('a' + ff), ('1' + rf), ('a' + ft), ('1' + rt), pchar);
	}
	else {
		sprintf(MvStr, "%c%c%c%c", ('a' + ff), ('1' + rf), ('a' + ft), ('1' + rt));
	}

	return MvStr;
}
Example #2
0
static void addcapturemove(const S_BOARD *pos,int move, S_MOVELIST *list)
{
  ASSERT(sqonboard(FROMSQ(move)));
  ASSERT(sqonboard(TOSQ(move)));
  ASSERT(piecevalid(CAPTURED(move)));
  
  list->moves[list->count].move = move;
  list->moves[list->count].score = MvvLvaScores[CAPTURED(move)][pos->pieces[FROMSQ(move)]]+1000000;
  list->count++;
}
Example #3
0
static void AddCaptureMove(const CHESS_BOARD *pos, int move, MOVELIST *list) {

	ASSERT(SqOnBoard(FROMSQ(move)));
	ASSERT(SqOnBoard(TOSQ(move)));
	ASSERT(PieceValid(CAPTURED(move)));
	ASSERT(CheckBoard(pos));

	list->moves[list->count].move = move;
	list->moves[list->count].score = MvvLvaScores[CAPTURED(move)][pos->pieces[FROMSQ(move)]] + 1000000;
	list->count++;
}
Example #4
0
void SortCaptures (int ply)
/***************************************************************************
 *
 *  Actually no sorting is done.  Just scores are assigned to the captures.
 *  When we need a move, we will select the highest score move from the
 *  list, place it at the top and try it.  This move might give us a cut
 *  in which case, there is no reason to sort.
 *  
 ***************************************************************************/
{
   leaf *p;
   int temp, f, t;

   for (p = TreePtr[ply]; p < TreePtr[ply+1]; p++)
   {
      f = Value[cboard[FROMSQ(p->move)]];
      t = Value[cboard[TOSQ(p->move)]];
      if (f < t)
         p->score = t - f;
      else
      {
         temp = SwapOff (p->move);
	 p->score = (temp < 0 ? -INFINITY : temp);
      }

   }
}
Example #5
0
static void addenpassantmove(const S_BOARD *pos,int move, S_MOVELIST *list)
{
  ASSERT(sqonboard(FROMSQ(move)));
  ASSERT(sqonboard(TOSQ(move)));
  
  list->moves[list->count].move = move;
  list->moves[list->count].score = 105+1000000;
  list->count++;
}
Example #6
0
static void AddQuietMove(const CHESS_BOARD *pos, int move, MOVELIST *list) {

	ASSERT(SqOnBoard(FROMSQ(move)));
	ASSERT(SqOnBoard(TOSQ(move)));
	ASSERT(CheckBoard(pos));
	ASSERT(pos->ply >= 0 && pos->ply < MAXDEPTH);

	list->moves[list->count].move = move;

	if (pos->searchKillers[0][pos->ply] == move) {
		list->moves[list->count].score = 900000;
	}
	else if (pos->searchKillers[1][pos->ply] == move) {
		list->moves[list->count].score = 800000;
	}
	else {
		list->moves[list->count].score = pos->searchHistory[pos->pieces[FROMSQ(move)]][TOSQ(move)];
	}
	list->count++;
}
Example #7
0
static void AddEnPassantMove(const CHESS_BOARD *pos, int move, MOVELIST *list) {

	ASSERT(SqOnBoard(FROMSQ(move)));
	ASSERT(SqOnBoard(TOSQ(move)));
	ASSERT(CheckBoard(pos));
	ASSERT((RanksBrd[TOSQ(move)] == RANK_6 && pos->side == WHITE) || (RanksBrd[TOSQ(move)] == RANK_3 && pos->side == BLACK));

	list->moves[list->count].move = move;
	list->moves[list->count].score = 105 + 1000000;
	list->count++;
}
Example #8
0
File: engine.c Project: adua/chess
/*
 * Extracts a command from the engine input buffer.
 * 
 * The command is removed from the buffer.
 * If the command is a move, the move is made.
 */
void NextEngineCmd( void )
{
  char engineinput[BUF_SIZE]="";
  char enginemovestr[BUF_SIZE]="";
  leaf* enginemove;
  
  if ( strlen( engineinputbuf ) > 0 ) {
    if ( GetNextLine( engineinputbuf, engineinput ) > 0 ) {
      dbg_printf("< ENGINE: %s\n", engineinput);
      if ( strncmp( engineinput, "move", 4 ) == 0 ) {
        /* Input from engine is a move */
        sscanf( engineinput, "move %s", enginemovestr );
        enginemove = ValidateMove( enginemovestr );
        if ( enginemove == (leaf *) NULL ) {
          dbg_printf( "Bad move from engine\n" );
        } else {
          dbg_printf( "Engine move: <%s> (%d,%d)\n", enginemovestr,
                      (enginemove!=NULL ? enginemove->move : -1), 
                      (enginemove!=NULL ? enginemove->score : -1) );
          SANMove (enginemove->move, 1);
          MakeMove( board.side, &(enginemove->move) );
          strcpy (Game[GameCnt].SANmv, SANmv);
	  if ( !(flags & XBOARD) ) {
		  //ShowBoard();
                  dbg_printf("USER <: My move is : %s\n", SANmv);
		  //printf( "\nMy move is : %s\n", SANmv );
		  printf( "\n<%i:%i>\n", FROMSQ(enginemove->move), TOSQ(enginemove->move) );
                  fflush( stdout );
	  } else {
                  dbg_printf("USER <: %d. ... %s\n", GameCnt/2 + 1, enginemovestr );
                  printf ("%d. ... %s\n", GameCnt/2 + 1, enginemovestr );
                  fflush( stdout );
                  dbg_printf("USER <: My move is : %s\n", enginemovestr);
		  printf( "My move is : %s\n", enginemovestr );
                  fflush( stdout );
          }
          RealGameCnt = GameCnt;
          showprompt = 1;
          /* Check if the color must be changed, e.g. after a go command. */
          if ( changeColor ) {
            RealGameCnt = GameCnt;
            RealSide = board.side;
          }
        }
      } else {
        dbg_printf( "USER <: %s\n",engineinput );
        printf( "%s", engineinput );
        if ( flags & XBOARD ) {
          fflush( stdout );
        }
      }
    }
  }
}
Example #9
0
static void AddQuietMove(const S_BOARD *pos, int move, S_MOVELIST *list) {
	list->moves[list->count].move = move;

	if(pos->searchKillers[0][pos->ply] == move) {
		list->moves[list->count].score = 900000;
	} else if(pos->searchKillers[1][pos->ply] == move) {
		list->moves[list->count].score = 800000;
	} else {
		list->moves[list->count].score = pos->searchHistory[pos->pieces[FROMSQ(move)]][TOSQ(move)];
	}
	list->count++;
}
Example #10
0
static void addquietmove(const S_BOARD *pos,int move, S_MOVELIST *list)
{
  ASSERT(sqonboard(FROMSQ(move)));
  ASSERT(sqonboard(TOSQ(move)));

  list->moves[list->count].move = move;
  
 if(pos->searchkillers[0][pos->ply]==move)
 {
  list->moves[list->count].score = 900000; 
 }
 else if(pos->searchkillers[1][pos->ply] == move)
 {
  list->moves[list->count].score = 800000; 
 }
 else
 {
  list->moves[list->count].score = pos->searchhistory[pos->pieces[FROMSQ(move)]][TOSQ(move)]; 
 }
  list->count++;
}
Example #11
0
void SortRoot (void)
/*****************************************************************************
 *
 *  Sort the moves at the root.  The heuristic is simple.  Try captures/
 *  promotions first.  Other moves are ordered based on their swapoff values.
 *
 *****************************************************************************/
{
   leaf *p;
   int f, t ;
   int side, xside;
   BitBoard enemyP;

   side = board.side;
   xside = 1^side;
   enemyP = board.b[xside][pawn];

   for (p = TreePtr[1]; p < TreePtr[2]; p++)
   {
      f = Value[cboard[FROMSQ(p->move)]];
      if (cboard[TOSQ(p->move)] != 0 || (p->move & PROMOTION))
      {
         t = Value[cboard[TOSQ(p->move)]];
         if (f < t)
            p->score = -1000 + t - f;
         else
            p->score = -1000 + SwapOff (p->move);
      }
      else 
         p->score = -3000 + SwapOff (p->move);

      p->score += taxicab[FROMSQ(p->move)][D5] - taxicab[TOSQ(p->move)][E4];

      if ( f == ValueP ) {
        /* Look at pushing Passed pawns first */
        if ( (enemyP & PassedPawnMask[side][TOSQ(p->move)]) == NULLBITBOARD )
           p->score +=50;
      } 
   }
}
Example #12
0
int ParseMove(char *ptrChar, CHESS_BOARD *pos) {

	ASSERT(CheckBoard(pos));

	if (ptrChar[1] > '8' || ptrChar[1] < '1') return NOMOVE;
	if (ptrChar[3] > '8' || ptrChar[3] < '1') return NOMOVE;
	if (ptrChar[0] > 'h' || ptrChar[0] < 'a') return NOMOVE;
	if (ptrChar[2] > 'h' || ptrChar[2] < 'a') return NOMOVE;

	int from = FR2SQ(ptrChar[0] - 'a', ptrChar[1] - '1');
	int to = FR2SQ(ptrChar[2] - 'a', ptrChar[3] - '1');

	ASSERT(SqOnBoard(from) && SqOnBoard(to));

	MOVELIST list[1];
	GenerateAllMoves(pos, list);
	int MoveNum = 0;
	int Move = 0;
	int PromPce = EMPTY;

	for (MoveNum = 0; MoveNum < list->count; ++MoveNum) {
		Move = list->moves[MoveNum].move;
		if (FROMSQ(Move) == from && TOSQ(Move) == to) {
			PromPce = PROMOTED(Move);
			if (PromPce != EMPTY) {
				if (IsRQ(PromPce) && !IsBQ(PromPce) && ptrChar[4] == 'r') {
					return Move;
				}
				else if (!IsRQ(PromPce) && IsBQ(PromPce) && ptrChar[4] == 'b') {
					return Move;
				}
				else if (IsRQ(PromPce) && IsBQ(PromPce) && ptrChar[4] == 'q') {
					return Move;
				}
				else if (IsKn(PromPce) && ptrChar[4] == 'n') {
					return Move;
				}
				continue;
			}
			return Move;
		}
	}

	return NOMOVE;
}
Example #13
0
inline const char *printMove(const unsigned move) {
  static char result[6];
  const unsigned from = FROMSQ(move);
  const unsigned to = TOSQ(move);
  ASSERT(squareOnBoard(to));
  if (move & MFLAGDROP) {
    result[0] = pieceChar[PROMOTED(move) % 6];
    result[1] = '@';
    result[2] = 'a' + fileBoard[to];
    result[3] = '1' + rankBoard[to];
    result[4] = 0;
  } else {
    ASSERT(squareOnBoard(from));
    result[0] = 'a' + fileBoard[from];
    result[1] = '1' + rankBoard[from];
    result[2] = 'a' + fileBoard[to];
    result[3] = '1' + rankBoard[to];
    result[4] = PROMOTED(move) ? "__nbrq__nbrq_"[PROMOTED(move)] : 0;
    result[5] = 0;
  }
  return result;
}
Example #14
0
int MoveListOk(const S_MOVELIST *list,  const S_BOARD *pos) {
	if(list->count < 0 || list->count >= MAXPOSITIONMOVES) {
		return FALSE;
	}

	int MoveNum;
	int from = 0;
	int to = 0;
	for(MoveNum = 0; MoveNum < list->count; ++MoveNum) {
		to = TOSQ(list->moves[MoveNum].move);
		from = FROMSQ(list->moves[MoveNum].move);
		if(!SqOnBoard(to) || !SqOnBoard(from)) {
			return FALSE;
		}
		if(!PieceValid(pos->pieces[from])) {
			PrintBoard(pos);
			return FALSE;
		}
	}

	return TRUE;
}
Example #15
0
void SortMoves (int ply)
/*****************************************************************************
 *
 *  Sort criteria is as follows.
 *  1.  The move from the hash table
 *  2.  Captures as above.
 *  3.  Killers.
 *  4.  History.
 *  5.  Moves to the centre.
 *
 *****************************************************************************/
{
   leaf *p;
   int f, t, m, tovalue;
   int side, xside;
   BitBoard enemyP;

   side = board.side;
   xside = 1^side;
   enemyP = board.b[xside][pawn];

   for (p = TreePtr[ply]; p < TreePtr[ply+1]; p++)
   {
      p->score = -INFINITY;
      f = FROMSQ (p->move);
      t = TOSQ (p->move);
      m = p->move & MOVEMASK;

      /* Hash table move (highest score) */
      if (m == Hashmv[ply])
         p->score += HASHSORTSCORE;

      else if (cboard[t] != 0 || p->move & PROMOTION)
      {

	/* ***** SRW My Interpretation of this code *************
           * Captures normally in other places but.....         *
           *                                                    *
           * On capture we generally prefer to capture with the *
	   * with the lowest value piece so to chose between    *
           * pieces we should subtract the piece value .... but *
           *                                                    *
           * The original code was looking at some captures     *
           * last, especially where the piece was worth more    *
           * than the piece captured - KP v K in endgame.epd    *
           *                                                    *
           * So code modified to prefer any capture by adding   *
           * ValueK                                             *
           ****************************************************** */

        tovalue = (Value[cboard[t]] + Value[PROMOTEPIECE (p->move)]);
        p->score += tovalue + ValueK - Value[cboard[f]];


      }
      /* Killers */
      else if (m == killer1[ply] || m == killer2[ply])
         p->score += KILLERSORTSCORE; 
      else if (ply > 2 && (m == killer1[ply-2] || m == killer2[ply-2]))
         p->score += KILLERSORTSCORE; 

      p->score += history[side][(p->move & 0x0FFF)] + taxicab[f][D5] - taxicab[t][E4];

      if ( cboard[f] == pawn ) {
        /* Look at pushing Passed pawns first */
        if ( (enemyP & PassedPawnMask[side][t]) == NULLBITBOARD )
           p->score +=50;
      } 
  }
}
Example #16
0
int PhasePick (leaf **p1, int ply)
/***************************************************************************
 *
 *  A phase style routine which returns the next move to the search.
 *  Hash move is first returned.  If it doesn't fail high, captures are
 *  generated, sorted and tried.  If no fail high still occur, the rest of
 *  the moves are generated and tried.
 *  The idea behind all this is to save time generating moves which might
 *  not be needed.
 *  CAVEAT: To implement this, the way that genmoves & friends are called
 *  have to be modified.  In particular, TreePtr[ply+1] = TreePtr[ply] must
 *  be set before the calls can be made.
 *  If the board ever gets corrupted during the search, then there is a bug
 *  in IsLegalMove() which has to be fixed.
 *
 ***************************************************************************/
{
   static leaf* p[MAXPLYDEPTH];
   leaf *p2;
   int mv;
   int side;

   side = board.side;
   switch (pickphase[ply])
   {
      case PICKHASH:
         TreePtr[ply+1] = TreePtr[ply];
         pickphase[ply] = PICKGEN1;
         if (Hashmv[ply] && IsLegalMove (Hashmv[ply]))
         {
            TreePtr[ply+1]->move = Hashmv[ply];
            *p1 = TreePtr[ply+1]++;
            return (true);
         }

      case PICKGEN1:
         pickphase[ply] = PICKCAPT;
         p[ply] = TreePtr[ply+1];
         GenCaptures (ply);
         for (p2 = p[ply]; p2 < TreePtr[ply+1]; p2++)
            p2->score = SwapOff(p2->move) * WEIGHT + 
				Value[cboard[TOSQ(p2->move)]];

      case PICKCAPT:
         while (p[ply] < TreePtr[ply+1])
         {
            pick (p[ply], ply);
            if ((p[ply]->move & MOVEMASK) == Hashmv[ply])
            {
	       p[ply]++;
	       continue;
            } 
            *p1 = p[ply]++;
            return (true);
         }

      case PICKKILL1:
         pickphase[ply] = PICKKILL2;
         if (killer1[ply] && killer1[ply] != Hashmv[ply] && 
				IsLegalMove (killer1[ply]))
         {
            TreePtr[ply+1]->move = killer1[ply];
            *p1 = TreePtr[ply+1];
            TreePtr[ply+1]++;
            return (true);
         }
         
      case PICKKILL2:
         pickphase[ply] = PICKGEN2;
         if (killer2[ply] && killer2[ply] != Hashmv[ply] && 
				IsLegalMove (killer2[ply]))
         {
            TreePtr[ply+1]->move = killer2[ply];
            *p1 = TreePtr[ply+1];
            TreePtr[ply+1]++;
            return (true);
         }

      case PICKGEN2:
         pickphase[ply] = PICKREST;
         p[ply] = TreePtr[ply+1];
         GenNonCaptures (ply);
         for (p2 = p[ply]; p2 < TreePtr[ply+1]; p2++)
	 {
            p2->score = history[side][(p2->move & 0x0FFF)] + 
		taxicab[FROMSQ(p2->move)][D5]  - taxicab[TOSQ(p2->move)][E4];
	    if (p2->move & CASTLING)
	       p2->score += CASTLINGSCORE;
         }
	 
      case PICKREST:
         while (p[ply] < TreePtr[ply+1])
         {
            pick (p[ply], ply);
            mv = p[ply]->move & MOVEMASK;
            if (mv == Hashmv[ply] || mv == killer1[ply] || 
		mv == killer2[ply])
	    {
	       p[ply]++;
               continue;
	    }
            *p1 = p[ply]++;
            return (true);
         }
   }
   return (false);
} 
Example #17
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);
}
Example #18
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);
}
Example #19
0
int SwapOff (int move)
/****************************************************************************
 *
 *  A Static Exchange Evaluator (or SEE for short).
 *  First determine the target square.  Create a bitboard of all squares
 *  attacking the target square for both sides.  Using these 2 bitboards,
 *  we take turn making captures from smallest piece to largest piece.
 *  When a sliding piece makes a capture, we check behind it to see if
 *  another attacker piece has been exposed.  If so, add this to the bitboard
 *  as well.  When performing the "captures", we stop if one side is ahead
 *  and doesn't need to capture, a form of pseudo-minimaxing.
 *
 ****************************************************************************/
{
   int f, t, sq, piece, lastval;
   int side, xside; 
   int swaplist[MAXPLYDEPTH], n;
   BitBoard b, c, *d, *e, r;

   f = FROMSQ (move);
   t = TOSQ (move);
   side = ((board.friends[white] & BitPosArray[f]) ? white : black);
   xside = 1^side;

   /*  Squares attacking t for side and xside  */
   b = AttackTo (t, side);
   c = AttackTo (t, xside);
   CLEARBIT(b, f);
   if (xray[cboard[f]])
      AddXrayPiece (t, f, side, &b, &c);

   d = board.b[side];
   e = board.b[xside]; 
   if (move & PROMOTION)
   {
      swaplist[0] = Value[PROMOTEPIECE (move)] - ValueP;
      lastval = -Value[PROMOTEPIECE (move)];
   }
   else
   {
      swaplist[0] = (move & ENPASSANT ? ValueP : Value[cboard[t]]);
      lastval = -Value[cboard[f]];
   }
   n = 1;
   while (1)
   {
      if (c == NULLBITBOARD)
         break;
      for (piece = pawn; piece <= king; piece++)
      {
         r = c & e[piece]; 
	 if (r)
         {
	    sq = leadz (r);
	    CLEARBIT (c, sq);
	    if (xray[piece])
	       AddXrayPiece (t, sq, xside, &c, &b);
	    swaplist[n] = swaplist[n-1] + lastval;
            n++;
	    lastval = Value[piece];
	    break;
         }
      }

      if (b == NULLBITBOARD)
         break;
      for (piece = pawn; piece <= king; piece++)
      {
         r = b & d[piece]; 
	 if (r)
         {
	    sq = leadz (r);
	    CLEARBIT (b, sq);
	    if (xray[piece])
	       AddXrayPiece (t, sq, side, &b, &c);
	    swaplist[n] = swaplist[n-1] + lastval;
            n++;
	    lastval = -Value[piece];
	    break;
         }
      }
   }

/****************************************************************************
 *
 *  At this stage, we have the swap scores in a list.  We just need to 
 *  mini-max the scores from the bottom up to the top of the list.
 *
 ****************************************************************************/
   --n;
   while (n)
   {
      if (n & 1)
      {
         if (swaplist[n] <= swaplist[n-1])
	    swaplist[n-1] = swaplist[n]; 
      }
      else
      {
         if (swaplist[n] >= swaplist[n-1])
	    swaplist[n-1] = swaplist[n]; 
      }
      --n;
   }
   return (swaplist[0]);
}
Example #20
0
static void AddCaptureMove(const S_BOARD *pos, int move, S_MOVELIST *list) {
	list->moves[list->count].move = move;
	list->moves[list->count].score = MvvLvaScores[CAPTURED(move)][pos->pieces[FROMSQ(move)]] + 1000000;
	list->count++;
}