Пример #1
0
int Board::qsearch(int ply, int alpha, int beta)
{
	// quiescence search 

	int i, j, val;

	if (timedout) return 0;
	triangularLength[ply] = ply;
	if (isOwnKingAttacked()) return alphabetapvs(ply, 1, alpha, beta);
	
	if(EVAL_FUNC == 0){
		val = board.eval();
	}else {
		val = board.evalJL(PARAM_EVAL_MATERIAL, PARAM_EVAL_ESPACIAL, PARAM_EVAL_DINAMICA, PARAM_EVAL_POS_TABLERO, ply);
	}

	if (val >= beta) return val;
	if (val > alpha) alpha = val;

	// generate captures & promotions:
	// captgen returns a sorted move list
	moveBufLen[ply+1] = captgen(moveBufLen[ply]);
	for (i = moveBufLen[ply]; i < moveBufLen[ply+1]; i++)
	{
		makeMove(moveBuffer[i]);
		{
			if (!isOtherKingAttacked()) 
			{
				inodes++;
				if (--countdown <=0) readClockAndInput();
				val = -qsearch(ply+1, -beta, -alpha);
				unmakeMove(moveBuffer[i]);
				if (val >= beta) return val;
				if (val > alpha)
				{
					alpha = val;
					triangularArray[ply][ply] = moveBuffer[i];
					for (j = ply + 1; j < triangularLength[ply+1]; j++) 
					{
						triangularArray[ply][j] = triangularArray[ply+1][j];
					}
					triangularLength[ply] = triangularLength[ply+1];
				}
			}
			else unmakeMove(moveBuffer[i]);
		}
	}
	return alpha;
}
Пример #2
0
BOOLTYPE toSan(Move &move, char *sanMove)
{

//	===========================================================================
//	toSan will convert a move into non-ambiguous SAN-notation, returned in char sanMove[].
//  "move" must belong to the current "board". Returns true if successful.
//  The move is compared with other moves from the current board position. 
//  Ambiguities can arise if two (or more) identical pieces can move to the same square.
//  In such cases, the piece's initial is followed by (in this priority):
//  - the from file, if it's unique, 
//  - or else the from rank, if it's unique
//  - or else the from file and rank (this can happen after pawn promotions, 
//	  e.g. with 4 rooks on c3, c7, a5 and e5; they all can move to c5, and then move notation would be: R3c5
//  'e.p.' is added for an en-passant capture 
//  '+'is added for check, '#' is added for mate.
//	===========================================================================

	int i, j, k, ibuf, from, to, piece, capt, prom, ambigfile, ambigrank;
	int asciiShift;
	BOOLTYPE legal, check, mate, ambig;

	asciiShift    = (int)'a';
	piece = move.getPiec();
	from = move.getFrom();
	to = move.getTosq();
	capt = move.getCapt();
	prom = move.getProm();
	ibuf = 0;
	ambig = false;
	ambigfile = 0;
	ambigrank = 0;
	legal = false;
	check = false;
	mate = false;
	sprintf(sanMove, "");

//	Generate all pseudo-legal moves to be able to remove any ambiguities 
//	and check legality. Take the next free location in moveBufLen:
	while (board.moveBufLen[ibuf+1]) ibuf++;
	board.moveBufLen[ibuf+1] = movegen(board.moveBufLen[ibuf]);

//	Loop over the moves to see what kind(s) of ambiguities exist, if any:
	for (i = board.moveBufLen[ibuf]; i < board.moveBufLen[ibuf+1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		if (!isOtherKingAttacked())
        {
			if (board.moveBuffer[i].moveInt == move.moveInt) 
			{
				legal = true;
				// it is check:
				if (isOwnKingAttacked()) 
				{
					check = true;
					// is it checkmate?
					k = 0;
					board.moveBufLen[ibuf+2] = movegen(board.moveBufLen[ibuf+1]);
					for (j = board.moveBufLen[ibuf+1]; j < board.moveBufLen[ibuf+2]; j++)
					{
						makeMove(board.moveBuffer[j]);
						if (!isOtherKingAttacked()) k++;
						unmakeMove(board.moveBuffer[j]);
					}
					if (!k) mate = true;
				}
			}
			// two same pieces can move to the same square:
			if ((board.moveBuffer[i].moveInt != move.moveInt) && (board.moveBuffer[i].getPiec() == piece) && (board.moveBuffer[i].getTosq() == to)) 
			{
				ambig = true;
				if (FILES[from] == FILES[board.moveBuffer[i].getFrom()]) ambigfile++; 
				if (RANKS[from] == RANKS[board.moveBuffer[i].getFrom()]) ambigrank++; 
			}
		}
		unmakeMove(board.moveBuffer[i]);
	}
//  cleanup:
	board.moveBufLen[ibuf+1] = 0;
	board.moveBufLen[ibuf+2] = 0;

//	construct the SAN string:
	if (!legal) 
	{
		strcpy(sanMove, "unknown");
		return false;
	}
	else
	{
		if (move.isCastleOO())
		{
			strcpy(sanMove, "O-O");
			return true;
		}	
		if (move.isCastleOOO())
		{
			strcpy(sanMove, "O-O-O");
			return true;
		}	
		// start building the string
		if (!move.isPawnmove()) 
		{
			sprintf(sanMove, "%s", PIECECHARS[piece]);
			if (ambig) 
			{
				if (ambigfile)
				{
					if (ambigrank) sprintf(sanMove, "%s%c%d", sanMove, FILES[from] + asciiShift - 1,RANKS[from]);
					else sprintf(sanMove, "%s%d", sanMove, RANKS[from]);
				}
				else
				{
					sprintf(sanMove, "%s%c", sanMove, FILES[from] + asciiShift - 1);
				}
			}
		}
		else
		{
			if (move.isCapture()) 
			{
				sprintf(sanMove, "%s%c", sanMove, FILES[from] + asciiShift - 1);
			}
		}
		if (move.isCapture()) sprintf(sanMove, "%sx", sanMove);
		sprintf(sanMove, "%s%c%d", sanMove, FILES[to] + asciiShift - 1, RANKS[to]);
		if (move.isEnpassant()) sprintf(sanMove, "%s e.p.", sanMove);
		if (move.isPromotion()) sprintf(sanMove, "%s=%s", sanMove, PIECECHARS[prom]);
		if (check)
		{
			if (mate) sprintf(sanMove, "%s#", sanMove); 
			else sprintf(sanMove, "%s+", sanMove);
		}
		return true;
	}
}
Пример #3
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;
}
Пример #4
0
BOOLTYPE Board::isEndOfgame(int &legalmoves, Move &singlemove)
{
  // Checks if the current position is end-of-game due to:
  // checkmate, stalemate, 50-move rule, or insufficient material
  
  int whiteknights, whitebishops, whiterooks, whitequeens, whitetotalmat;
  int blackknights, blackbishops, blackrooks, blackqueens, blacktotalmat;
  
  // are we checkmating the other side?
  int i;
  if (isOtherKingAttacked())
  {
    if (nextMove) std::cout << "1-0 {Black mates}" << std::endl;
    else std::cout << "1-0 {White mates}" << std::endl;
    return true;
  }
  
  // how many legal moves do we have?
  legalmoves = 0;
  moveBufLen[0] = 0;
  moveBufLen[1] = movegen(moveBufLen[0]);
  for (i = moveBufLen[0]; i < moveBufLen[1]; i++)
  {
    makeMove(moveBuffer[i]);
    if (!isOtherKingAttacked())
    {
      legalmoves++;
      singlemove = moveBuffer[i];
    }
    unmakeMove(moveBuffer[i]);
  }
  
  // checkmate or stalemate?
  if (!legalmoves)
  {
    if (isOwnKingAttacked())
    {
      if (nextMove) std::cout << "1-0 {White mates}" << std::endl;
      else std::cout << "1-0 {Black mates}" << std::endl;
    }
    else std::cout << "1/2-1/2 {stalemate}" << std::endl;
    return true;
  }
  
  // draw due to insufficient material:
  if (!whitePawns && !blackPawns)
  {
    whiteknights = bitCnt(whiteKnights);
    whitebishops = bitCnt(whiteBishops);
    whiterooks = bitCnt(whiteRooks);
    whitequeens = bitCnt(whiteQueens);
    whitetotalmat = 3 * whiteknights + 3 * whitebishops + 5 * whiterooks + 10 * whitequeens;
    blackknights = bitCnt(blackKnights);
    blackbishops = bitCnt(blackBishops);
    blackrooks = bitCnt(blackRooks);
    blackqueens = bitCnt(blackQueens);
    blacktotalmat = 3 * blackknights + 3 * blackbishops + 5 * blackrooks + 10 * blackqueens;
    
    // king versus king:
    if ((whitetotalmat == 0) && (blacktotalmat == 0))
    {
      std::cout << "1/2-1/2 {material}" << std::endl;
      return true;
    }
    
    // king and knight versus king:
    if (((whitetotalmat == 3) && (whiteknights == 1) && (blacktotalmat == 0)) ||
        ((blacktotalmat == 3) && (blackknights == 1) && (whitetotalmat == 0)))
    {
      std::cout << "1/2-1/2 {material}" << std::endl;
      return true;
    }
    
    // 2 kings with one or more bishops, all bishops on the same colour:
    if ((whitebishops + blackbishops) > 0)
    {
      if ((whiteknights == 0) && (whiterooks == 0) && (whitequeens == 0) &&
          (blackknights == 0) && (blackrooks == 0) && (blackqueens == 0))
      {
        if (!((whiteBishops | blackBishops) & WHITE_SQUARES) ||
            !((whiteBishops | blackBishops) & BLACK_SQUARES))
        {
          std::cout << "1/2-1/2 {material}" << std::endl;
          return true;
        }
      }
    }
  }
  
  // draw due to repetition:
  if (repetitionCount() >= 3)
  {
    std::cout << "1/2-1/2 {repetition}" << std::endl;
    return true;
    
  }
  
  // draw due to 50 move rule:
  if (fiftyMove >= 100)
  {
    std::cout << "1/2-1/2 {50-move rule}" << std::endl;
    return true;
  }
  
  return false;
}
Пример #5
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;
}