예제 #1
0
 public static Move NoMove()
 {
     // This returns a Move, which indicates no move has been made.
      Move result = new Move();
      result.moveType = Const.NoMoveID;
      return result;
 }
예제 #2
0
 private void AddMove(int moveType, int fromPos, int toPos)
 {
     if (nrGeneratedMoves == maxNrMoves)
      {
     // optionally increase the moveList
     int newMaxNrMoves = maxNrMoves * 2;
     Move[] moveList2 = new Move[newMaxNrMoves];
     for (int i = 0; i < maxNrMoves; i++)
        moveList2[i] = moveList[i];
     maxNrMoves = newMaxNrMoves;
     moveList = moveList2;
      }
      //
      moveList[nrGeneratedMoves].moveType = moveType;
      moveList[nrGeneratedMoves].fromPosition = fromPos;
      moveList[nrGeneratedMoves].toPosition = toPos;
      // don't know yet how to handle promotions in seeScore
      moveList[nrGeneratedMoves].seeScore = 0;            // will be filled later
      // store the possible captured piece :
      if (moveType < Const.SpecialMoveID)
      {
     // this can be EmptyID or some PieceType
     int capturedPieceType = board.SquareContents[toPos].pieceType;
     //
     if (capturedPieceType == Const.EmptyID)
     {
        moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
     }
     else
     {
        // yes, it is a capture.
        // Store the captured piece type in bits 0..2, and the capturing piece type in bits 3..5
        moveList[nrGeneratedMoves].captureInfo =
           capturedPieceType + (board.SquareContents[fromPos].pieceType << Const.NrPieceTypeBits);
        // also store the SEE score
        moveList[nrGeneratedMoves].seeScore = attack.SEE(moveType, fromPos, toPos);
     }
      }
      else
      {
     switch (moveType)
     {
        case Const.EnPassantCaptureID:
           moveList[nrGeneratedMoves].captureInfo = Const.PawnID + (Const.PawnID << Const.NrPieceTypeBits);
           moveList[nrGeneratedMoves].seeScore = attack.SEE(moveType, fromPos, toPos);
           break;
        case Const.PawnPromoteQueenID:
        case Const.PawnPromoteRookID:
        case Const.PawnPromoteBishopID:
        case Const.PawnPromoteKnightID:
           // this can be EmptyID or some PieceType
           // this can be EmptyID or some PieceType
           int capturedPieceType = board.SquareContents[toPos].pieceType;
           //
           if (capturedPieceType == Const.EmptyID)
              moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
           else
           {
              // yes, it is a capture.
              // Store the captured piece type in bits 0..2,  and the capturing piece type in bits 3..5
              moveList[nrGeneratedMoves].captureInfo =
                 capturedPieceType + (board.SquareContents[fromPos].pieceType << Const.NrPieceTypeBits);
           }
           break;
        default:
           moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
           break;
     }
      }
      nrGeneratedMoves++;
 }
예제 #3
0
 public Move[] GenerateQuiescenceMoves(Move[] initialMoveStorage)
 {
     // This generates only captures and pawn promotions
      moveList = initialMoveStorage;
      if (moveList == null || moveList.Length < 50)
     moveList = new Move[50];
      maxNrMoves = moveList.Length;
      nrGeneratedMoves = 0;
      //
      // Now generate pseudo legal moves. No check for getting into Check !
      nrGeneratedMoves = 0;
      GenerateCapturingKingMoves();
      GenerateCapturingQueenMoves();
      GenerateCapturingRookMoves();
      GenerateCapturingBishopMoves();
      GenerateCapturingKnightMoves();
      GenerateCapturingPawnMoves();
      GeneratePromotingPawnMoves();
      // Returns a pointer to the moveList.
      // This may be a different one then the initial, if the initial was to short.
      return moveList;
 }
예제 #4
0
        public Move[] GenerateMoves(Move[] initialMoveStorage)
        {
            moveList = initialMoveStorage;
             if (moveList == null || moveList.Length < 50)
            moveList = new Move[50];
             maxNrMoves = moveList.Length;
             nrGeneratedMoves = 0;
             //
             // Now generate pseudo legal moves. No check for getting into Check !
             nrGeneratedMoves = 0;

             GenerateKingMoves();
             GenerateCastleMoves();
             GenerateQueenMoves();
             GenerateRookMoves();
             GenerateBishopMoves();
             GenerateKnightMoves();
             GeneratePawnMoves();
             // Returns a pointer to the moveList.
             // This may be a different one then the initial, if the initial was to short.
             return moveList;
        }
예제 #5
0
        private void ScoreMoves(int plyNr)
        {
            const int transpostionTableScore = 1 << 30;
             const int followPVScore = 1 << 29;
             const int pawnPromotionOffset = 1 << 27;
             const int winningCaptureScoreOffset = 1 << 25;
             const int equalCaptureScoreOffset = 1 << 24;
             const int killerMove1Score = 1 << 21;
             const int killerMove2Score = killerMove1Score + 100;    // this seems to speed it up by a very little
             const int losingCaptureScoreOffset = 1 << 20;
             const int historyMoveScore = 1 << 14;    // 16384
             //

             int colorToMove = board.colorToMove;
             int historyTableNr;
             if (use2HistoryTables)
            historyTableNr = colorToMove;
             else
            historyTableNr = Const.White;         // use the same table for both colors
             bool haveFoundPVMove = false;
             // assign some static score to each move and order them
             if (moveOrdering_SearchPV)
             {
            if (plyNr >= PrincipalVariation.Length)
               isFollowingThePV = false;   // Searching beyond the PrincipalVariation length.
             }
             //
             bool searchForTTMove = false;
             Move ttMove = Move.NoMove();
             if (moveOrdering_SearchTT)
             {
            int index = transpositionTable.GetIndex(board.HashValue, 0);
            if (index >= 0)
            {
               int compressedMove = transpositionTable.slots[index].compressedMove;
               ttMove = new Move(compressedMove);
               if (ttMove.moveType != Const.NoMoveID)
                  searchForTTMove = true;
            }
             }
             //
             int nrMoves = nrGeneratedMovesInPly[plyNr];
             if (scoreMatrix[plyNr] == null || scoreMatrix[plyNr].Length < nrMoves)
            scoreMatrix[plyNr] = new int[nrMoves + 1];
             Move[] moves = moveMatrix[plyNr];   // just a pointer
             int[] scores = scoreMatrix[plyNr];   // just a pointer
             //
             // History : find the min and max for this set of moves
             int maxHistoryValue = 0;
             if (useMoveOrdering_History)
             {
            // find the highest history value
            for (int i = 0; i < nrMoves; i++)
            {
               int from = moves[i].fromPosition;
               int to = moves[i].toPosition;
               if (History[historyTableNr][from, to] > maxHistoryValue)
                  maxHistoryValue = History[historyTableNr][from, to];
            }
             }

             //
             for (int i = 0; i < nrMoves; i++)
             {
            // first set the score to 0
            scores[i] = 0;
            // see if anyting can be found in the transposition table
            if (searchForTTMove)
            {
               if (moves[i].fromPosition == ttMove.fromPosition
                  && moves[i].toPosition == ttMove.toPosition
                  && moves[i].moveType == ttMove.moveType)
               {
                  searchForTTMove = false;
                  scores[i] += transpostionTableScore;
               }
            }
            // check for the PV
            if (moveOrdering_SearchPV)
            {
               // is this move in the correct place in the principal variation ?
               if (isFollowingThePV && !haveFoundPVMove)
               {
                  if (moves[i].fromPosition == PrincipalVariation[plyNr].fromPosition
                     && moves[i].toPosition == PrincipalVariation[plyNr].toPosition
                     && moves[i].moveType == PrincipalVariation[plyNr].moveType)
                  {
                     haveFoundPVMove = true;
                     scores[i] += followPVScore;
                  }
               }
            }
            // is this a capture ?
            if (moves[i].captureInfo != Const.NoCaptureID)
            {
               if (moveOrdering_UseSEE)
               {
                  int seeScore = moves[i].seeScore;
                  // multiply by (historyMoveScore+1), to not let HistoryMoveScore interfere with SeeScore's
                  if (seeScore > 0)
                     scores[i] += winningCaptureScoreOffset + seeScore * (historyMoveScore + 1);
                  else if (seeScore < 0)
                     scores[i] += losingCaptureScoreOffset + seeScore * (historyMoveScore + 1);    // seeScore is negative
                  else
                     scores[i] += equalCaptureScoreOffset;
               }
               else
               {
                  // NB : pawn = 5, queen = 0
                  int capturedPieceType = moves[i].captureInfo & Const.PieceTypeBitMask;
                  int capturingPieceType = (moves[i].captureInfo >> Const.NrPieceTypeBits) & Const.PieceTypeBitMask;
                  // positive=winning , negative=losing
                  int captureScore = capturingPieceType - capturedPieceType;
                  if (captureScore > 0)
                     scores[i] += winningCaptureScoreOffset + captureScore * (historyMoveScore + 1);
                  else if (captureScore == 0)
                     scores[i] += equalCaptureScoreOffset;
                  else
                     scores[i] += losingCaptureScoreOffset + captureScore * (historyMoveScore + 1);
               }
            }
              else
            {
               // Not a capture : is it a Killer move ?
               if (useKillerMoves)
               {
                  if (moves[i] == KillerMoves1[plyNr])
                     scores[i] += killerMove1Score;
                  else if (moves[i] == KillerMoves2[plyNr])
                     scores[i] += killerMove2Score;
               }
            }
            // is it a pawn promotion ? Only score the Queen promotion. Let the minor promotions get score = 0;
            if (moves[i].moveType == Const.PawnPromoteQueenID)
               scores[i] += pawnPromotionOffset;
            /*
            if (moves[i].moveType >= Const.SpecialMoveID)
            {
               switch (moves[i].moveType)
               {
                  case Const.PawnPromoteQueenID: scores[i] += pawnPromotionOffset + 4 * (historyMoveScore + 1); break;
                  // don't care about the minor promotions
                  case Const.PawnPromoteRookID: scores[i] -= pawnPromotionOffset + 3 * (historyMoveScore + 1);  break;
                  case Const.PawnPromoteBishopID: scores[i] -= pawnPromotionOffset + 2 * (historyMoveScore + 1); break;
                  case Const.PawnPromoteKnightID: scores[i] -= pawnPromotionOffset + 1 * (historyMoveScore + 1); break;
               }
            }
            */
            if (useMoveOrdering_History && maxHistoryValue != 0)
            {
               // if maxHistoryValue == 0, History is empty. Dividing by it yields Int.MinValue !!
               int moveFromPos = moves[i].fromPosition;
               int moveToPos = moves[i].toPosition;
               // history now scores from historyMoveScore to 2*historyMoveScore
               scores[i] += historyMoveScore + (int)(historyMoveScore * 1.0 * History[historyTableNr][moveFromPos, moveToPos] / maxHistoryValue);

            #if CheckIfMoveOrderingHasMoves
              if (scores[i] == int.MinValue)
                  MessageBox.Show("oo");
            #endif

            }
            if (moveOrdering_StaticPositionValue)
            {
               // trick from Rebel : sort moves by their static position evaluation.
               // This might help a little for otherwise unsorted moves.
               // this probably only works for a very simple evaluation !!!
               // A better approach might be internal deepening
               int moveFromPos = moves[i].fromPosition;
               int moveToPos = moves[i].toPosition;
               int moveType = moves[i].moveType;
               switch (moves[i].moveType)
               {
                  case Const.KingID:
                  case Const.QueenID:
                  case Const.RookID:
                  case Const.BishopID:
                  case Const.KnightID:
                     scores[i] += evaluator.PieceSquareValues[colorToMove][moveType][moveToPos]
                                  - evaluator.PieceSquareValues[colorToMove][moveType][moveFromPos];
                     break;
                  case Const.PawnID:
                  case Const.Pawn2StepID:
                  case Const.EnPassantCaptureID:
                     scores[i] += evaluator.PieceSquareValues[colorToMove][Const.PawnID][moveToPos]
                                  - evaluator.PieceSquareValues[colorToMove][Const.PawnID][moveFromPos];
                     break;
                  case Const.CastleKSID:
                  case Const.CastleQSID:
                     // the from/to pos is that of the king
                     scores[i] += evaluator.PieceSquareValues[colorToMove][Const.KingID][moveToPos]
                                  - evaluator.PieceSquareValues[colorToMove][Const.KingID][moveFromPos];
                     break;
               }
            }
             }
             //
             if (moveOrdering_SearchPV && !haveFoundPVMove)
            isFollowingThePV = false;    // lost the PV track

            #if CheckIfMoveOrderingHasMoves
             for (int i = 0; i < nrGeneratedMovesInPly[plyNr]; i++)
             {
            if (scores[i] == int.MinValue)
               MessageBox.Show("OhOh");
             }
            #endif
        }
예제 #6
0
 private void CreateStorage()
 {
     // Creates the initial storage. It will be extended if needed.
      nrGeneratedMovesInPly = new int[maxNrPlies];
      moveMatrix = new Move[maxNrPlies][];
      scoreMatrix = new int[maxNrPlies][];
      PV_Matrix = new Move[maxNrPlies][];
      nrMovesInPVLine = new int[maxNrPlies];
      for (int i = 0; i < maxNrPlies; i++)
     PV_Matrix[i] = new Move[maxNrExpectedPVMoves];
      KillerMoves1 = new Move[maxNrPlies];
      KillerMoves2 = new Move[maxNrPlies];
      // create history for both colors
      History = new int[2][,];
      History[0] = new int[Const.NrSquares, Const.NrSquares];
      History[1] = new int[Const.NrSquares, Const.NrSquares];
 }
예제 #7
0
 private void CheckEnoughNrPliesStorage(int plyNr)
 {
     // optionally create extra storage when the new PlyNr exceeds the maxnrPlies.
      if (plyNr < maxNrPlies)
        return;
      //
      int newMaxNrPlies = maxNrPlies + 10;
      Move[][] newMoveMatrix = new Move[newMaxNrPlies][];
      int[][] newScoreMatrix = new int[newMaxNrPlies][];
      int[] newNrGeneratedMovesInPly = new int[newMaxNrPlies];
      Move[][] newPV_Matrix = new Move[newMaxNrPlies][];
      int[] newNrMovesInPVLine = new int[newMaxNrPlies];
      Move[] newKillerMoves1 = new Move[newMaxNrPlies];
      Move[] newKillerMoves2 = new Move[newMaxNrPlies];
      for (int i = 0; i < maxNrPlies; i++)
      {
     newMoveMatrix[i] = moveMatrix[i];
     newScoreMatrix[i] = scoreMatrix[i];
     newNrGeneratedMovesInPly[i] = nrGeneratedMovesInPly[i];
     newPV_Matrix[i] = PV_Matrix[i];
     newNrMovesInPVLine[i] = nrMovesInPVLine[i];
     newKillerMoves1[i] = KillerMoves1[i];
     newKillerMoves2[i] = KillerMoves2[i];
      }
      // initialize the appended storage
      for (int i = maxNrPlies; i < newMaxNrPlies; i++)
      {
     // moveMatrix[] will be handled (created) by MoveGenerator.GenerateMoves
     newPV_Matrix[i] = new Move[maxNrExpectedPVMoves];
      }
      moveMatrix = newMoveMatrix;
      scoreMatrix = newScoreMatrix;
      nrGeneratedMovesInPly = newNrGeneratedMovesInPly;
      PV_Matrix = newPV_Matrix;
      nrMovesInPVLine = newNrMovesInPVLine;
      KillerMoves1 = newKillerMoves1;
      KillerMoves2 = newKillerMoves2;
      maxNrPlies = newMaxNrPlies;
 }
예제 #8
0
 public bool MakeMove(Move move)
 {
     bool moveIsLegal = true;   // this will be checked if a castle is done and by the IsInCheck test
      // increment the HalfMoveNr
      halfMoveNr++;
      // increment the fiftyMoveNr. It will be reset later in this method if it was a capture or a pawn-move.
      fiftyMoveNr++;
      //
      capturedPieceType = Const.InvalidID;
      capturedPiecePosition = Const.InvalidID;
     #if HashDebug
      if (HashValue != CalcHashValue())
     throw new ApplicationException("hash differs");
     #endif
      // maybe remove the en-passant from the hash
      if (enPassantPosition != Const.InvalidID)
     HashValue ^= transpositionTable.EPSquareValue[enPassantPosition];
      //
      if (move.moveType < Const.SpecialMoveID)
      {
     // a normal move of a piece
     enPassantPosition = Const.InvalidID;    // normal move : always reset the enpassant position
     // Handle castling info
     if (canCastleQueenSide[colorToMove] || canCastleKingSide[colorToMove])
     {
        // check for a king move
        if (move.moveType == Const.KingID)
        {
           ResetCanCastleQS(colorToMove);
           ResetCanCastleKS(colorToMove);
        }
        // check for a castle move
        if (move.moveType == Const.RookID)
        {
           int offset = colorToMove * 56;
           // check if the QS rook will move. Offset points to the queen-side rooks.
           if (move.fromPosition == offset)
              ResetCanCastleQS(colorToMove);
           // check if the KS rook will move.  Offset+7 points to the king-side rooks.
           if (move.fromPosition == offset + 7)
              ResetCanCastleKS(colorToMove);
        }
     }
     // update the fiftyMoveNr
     if (move.moveType == Const.PawnID)
     {
        fiftyMoveNr = 0;                 // pawn move : reset the fiftyMoveNr
        // if a pawn is moved, the previous position can never be seen again : so
        repeatedPosition_SearchOffset = nrHashValuesInHistory;
        //repeatedPosition_SearchOffset = halfMoveNr - 1;
     }
     // is it a capture ? Yes : remove the captured piece
     if (SquareContents[move.toPosition].pieceType != Const.EmptyID)
     {
        // save state
        capturedPiecePosition = move.toPosition;
        capturedPieceType = SquareContents[move.toPosition].pieceType;
        //
        RemovePieceFromBoard(move.toPosition);
        fiftyMoveNr = 0;   // capture : reset the fiftyMoveNr
     }
     // now make the move
     MovePieceOnBoard(move.fromPosition, move.toPosition);
      }
      else
      {
     // Specials
     // it is a Castle, enpassant capture, 2-stap pawn move or pawn promotion
     int castleRankOffset = colorToMove * 56;
     switch (move.moveType)
     {
        case Const.CastleQSID:
           // Maybe the castle was illegal. Do it anyway.
           // Illegal castle will immediately be undone in SearchMove.
           if (moveIsLegal)
              moveIsLegal = moveGenerator.CastleIsLegal(Const.CastleQSID);
           MovePieceOnBoard(castleRankOffset + 4, castleRankOffset + 2);  // King
           MovePieceOnBoard(castleRankOffset + 0, castleRankOffset + 3);  // Rook
           hasCastled[colorToMove] = true;
           ResetCanCastleQS(colorToMove);
           ResetCanCastleKS(colorToMove);
           break;
        case Const.CastleKSID:
           // Maybe the castle was illegal. Do it anyway.
           // Illegal castle will immediately be undone in SearchMove.
           if (moveIsLegal)
              moveIsLegal = moveGenerator.CastleIsLegal(Const.CastleKSID);
           MovePieceOnBoard(castleRankOffset + 4, castleRankOffset + 6);  // King
           MovePieceOnBoard(castleRankOffset + 7, castleRankOffset + 5);  // Rook
           hasCastled[colorToMove] = true;
           ResetCanCastleQS(colorToMove);
           ResetCanCastleKS(colorToMove);
           break;
        case Const.EnPassantCaptureID:
           capturedPieceType = Const.PawnID;
           if (colorToMove == Const.White)
              capturedPiecePosition = enPassantPosition - 8;  // captured pawn is black
           else
              capturedPiecePosition = enPassantPosition + 8;  // captured pawn is white
           RemovePieceFromBoard(capturedPiecePosition);
           MovePieceOnBoard(move.fromPosition, move.toPosition);
           break;
        case Const.PawnPromoteQueenID:
        case Const.PawnPromoteRookID:
        case Const.PawnPromoteBishopID:
        case Const.PawnPromoteKnightID:
           if (SquareContents[move.toPosition].pieceType != Const.EmptyID)
           {
              // save state
              capturedPiecePosition = move.toPosition;
              capturedPieceType = SquareContents[move.toPosition].pieceType;
              RemovePieceFromBoard(move.toPosition);          // it was a capture
           }
           RemovePieceFromBoard(move.fromPosition);
           AddNewPieceToBoard(colorToMove, Const.QueenID + move.moveType - Const.PawnPromoteQueenID, move.toPosition);
           fiftyMoveNr = 0;                 // pawn move : reset the fiftyMoveNr
           break;
        case Const.Pawn2StepID:
           MovePieceOnBoard(move.fromPosition, move.toPosition);
           // point enPassantPosition to the jumped over square
           enPassantPosition = (move.fromPosition + move.toPosition) / 2;
           fiftyMoveNr = 0;                 // pawn move : reset the fiftyMoveNr
           // update hashValue
           HashValue ^= transpositionTable.EPSquareValue[enPassantPosition];
           break;
        case Const.NullMoveID:
           // just do nothing
           break;
        default:
           throw new Exception("Invalid special move nr");
     }
     // always reset the enPassant pasition, unless it set by the Pawn 2Step move
     if (move.moveType != Const.Pawn2StepID)
        enPassantPosition = Const.InvalidID;
      }
      // Finally check if this move was legal. If not, it will immediately be undone in SearchMove.
      // Do it with an IF statement, since also castling could have set moveIsLegal to false.
      if (IsInCheck())
     moveIsLegal = false;
      //
      ToggleMoveColor();
      // Store the state exactly as it was AFTER this move was made. Also stores HashValue.
      StoreBoardState();
      //
      // Remember the hash-value of this board
      nrHashValuesInHistory++;
      if (nrHashValuesInHistory == HashValueHistory.Length)
      {
     // increase size
     ulong[] newArray = new ulong[HashValueHistory.Length + 100];
     Array.Copy(HashValueHistory, newArray, HashValueHistory.Length);
     HashValueHistory = newArray;
      }
      HashValueHistory[nrHashValuesInHistory] = HashValue;
      //
      return moveIsLegal;
 }
예제 #9
0
 private void StoreKillerAndHistory(Move currentMove, int currentDepth)
 {
     if (useKillerMoves && currentMove.captureInfo == Const.NoCaptureID)
      {
     // It gives a cut-off. Remember if for move-ordening
     // Don't store capturing moves (they already get high move-order priority)
     // And make sure KillerMove2 does not becomes equal to KillerMove1
     if (KillerMoves1[plyNr] != currentMove)
     {
        KillerMoves2[plyNr] = KillerMoves1[plyNr];
        KillerMoves1[plyNr] = currentMove;
     }
     else
     {
        // KillerMove1 is already set to CurrentMove. Try KillerMove2
        if (KillerMoves2[plyNr] != currentMove)
           KillerMoves2[plyNr] = currentMove;
     }
      }
      if (useMoveOrdering_History)
      {
     int color;
     if (use2HistoryTables)
        color = board.colorToMove;
     else
        color = Const.White;             // use the same table for both colors
     int[,] history = History[color];
     history[currentMove.fromPosition, currentMove.toPosition] += 2 << currentDepth;
     if (history[currentMove.fromPosition, currentMove.toPosition] > maxHistoryValue[color])
     {
        maxHistoryValue[color] = history[currentMove.fromPosition, currentMove.toPosition];
        if (maxHistoryValue[color] > 1 << 30)
           ScaleDownHistory(color, 2);
     }
      }
 }
예제 #10
0
        private void StoreCurrentThinking(int score)
        {
            // stores the best found mobes, so far and the score
             currentScore = score;

             int nrPVMoves = PrincipalVariation.Length;
             if (nrPVMoves > maxNrThinkMoves)
            nrPVMoves = maxNrThinkMoves;
             bool TTStillMatchesPV = true;         // this signals if the PV matches the TT
             int nrThinkMoves = 0;
             Move[] thinkMoves = new Move[maxNrThinkMoves];
             ulong[] thinkMoveHashValues = new ulong[maxNrThinkMoves];

             // First store everything in a clone, since making captures reorders the indices of pieces in PiecePos.
             // This reorders future moves. Somehow, this gives problems
             Board clone = new Board(false);
             clone.LoadFrom(board);
             //
             for (int i = 0; i < nrPVMoves; i++)
             {
            if (TTStillMatchesPV)
            {
               int ttIndex = transpositionTable.GetIndex(board.HashValue, 0);
               if (ttIndex >= 0)
               {
                  Move ttMove = new Move(transpositionTable.slots[ttIndex].compressedMove);
                  if (ttMove != PrincipalVariation[i])
                     TTStillMatchesPV = false;
               }
               else
                  TTStillMatchesPV = false;
            }
            thinkMoves[i] = PrincipalVariation[i];
            thinkMoveHashValues[i] = board.HashValue;
            board.MakeMove(PrincipalVariation[i]);
            nrThinkMoves++;
             }
             // finished the PrincipalVariation. Now follow the TT
             nrCurrentMovesFromPV = nrThinkMoves;
             int ttIndex2;
             while ((ttIndex2 = transpositionTable.GetIndex(board.HashValue, 0)) != -1)
             {
            Move move = new Move(transpositionTable.slots[ttIndex2].compressedMove);
            if (move.moveType == Const.NoMoveID)
               break;
            if (nrThinkMoves >= maxNrThinkMoves - 1)
               break;
            thinkMoves[nrThinkMoves] = move;
            thinkMoveHashValues[nrThinkMoves] = board.HashValue;
            board.MakeMove(move);
            nrThinkMoves++;
            // Check if this move has occured before. Otherwise an endless loop would occurr.
            // Allow for 3 entries, since this is possible for the 3-move rule (?)
            int nrSameEntries = 0;
            for (int i = 0; i < nrThinkMoves; i++)
               if (thinkMoveHashValues[i] == board.HashValue)
                  nrSameEntries++;
            if (nrSameEntries >= 3)
               break;
             }
             // now rewind the board by undoing the moves made
             for (int i = nrThinkMoves - 1; i >= 0; i--)
            board.UnMakeMove(thinkMoves[i]);
             // switch back to the original board
             board.LoadFrom(clone);
             //
             // So found the moves, now store them
             currentMoves = new Move[nrThinkMoves];
             for (int i = 0; i < nrThinkMoves; i++)
            currentMoves[i] = thinkMoves[i];
        }
예제 #11
0
        private void ScoreQMoves(int plyNr)
        {
            const int transpostionTableScore = 1 << 30;
             const int pawnPromotionOffset = 1 << 27;
             const int winningCaptureScoreOffset = 1 << 25;
             const int equalCaptureScoreOffset = 1 << 24;
             const int losingCaptureScoreOffset = 1 << 20;
             //
             // assign some static score to each move
             //

             bool searchForTTMove = false;
             Move ttMove = Move.NoMove();
             if (moveOrdering_SearchTT)
             {
            int index = transpositionTable.GetIndex(board.HashValue, 0);
            if (index >= 0)
            {
               int compressedMove = transpositionTable.slots[index].compressedMove;
               ttMove = new Move(compressedMove);
               if (ttMove.moveType != Const.NoMoveID)
                  searchForTTMove = true;
            }
             }

             int nrMoves = nrGeneratedMovesInPly[plyNr];
             if (scoreMatrix[plyNr] == null || scoreMatrix[plyNr].Length < nrMoves)
            scoreMatrix[plyNr] = new int[nrMoves + 1];
             Move[] moves = moveMatrix[plyNr];    // just a pointer
             int[] scores = scoreMatrix[plyNr];   // just a pointer

             for (int i = 0; i < nrMoves; i++)
             {
            // first set the score to 0
            scores[i] = 0;

            if (searchForTTMove)
            {
               // see if anyting can be found in the transposition table
               if (moves[i].fromPosition == ttMove.fromPosition
                  && moves[i].toPosition == ttMove.toPosition
                  && moves[i].moveType == ttMove.moveType)
               {
                  searchForTTMove = false;
                  scores[i] += transpostionTableScore;
               }
            }

            // is this a capture ?
            if (moves[i].captureInfo != Const.NoCaptureID)
            {
               if (moveOrdering_UseSEE)
               {
                  int seeScore = moves[i].seeScore;
                  if (seeScore > 0)
                     scores[i] += winningCaptureScoreOffset + seeScore;
                  else if (seeScore < 0)
                     scores[i] += losingCaptureScoreOffset + seeScore;    // seeScore is negative
                  else
                     scores[i] += equalCaptureScoreOffset;
               }
               else
               {
                  // NB : pawn = 5, queen = 0
                  int capturedPieceType = moves[i].captureInfo & Const.PieceTypeBitMask;
                  int capturingPieceType = (moves[i].captureInfo >> Const.NrPieceTypeBits) & Const.PieceTypeBitMask;
                  // positive=winning , negative=losing
                  int captureScore = capturingPieceType - capturedPieceType;
                  if (captureScore > 0)
                     scores[i] += winningCaptureScoreOffset + captureScore;
                  else if (captureScore == 0)
                     scores[i] += equalCaptureScoreOffset;
                  else
                     scores[i] += losingCaptureScoreOffset + captureScore;
               }
            }

            // is it a pawn promotion ? Only score the Queen promotion. Let the minor promotions get score = 0;
            if (moves[i].moveType == Const.PawnPromoteQueenID)
               scores[i] = pawnPromotionOffset;
            /*
            if (moves[i].moveType >= Const.SpecialMoveID)
            {
               switch (moves[i].moveType)
               {
                  case Const.PawnPromoteQueenID: scores[i] += pawnPromotionOffset + 4; break;
                  // don't care about these
                  case Const.PawnPromoteRookID: scores[i] -= pawnPromotionOffset + 3; break;
                  case Const.PawnPromoteBishopID: scores[i] -= pawnPromotionOffset + 2; break;
                  case Const.PawnPromoteKnightID: scores[i] -= pawnPromotionOffset + 1; break;
               }
            }
             */
             }
        }
예제 #12
0
 public void StoreMoveInHistory(Move move)
 {
     if (nrMovesInHistory == MoveHistory.Length)
      {
     // increase storage space
     Move[] newArray = new Move[MoveHistory.Length + 100];
     Array.Copy(MoveHistory, newArray, MoveHistory.Length);
     MoveHistory = newArray;
      }
      MoveHistory[nrMovesInHistory] = move;
      nrMovesInHistory++;
 }
예제 #13
0
 public void MakeMove(Move move)
 {
     // this must later go, in favour of MakeMove(string)
      if (move.moveType != Const.NoMoveID)
     board.MakeMove(move);
      else
     throw new Exception("illegal move");
      // store the move in MoveHistory
      StoreMoveInHistory(move);
 }
예제 #14
0
        public string MoveToSANString(Move move)
        {
            int fromPosition = move.fromPosition;
             int toPosition = move.toPosition;
             // first generate all (pseudo-legal) moves :
             Move[] moves = moveGenerator.GenerateMoves(null);
             int nrMoves = moveGenerator.nrGeneratedMoves;
             // Check the list to see if the move is present
             int moveNr = -1;
             for (int i=0; i<nrMoves; i++)
            if (moves[i] == move)
            {
               moveNr = i;
               break;
            }
             if (moveNr == -1)
            return "???";

             // maybe it's a special move

             if (move.moveType >= Const.SpecialMoveID)
             {
            // these are never ambiguous
            switch (move.moveType)
            {
               case Const.CastleQSID: return "O-O-O";
               case Const.CastleKSID: return "O-O";
               case Const.EnPassantCaptureID:
                  return EPD.PositionToFileString(fromPosition) + "x" +EPD.PositionToString(toPosition);
               case Const.PawnPromoteQueenID:
               case Const.PawnPromoteRookID:
               case Const.PawnPromoteBishopID:
               case Const.PawnPromoteKnightID:
                  string s = EPD.PositionToFileString(fromPosition);
                  if (move.captureInfo == Const.NoCaptureID)
                     s += EPD.PositionToRankString(toPosition);
                  else
                  {
                     s += "x" + EPD.PositionToString(toPosition);
                  }
                  return s + "=" + EPD.PromotionPieceToString(move.moveType);
               case Const.Pawn2StepID:
                  return EPD.PositionToString(toPosition);
               default:
                  throw new ArgumentException("Invalid Special MoveType");
            }
             }

             // maybe it's a pawn move :

             if (move.moveType == Const.PawnID)
             {
            // is never ambiguous
            if (move.captureInfo == Const.NoCaptureID)
               return EPD.PositionToString(toPosition);
            else
               return EPD.PositionToFileString(fromPosition) + "x" + EPD.PositionToString(toPosition);
             }

             // It's a major piece move.

             string ss = EPD.PieceTypeToString(move.moveType);
             // check whetter multiple moves of the same type end on the same square
             int nrAmbiguousMoves = 0;
             Move ambiguousMove = Move.NoMove();
             for (int i = 0; i < nrMoves; i++)
             {
            if (i == moveNr)
               continue;
            if (move.moveType == moves[i].moveType && toPosition == moves[i].toPosition)
            {
               nrAmbiguousMoves++;
               if (nrAmbiguousMoves > 1)
                  break;  // more then 1, always specify both file and rank
               // only need to store 1
               ambiguousMove = moves[i];
            }
             }
             if (nrAmbiguousMoves > 0)
             {
            // add either a FileChar, a RankChar or both
            if (nrAmbiguousMoves == 1)
            {
               // different files ?
               if (ambiguousMove.fromPosition %8 != move.fromPosition % 8)
                  ss += EPD.PositionToFileString(move.fromPosition);
               else
                  // no, so differnent ranks
                  ss += EPD.PositionToRankString(move.fromPosition);
            }
            else
               // more then 1 ambiguous move. Use both file and rank
               ss += EPD.PositionToString(move.fromPosition);
             }
             if (move.captureInfo != Const.NoCaptureID)
            ss += "x";
             return ss + EPD.PositionToString(toPosition);
        }
예제 #15
0
 public string MoveToLANString(Move move)
 {
     // e.g. e2e4  e1g1 (KS castle), e7e8q (promotion)
      string s = EPD.PositionToFileString(move.fromPosition) + EPD.PositionToFileString(move.toPosition);
      if (move.moveType >= Const.SpecialMoveID)
     switch (move.moveType)
     {
        case Const.PawnPromoteQueenID:
        case Const.PawnPromoteRookID:
        case Const.PawnPromoteBishopID:
        case Const.PawnPromoteKnightID:
           s += EPD.PromotionPieceToString(move.moveType).ToLower();
           break;
     }
      return s;
 }
예제 #16
0
 private void AddQuiescenceMove(int moveType, int fromPos, int toPos)
 {
     if (nrGeneratedMoves == maxNrMoves)
      {
     // optionally increase the moveList
     int newMaxNrMoves = maxNrMoves * 2;
     Move[] moveList2 = new Move[newMaxNrMoves];
     for (int i = 0; i < maxNrMoves; i++)
        moveList2[i] = moveList[i];
     maxNrMoves = newMaxNrMoves;
     moveList = moveList2;
      }
      //
      moveList[nrGeneratedMoves].moveType = moveType;
      moveList[nrGeneratedMoves].fromPosition = fromPos;
      moveList[nrGeneratedMoves].toPosition = toPos;
      moveList[nrGeneratedMoves].seeScore = 0;             // filled in later
      //
      // store the possible captured piece :
      if (moveType < Const.SpecialMoveID)
      {
     // this can be EmptyID or some PieceType
     int capturedPieceType = board.SquareContents[toPos].pieceType;
     //
     if (capturedPieceType == Const.EmptyID)
        moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
     else
     {
        // yes, it is a capture.
        // Store the captured piece type in bits 0..2, and the capturing piece type in bits 3..5
        moveList[nrGeneratedMoves].captureInfo =
           capturedPieceType + (board.SquareContents[fromPos].pieceType << Const.NrPieceTypeBits);
        // also store the SEE-score
        moveList[nrGeneratedMoves].seeScore = attack.SEE(moveType, fromPos, toPos);
     }
      }
      else
      {
     switch (moveType)
     {
        case Const.EnPassantCaptureID:
           moveList[nrGeneratedMoves].captureInfo = Const.PawnID + (Const.PawnID << Const.NrPieceTypeBits);
           moveList[nrGeneratedMoves].seeScore = attack.SEE(moveType, fromPos, toPos);
           break;
        case Const.PawnPromoteQueenID:
        case Const.PawnPromoteRookID:
        case Const.PawnPromoteBishopID:
        case Const.PawnPromoteKnightID:
           // this can be EmptyID or some PieceType
           // this can be EmptyID or some PieceType
           int capturedPieceType = board.SquareContents[toPos].pieceType;
           //
           if (capturedPieceType == Const.EmptyID)
              moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
           else
           {
              // yes, it is a capture.
              // Store the captured piece type in bits 0..2,  and the capturing piece type in bits 3..5
              moveList[nrGeneratedMoves].captureInfo =
                 capturedPieceType + (board.SquareContents[fromPos].pieceType << Const.NrPieceTypeBits);
           }
           break;
        default:
           moveList[nrGeneratedMoves].captureInfo = Const.NoCaptureID;
           break;
     }
      }
      // maybe abort here, if captures with negative SEE is excluded
      if (noNegativeSEECaptures && !(moveType >= Const.SpecialMoveID))
      {
     // moveType>=Const.SpecialMoveID : always do special stuff.
     // This also means that en-passant captures are never filtered out !
     // Also : SEE has problems with promotions or so
     if (moveList[nrGeneratedMoves].seeScore < 0)
        return;
      }
      nrGeneratedMoves++;
 }
예제 #17
0
        private int AlphaBeta(int depth, int alpha, int beta, bool canDoNullMove, bool canDoLMR)
        {
            // Alpha = the current best score that can be forced by some means.
             // Beta  = the worst-case scenario for the opponent.
             //       = upper bound of what the opponent can achieve
             // Score >= Beta, the opponent won't let you get into this position : he has a better previous move.
             //
             nrNodesSearchedAfterLastTimeCheck++;
             // Check the time.
             if (nrNodesSearchedAfterLastTimeCheck >= maxNrNodeSearchesBeforeTimeCheck)
             {
            nrNodesSearchedAfterLastTimeCheck = 0;
            abortSearch = IsSearchTimeFinished();              // check the time

            if ((DateTime.Now - lastTimeReportWasSent).TotalSeconds > 0.5)
            {
               // send a report, once a second
               if (SearchMoveHasNewResults != null)
               {
                  currentNrNodes = nodeCount;
                  currentSearchTime = (int)((DateTime.Now - startedThinkingTime).TotalMilliseconds) / 1000.0;
                  currentTTFullPerMill = transpositionTable.GetTTFullPerMill();
                  SearchMoveHasNewResults(false);
               }
               lastTimeReportWasSent = DateTime.Now;
            }
            #if !SILVERLIGHT
            Application.DoEvents();
            #endif
             }
             //
             // If we are out of time, quit. Don't care about the score, since this entire depth will be discarded.
             if (abortSearch)
            return 0;
             //
             nodeCount++;
             int initialAlpha = alpha;

             // check for enough storage
             CheckEnoughNrPliesStorage(plyNr);
             //
             nrMovesInPVLine[plyNr] = 0;
             //
             if (plyNr > 0 && board.IsPracticallyDrawn())
            return 0;                  // check for 50-move rule ,3x repetition & not enough material

             // First look in the Transposition Table
             // But not for PlyNr = 0, otherwise no move is made on finding an exact score !
             // Not for depth <=0, since this should go to QSearch below
             if (useTTable && plyNr > 0 && depth > 0)
             {
            int index = transpositionTable.GetIndex(board.HashValue, depth);
            if (index >= 0)
            {
               int hashScore = transpositionTable.slots[index].score;

               /*
               // correct the mate-score ?? This doesn't work, since the stored hashScore is incorrect.
                     if (Math.Abs(hashScore) > Evaluator.FutureMate && Math.Abs(hashScore) <= Evaluator.MateValue)
                     {
                        if (hashScore > Evaluator.FutureMate)
                           hashScore -= plyNr;
                        else
                           hashScore += plyNr;
                     }
               */

               int bound = transpositionTable.slots[index].flags;

               // http://www.cs.ualberta.ca/~jonathan/Courses/657/Notes/4.DAGs.pdf
               // Also see Beowulf, comp.c
               switch (bound)
               {
                  case TranspositionTable.exactBound:
                     // This score is precisely known, so return it.
                     return hashScore;
                  case TranspositionTable.upperBound:
                     // Upperbound : true score is hashScore or less.
                     if (hashScore <= alpha)
                        // This was an upper bound, but still isn't greater than alpha, so return a fail-low
                        return hashScore;   // was alpha
                     if (hashScore < beta)
                        // This was an upper bound, but was greater than alpha, so adjust beta if necessary
                        beta = hashScore;
                     break;
                  case TranspositionTable.lowerBound:
                     // Lowerbound (caused by beta cutoff) : true score is hashScore or larger.
                     if (hashScore >= beta)
                        // This was a lower bound, but was still greater than beta, so return a fail-high
                        return hashScore;
                     if (hashScore > alpha)
                        // This was a lower bound, but was not greater than beta, so adjust alpha if necessary
                        alpha = hashScore;
                     break;
               }
            }
             }

             bool isInCheck = board.IsInCheck();

             // maybe extend the remaining depth in certain circumstances
             bool haveExtended = false;
             if (UseExtensions)
             {
            if (isInCheck)
            {
               depth++;
               haveExtended = true;
            }
             }

             // due to the extensions, we do not enter QSearch while in check.
             if (depth <= 0)
            return QSearch(maxQuiescenceDepth, alpha, beta);

             if (useNullMove)
             {
            // If making no move at all would produce a beta cut-off, it is reasonable to assume
            // that _do_ making a move would _definitely_ produce a cut-off.
            // (assuming that making a move always improves the position).
            // Test it (= make no move) quickly, with a reduced depth (-2).
            // alpha == beta - 1 : only try null moves when not in the PV
            if (canDoNullMove && alpha == beta - 1 && depth >= 2 && !isInCheck && !board.HasZugZwang())
            {
               Move nullMove = Move.NullMove();
               board.MakeMove(nullMove);
               // This might screw up the PV !!
               nullMoveCounter++;
               plyNr++;
               int nullMoveScore;
               // adaptive null-move pruning
               if (depth > 6)
                  nullMoveScore = -AlphaBeta(depth - 1 - 3, -beta, -beta + 1, false, canDoLMR);  // 3-depth reduction
               else
                  nullMoveScore = -AlphaBeta(depth - 1 - 2, -beta, -beta + 1, false, canDoLMR);  // 2-depth reduction
               plyNr--;
               nullMoveCounter--;
               board.UnMakeMove(nullMove);
               if (nullMoveScore >= beta)
                  return nullMoveScore;            // was beta
            }
             }

             // extended futility pruning
             // not sure is this is done in the right way, but it seems to work very well.
             bool doPruneFutilities = false;
             if (useFutilityPruning)
             {
            if ( (depth==2 || depth == 3) && Math.Abs(alpha) < Evaluator.FutureMate && !isInCheck && !haveExtended)
            {
               //int fastEval = evaluator.GetFastEvaluation();
               // do full evaluation (?)
               int fastEval = evaluator.GetEvaluation(alpha, beta);
               // nb : depth=0 is unused, since it already went to QSearch
               // nb : depth=1 makes just 1 move and then goes to QSearch. Pruning this does not work very well.
               int[] margin = { 0, 0, 125, 300 };
               if (fastEval + margin[depth] < alpha)
                  doPruneFutilities = true;
            }
             }

             // generate moves
             moveMatrix[plyNr] = moveGenerator.GenerateMoves(moveMatrix[plyNr]);
             nrGeneratedMovesInPly[plyNr] = moveGenerator.nrGeneratedMoves;
             // statically order the moves, so the (hopefully) best are tried first : Good for AlphaBeta
             ScoreMoves(plyNr);

             // singular move extension
             //   if (nrGeneratedMovesInPly[plyNr] == 1)
             //      depth++;

             // loop over all generated moves
             bool legalMoveIsMade = false;
             Move bestMove = Move.NoMove();
             int bestScore = -10 * Evaluator.MateValue;

             for (int i = 0; i < nrGeneratedMovesInPly[plyNr]; i++)
             {
            // If we are out of time, quit. Don't care about the score, since this entire depth is not used.
            if (abortSearch)
               return 0;

            Move currentMove = moveMatrix[plyNr][FindBestMoveNr(plyNr)];

            // check if this move is legal
            if (!board.MakeMove(currentMove))
            {
               // the move is illegal, e.g. by illegal castle or leaving king in check.
               board.UnMakeMove(currentMove);
               continue;
            }

            bool moveGivesCheck = board.IsInCheck();

            if (doPruneFutilities)
            {
               // don't futility prune : captures, 'special'-moves && putting king in check, no legal move was made
               if (legalMoveIsMade && !moveGivesCheck && currentMove.seeScore <= 0
                                   && currentMove.moveType < Const.EnPassantCaptureID)
               {
                  board.UnMakeMove(currentMove);
                  continue;
               }
            }

            legalMoveIsMade = true;
            //
            if (plyNr == 0)
               currentRootMoveNr = i;        // keep track of which root-move we are trying
            //
            int score;
            plyNr++;

            if (UsePVSearch)
            {
               if (i == 0)
                  // assume the first move is the best (&legal). Search it with the normal window.
                  score = -AlphaBeta(depth - 1, -beta, -alpha, true, canDoLMR);
               else
               {
                  // The next moves are considered to be worse.
                  // Check this with a 'very' narrow window

                  // try reduction on the 'not' so important moves
                  // But : not for captures, pawn-moves, special moves, checks, root-moves
                  if (useLateMoveReduction && canDoLMR
                     && i >= 4 && depth >= 3     // depth 3 & 5 gave identical results after 43 games
                     && !haveExtended
                     && currentMove.captureInfo == Const.NoCaptureID
                     && currentMove.moveType < Const.PawnID     // dont reduces pawn- & special-moves
               //      && currentMove.moveType < Const.CastleQSID     // dont reduces pawn- & special-moves
                     && plyNr > 1                               // 1=root : don't reduce the root
                     && !isInCheck
                     && !moveGivesCheck)
                  {
                     // a reduced PV search
                     bool canDoMoreRecuctions = useOnly1LateMoveReduction ? false : true;
                     score = -AlphaBeta(depth - 2, -alpha - 1, -alpha, true, canDoMoreRecuctions);
                     // If it was not worse but better, research it with a normal & unreduced window.
                     if (score > alpha)
                        score = -AlphaBeta(depth - 1, -beta, -alpha, true, canDoLMR);
                  }
                  else
                  {
                     // a normal PV search
                     score = -AlphaBeta(depth - 1, -alpha - 1, -alpha, true, canDoLMR);
                     // If it was not worse but better, research it with a normal window.
                     // If it's >= beta, don't worry, it will be cut-off.
                     if (score > alpha && score < beta)
                        score = -AlphaBeta(depth - 1, -beta, -score, true, canDoLMR);
                  }
               }
            }
            else
               score = -AlphaBeta(depth - 1, -beta, -alpha, true, canDoLMR);

            plyNr--;
            board.UnMakeMove(currentMove);

            // If we are out of time, quit. Don't care about the score, since this entire depth will be discarded.
            if (abortSearch)
               return 0;

            if (score > bestScore)
            {
               // The score is better then was attained before. Store it and compare it to alpha and beta.
               bestScore = score;
               bestMove = currentMove;

               if (bestScore > alpha)
               {
                  if (bestScore >= beta)
                  {
                     // To good to be true. The opponent will never let us get in this position.
                     // Store the move which caused the cut-off, and quit.
                     StoreKillerAndHistory(currentMove, depth);
                     if (bestScore != 0)          // don't store draw-values ??
                        transpositionTable.Put(board.HashValue, bestScore, TranspositionTable.lowerBound
                                              , depth, board.halfMoveNr, bestMove.Compress());
                     return bestScore;
                  }

                  alpha = bestScore;
                  // update the PV_Matrix;
                  if (!dontStoreNullMoveInPV || nullMoveCounter == 0)
                  {
                     int nrPVMovesToCopy = nrMovesInPVLine[plyNr + 1];
                     if (PV_Matrix[plyNr].Length < nrPVMovesToCopy + 1)
                        PV_Matrix[plyNr] = new Move[nrPVMovesToCopy + 10];
                     // store the current move, since it was better
                     PV_Matrix[plyNr][0] = currentMove;
                     // Append the current moves of the searched tree, since the current move is better.
                     Array.Copy(PV_Matrix[plyNr + 1], 0, PV_Matrix[plyNr], 1, nrPVMovesToCopy);
                     nrMovesInPVLine[plyNr] = nrPVMovesToCopy + 1;
                  }
               }
            }
             }

             if (legalMoveIsMade)
             {
            // update transposition table.
            if (useTTable)
            {

               /*
               // correct the mate-score ??
               if (Math.Abs(ttScore) > Evaluator.FutureMate && Math.Abs(ttScore) <= Evaluator.MateValue)
               {
                  if (ttScore > Evaluator.FutureMate)
                     ttScore += plyNr;
                  else
                     ttScore -= plyNr;
               }
               */
               if (bestScore != 0)          // don't store draw-values ??
               {
                  if (bestScore > initialAlpha)
                     transpositionTable.Put(board.HashValue, bestScore, TranspositionTable.exactBound
                                            , depth, board.halfMoveNr, bestMove.Compress());
                  else if (StoreUpperBoundsInTT)
                     transpositionTable.Put(board.HashValue, bestScore, TranspositionTable.upperBound
                                           , depth, board.halfMoveNr, bestMove.Compress());
               }
            }
            return bestScore;   // the current best possible score.
             }
             else
             {
            // no legal move could be made : either CheckMate or StaleMate
            if (board.IsInCheck())
               return -Evaluator.MateValue + plyNr ;   // CheckMate.    +PlyNr : promote fastest checkmates
              // return -Evaluator.MateValue + plyNr - 1;   // CheckMate.    +PlyNr : promote fastest checkmates
            else
               return 0;              // StaleMate : this must be done better !!
             }
        }
예제 #18
0
 public void UnMakeMove(Move move)
 {
     int prevColorToMove = colorToMove;
      // This is the color which made the move :
      ToggleMoveColor();
      // decrement the HalfMoveNr
      halfMoveNr--;
      //
      if (move.moveType < Const.SpecialMoveID)
      {
     // un-make the move
     MovePieceOnBoard(move.toPosition, move.fromPosition);
      }
      else
      {
     // Unmake specials
     // it is a Castle, enpassant capture, 2-stap pawn move or pawn promotion
     int castleRankOffset = colorToMove * 56;
     switch (move.moveType)
     {
        case Const.CastleQSID:
           MovePieceOnBoard(castleRankOffset + 2, castleRankOffset + 4);  // King
           MovePieceOnBoard(castleRankOffset + 3, castleRankOffset + 0);  // Rook
           break;
        case Const.CastleKSID:
           MovePieceOnBoard(castleRankOffset + 6, castleRankOffset + 4);  // King
           MovePieceOnBoard(castleRankOffset + 5, castleRankOffset + 7);  // Rook
           break;
        case Const.EnPassantCaptureID:
           MovePieceOnBoard(move.toPosition, move.fromPosition);
           break;
        case Const.PawnPromoteQueenID:
        case Const.PawnPromoteRookID:
        case Const.PawnPromoteBishopID:
        case Const.PawnPromoteKnightID:
           RemovePieceFromBoard(move.toPosition);     // the promoted piece
           AddNewPieceToBoard(colorToMove, Const.PawnID, move.fromPosition);
           break;
        case Const.Pawn2StepID:
           MovePieceOnBoard(move.toPosition, move.fromPosition);
           int oldEPPos = (move.toPosition + move.fromPosition)/2;
           break;
        case Const.NullMoveID:
           break;
        default:
           throw new Exception("Invalid special move nr");
     }
      }
      // was it a capture ? Yes : restore the captured piece
      if (capturedPieceType != Const.InvalidID)
     AddNewPieceToBoard(prevColorToMove, capturedPieceType, capturedPiecePosition);
      // Last restore the BoardState as it was just after the move. This also restores the HashValue.
      RestoreBoardState();
     #if HashDebug
      if (HashValue != CalcHashValue())
        throw new ApplicationException("hash differs");
     #endif
      nrHashValuesInHistory--;
 }