Пример #1
0
Move Board::think()
{
  
  //     ===========================================================================
  //  This is the entry point for search, it is intended to drive iterative deepening
  //  The search stops if (whatever comes first):
  //  - there is no legal move (checkmate or stalemate)
  //  - there is only one legal move (in this case we don't need to search)
  //  **later** - time is up
  //  - the search is interrupted by the user, or by winboard
  //  - the search depth is reached
  //     ===========================================================================
  
  int score, legalmoves, currentdepth;
  Move singlemove;
  
  //     ===========================================================================
  //     Check if the game has ended, or if there is only one legal move,
  //  because then we don't need to search:
  //     ===========================================================================
  if (isEndOfgame(legalmoves, singlemove)) return NOMOVE;
  if (legalmoves == 1)
  {
    std::cout << "forced move: "; displayMove(singlemove); std::cout << std::endl;
    return singlemove;
  }
  
  //     ===========================================================================
  //     There is more than legal 1 move, so prepare to search:
  //     ===========================================================================
  lastPVLength = 0;
  memset(lastPV, 0 , sizeof(lastPV));
  memset(whiteHeuristics, 0, sizeof(whiteHeuristics));
  memset(blackHeuristics, 0, sizeof(blackHeuristics));
  inodes = 0;
  // display console header
  displaySearchStats(1, 0, 0); 
  timer.init();
  msStart = timer.getms();
  
  //  iterative deepening:
  for (currentdepth = 1; currentdepth <= searchDepth; currentdepth++)
  {
    //  clear the buffers:
    memset(moveBufLen, 0, sizeof(moveBufLen));
    memset(moveBuffer, 0, sizeof(moveBuffer));
    memset(triangularLength, 0, sizeof(triangularLength));
    memset(triangularArray, 0, sizeof(triangularArray));
    followpv = true;
    score = alphabetapvs(0, currentdepth, -LARGE_NUMBER, LARGE_NUMBER);
    msStop = timer.getms();
    displaySearchStats(2, currentdepth, score);
    // stop searching if the current depth leads to a forced mate:
    if ((score > (CHECKMATESCORE-currentdepth)) || (score < -(CHECKMATESCORE-currentdepth)))
      currentdepth = searchDepth;
  }
  return (lastPV[0]);
}
Пример #2
0
int Board::alphabeta(int ply, int depth, int alpha, int beta)
{
  // Negascout
  
  int i, j, val;
  
  triangularLength[ply] = ply;
  if (depth == 0) return board.eval();
  
  moveBufLen[ply+1] = movegen(moveBufLen[ply]);
  for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++)
  {
    makeMove(moveBuffer[i]);
    {
      if (!isOtherKingAttacked())
      {
        inodes++;
        if (!ply) displaySearchStats(3, ply, i);
        val = -alphabeta(ply+1, depth-1, -beta, -alpha);
        unmakeMove(moveBuffer[i]);
        if (val >= beta)
        {
          return beta;
        }
        if (val > alpha)
        {
          alpha = val;                                                                              // both sides want to maximize from *their* perspective
          triangularArray[ply][ply] = moveBuffer[i];                                  // save this move
          for (j = ply + 1; j < triangularLength[ply + 1]; j++)
          {
            triangularArray[ply][j] = triangularArray[ply+1][j];   // and append the latest best PV from deeper plies
          }
          triangularLength[ply] = triangularLength[ply + 1];
          if (!ply)
          {
            msStop = timer.getms();
            displaySearchStats(2, depth, val);
          }
        }
      }
      else unmakeMove(moveBuffer[i]);
    }
  }
  return alpha;
}
Пример #3
0
int Board::minimax(int ply, int depth)
{
  // Negamax
  
  int i, j, val, best;
  best = -LARGE_NUMBER;
  triangularLength[ply] = ply;
  if (depth == 0) return board.eval();
  moveBufLen[ply+1] = movegen(moveBufLen[ply]);
  for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++)
  {
    makeMove(moveBuffer[i]);
    {
      if (!isOtherKingAttacked())
      {
        inodes++;
        if (!ply) displaySearchStats(3, ply, i);
        val = -minimax(ply+1, depth-1);                                 // note the minus sign
        unmakeMove(moveBuffer[i]);
        if (val > best)                                                 // both sides want to maximize from *their* perspective
        {
          best = val;
          triangularArray[ply][ply] = moveBuffer[i];                                  // save this move
          for (j = ply + 1; j < triangularLength[ply + 1]; j++)
          {
            triangularArray[ply][j] = triangularArray[ply+1][j];   // and append the latest best PV from deeper plies
          }
          triangularLength[ply] = triangularLength[ply + 1];
          if (!ply)
          {
            msStop = timer.getms();
            displaySearchStats(2, depth, val);
          }
        }
      }
      else unmakeMove(moveBuffer[i]);
    }
  }
  return best;
}
Пример #4
0
int Board::alphabetapvs(int ply, int depth, int alpha, int beta)
{
  // PV search
  
  int i, j, movesfound, pvmovesfound, val;
  triangularLength[ply] = ply;
  if (depth == 0)
  {
    followpv = false;
    return qsearch(ply, alpha, beta);
  }
  
  // repetition check:
  if (repetitionCount() >= 3) return DRAWSCORE;
  movesfound = 0;
  pvmovesfound = 0;
  moveBufLen[ply+1] = movegen(moveBufLen[ply]);
  for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++)
  {
    selectmove(ply, i, depth, followpv);
    makeMove(moveBuffer[i]);
    {
      if (!isOtherKingAttacked())
      {
        inodes++;
        movesfound++;
        if (!ply) displaySearchStats(3, ply, i);
        if (pvmovesfound)
        {
          val = -alphabetapvs(ply+1, depth-1, -alpha-1, -alpha);
          if ((val > alpha) && (val < beta))
          {
            // in case of failure, proceed with normal alphabeta
            val = -alphabetapvs(ply+1, depth - 1, -beta, -alpha);                        
          }
        }
        // normal alphabeta
        else val = -alphabetapvs(ply+1, depth-1, -beta, -alpha);         
        unmakeMove(moveBuffer[i]);
        if (val >= beta)
        {
          // update the history heuristic
          if (nextMove)
            blackHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth;
          else
            whiteHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth;
          return beta;
        }
        if (val > alpha)
        {
          alpha = val;                                                      // both sides want to maximize from *their* perspective
          pvmovesfound++;
          triangularArray[ply][ply] = moveBuffer[i];                                  // save this move
          for (j = ply + 1; j < triangularLength[ply+1]; j++)
          {
            triangularArray[ply][j] = triangularArray[ply+1][j];   // and append the latest best PV from deeper plies
          }
          triangularLength[ply] = triangularLength[ply+1];
          if (!ply)
          {
            msStop = timer.getms();
            displaySearchStats(2, depth, val);
          }
        }
      }
      else unmakeMove(moveBuffer[i]);
    }
  }
  
  // update the history heuristic
  if (pvmovesfound)
  {
    if (nextMove)
      blackHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth;
    else
      whiteHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth;
  }
  
  //     50-move rule:
  if (fiftyMove >= 100) return DRAWSCORE;
  
  //     Checkmate/stalemate detection:
  if (!movesfound)
  {
    if (isOwnKingAttacked())  return (-CHECKMATESCORE+ply-1);
    else  return (STALEMATESCORE);
  }
  
  return alpha;
}
Пример #5
0
Move Board::think()
{

//	===========================================================================
//  This is the entry point for search, it is intended to drive iterative deepening 
//  The search stops if (whatever comes first): 
//  - there is no legal move (checkmate or stalemate)
//  - there is only one legal move (in this case we don't need to search)
//  - time is up 
//  - the search is interrupted by the user, or by winboard
//  - the search depth is reached
//	===========================================================================

	int score, legalmoves, currentdepth;
	Move singlemove;

	lastScore = 0;

//	===========================================================================
//	Check if the game has ended, or if there is only one legal move,
//  because then we don't need to search:
//	===========================================================================
	if (isEndOfgame(legalmoves, singlemove)) return NOMOVE;
	if (legalmoves == 1) 
	{
		//LC std::cout << "forced move: "; displayMove(singlemove); std::cout << std::endl; 
		/*if (XB_MODE && XB_POST) 
		{
			printf("0 0 0 0 "); 
			displayMove(singlemove);
			std::cout << std::endl;
		}*/
		return singlemove;
	}

//	===========================================================================
//	There is more than legal 1 move, so prepare to search:
//	===========================================================================
	if (XB_MODE) timeControl();
	lastPVLength = 0;
	memset(lastPV, 0 , sizeof(lastPV));
	memset(whiteHeuristics, 0, sizeof(whiteHeuristics));
	memset(blackHeuristics, 0, sizeof(blackHeuristics));
	inodes = 0;
	countdown = UPDATEINTERVAL;
	timedout = false;
	// display console header
	displaySearchStats(1, 0, 0);  
	timer.init();
	msStart = timer.getms();

	//  iterative deepening:
	for (currentdepth = 1; currentdepth <= searchDepth; currentdepth++)
	{
		//  clear the buffers:
		memset(moveBufLen, 0, sizeof(moveBufLen));
		memset(moveBuffer, 0, sizeof(moveBuffer));
		memset(triangularLength, 0, sizeof(triangularLength));
		memset(triangularArray, 0, sizeof(triangularArray));
		followpv = true;
		allownull = true;
		score = alphabetapvs(0, currentdepth, -LARGE_NUMBER, LARGE_NUMBER);
		lastScore = score;
		// now check if time is up
		// if not decide if it makes sense to start another iteration:
		if (timedout) 
		{
			//LC std::cout << std::endl;
			return (lastPV[0]);
		}
		else
		{
			if (!XB_NO_TIME_LIMIT)
			{
				msStop = timer.getms();
				if ((msStop - msStart) > (STOPFRAC * maxTime)) 
				{
					//if (!XB_MODE) std::cout << "    ok" << std::endl;
					return (lastPV[0]);
				}
			}
		}
		displaySearchStats(2, currentdepth, score);
		// stop searching if the current depth leads to a forced mate:
		if ((score > (CHECKMATESCORE-currentdepth)) || (score < -(CHECKMATESCORE-currentdepth))) 
			currentdepth = searchDepth;
	}
	return (lastPV[0]);
}
Пример #6
0
int Board::alphabetapvs(int ply, int depth, int alpha, int beta)
{
	// PV search

	int i, j, movesfound, pvmovesfound, val;

	triangularLength[ply] = ply;
	if (depth <= 0) 
	{
		followpv = false;
		return qsearch(ply, alpha, beta);
	}

	// repetition check:
	if (repetitionCount() >= 3) return DRAWSCORE;
	
	// now try a null move to get an early beta cut-off:
	if (!followpv && allownull)
	{
		if ((nextMove && (board.totalBlackPieces > NULLMOVE_LIMIT)) || (!nextMove && (board.totalWhitePieces > NULLMOVE_LIMIT)))
		{
			if (!isOwnKingAttacked())
			{
				allownull = false;
				inodes++;
				if (--countdown <=0) readClockAndInput();
				nextMove = !nextMove;
				hashkey ^= KEY.side; 
				val = -alphabetapvs(ply, depth - NULLMOVE_REDUCTION, -beta, -beta+1);
				nextMove = !nextMove;
				hashkey ^= KEY.side;
				if (timedout) return 0;
				allownull = true;
				if (val >= beta) return val;
			}
		}
	}
	allownull = true;

	movesfound = 0;
	pvmovesfound = 0;
	moveBufLen[ply+1] = movegen(moveBufLen[ply]);
	for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++)
	{
		selectmove(ply, i, depth, followpv); 
		makeMove(moveBuffer[i]);
		{
			if (!isOtherKingAttacked()) 
			{
				inodes++;
				if (--countdown <=0) readClockAndInput();
				movesfound++;
				if (!ply) displaySearchStats(3, ply, i); 
				if (pvmovesfound)
				{
					val = -alphabetapvs(ply+1, depth-1, -alpha-1, -alpha); 
		            if ((val > alpha) && (val < beta))
					{
						 // in case of failure, proceed with normal alphabeta
						val = -alphabetapvs(ply+1, depth - 1, -beta, -alpha);  		        
					}
				} 
				// normal alphabeta
	 			else val = -alphabetapvs(ply+1, depth-1, -beta, -alpha);	    
				unmakeMove(moveBuffer[i]);
				if (timedout) return 0;
				if (val >= beta)
				{
					// update the history heuristic
					if (nextMove) 
						blackHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth;
					else 
						whiteHeuristics[moveBuffer[i].getFrom()][moveBuffer[i].getTosq()] += depth*depth;
					return beta;
				}
				if (val > alpha)
				{
					alpha = val;								    // both sides want to maximize from *their* perspective
					pvmovesfound++;
					triangularArray[ply][ply] = moveBuffer[i];					// save this move
					for (j = ply + 1; j < triangularLength[ply+1]; j++) 
					{
						triangularArray[ply][j] = triangularArray[ply+1][j];	// and append the latest best PV from deeper plies
					}
					triangularLength[ply] = triangularLength[ply+1];
					if (!ply) displaySearchStats(2, depth, val);
				}
			}
			else unmakeMove(moveBuffer[i]);
		}
	}

	// update the history heuristic
	if (pvmovesfound)
	{
		if (nextMove) 
			blackHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth;
		else
			whiteHeuristics[triangularArray[ply][ply].getFrom()][triangularArray[ply][ply].getTosq()] += depth*depth;
	}

	//	50-move rule:
	if (fiftyMove >= 100) return DRAWSCORE;

	//	Checkmate/stalemate detection:
	if (!movesfound)
	{
		if (isOwnKingAttacked())  return (-CHECKMATESCORE+ply-1);
		else  return (STALEMATESCORE);
	}

	return alpha;
}