Ejemplo n.º 1
0
 public static void UndoMove()
 {
     if (m_movesHistory.Count > 0)
     {
         Move moveUndo = m_movesHistory.Item(m_movesHistory.Count - 1);
         m_playerToPlay.Clock.Revert();
         m_movesRedoList.Add(moveUndo);
         Move.Undo(moveUndo);
         m_playerToPlay = m_playerToPlay.OtherPlayer;
         if (m_movesHistory.Count > 1)
         {
             Move movePenultimate = m_movesHistory.Item(m_movesHistory.Count - 2);
             m_playerToPlay.Clock.TimeElapsed = movePenultimate.TimeStamp;
         }
         else
         {
             m_playerToPlay.Clock.TimeElapsed = new TimeSpan(0);
         }
         m_playerToPlay.Clock.Start();
     }
 }
Ejemplo n.º 2
0
        private int AlphaBeta(Player player, int depth, int alpha, int beta, bool verify, ref Move moveAnalysed)
        {
            int val = int.MinValue;

            HashTable.enmHashType hashType = HashTable.enmHashType.Alpha;
            Move moveBest        = null;
            Move moveHash        = null;
            bool blnPVNode       = false;
            int  intScoreAtEntry = 0;
//			bool failhigh = false;
            bool blnAllMovesWereGenerated;
            int  intLegalMovesAttempted = 0;

            m_intPositionsSearched++;

            if ((val = HashTable.ProbeHash(Board.HashCodeA, Board.HashCodeB, depth, alpha, beta, player.Colour)) != HashTable.UNKNOWN)
            {
                // High values of "val" indicate that a checkmate has been found
                if (val > 1000000 || val < -1000000)
                {
                    val /= (m_intMaxSearchDepth - depth);
                }
                return(val);
            }

            if (player.CanClaimThreeMoveRepetition)
            {
                return(-player.OtherPlayer.Score);
            }

            // Depth <=0 means we're into Quiescence searching
            if (depth <= 0)
            {
                if (depth < m_intMaxQDepth)
                {
                    m_intMaxQDepth = depth;
                    if (m_intMaxQDepth < 0)
                    {
                        m_intMaxQDepth += 0;
                    }
                }
                intScoreAtEntry = val = -player.OtherPlayer.Score;      m_intEvaluations++;

                if (val > 100000000 || val < -100000000)
                {
                    val /= (m_intMaxSearchDepth - depth);
                }
                // Allow a deeper ply of search if a piece was captured or if a pawn was promoted,
                // or either side is in check.
                if (!(
                        moveAnalysed.PieceTaken != null
                        ||
                        moveAnalysed.Name == Move.enmName.PawnPromotion
                        ||
                        (moveAnalysed.IsInCheck || moveAnalysed.IsEnemyInCheck)
                        )
                    )
                {
                    return(val);
                }
            }

            if (Game.DisplayMoveAnalysisTree)
            {
                moveAnalysed.Moves = new Moves();
            }

            Move moveThis = null;

            // Get last iteration's best move from the Transition Table
            moveHash = HashTable.ProbeForBestMove(player.Colour);

            // Verified Null-move forward pruning
//			if (false && !player.IsInCheck && (!verify || depth > 1))
//			{

            // "Adaptive" Null-move forward pruning
            R = (depth > 6 && Game.Stage != Game.enmStage.End) ? 3 : 2;         //  << This is the "adaptive" bit
            // The rest is normal Null-move forward pruning
            if (depth >= 3)
            {
                Move moveNull = new Move(Game.TurnNo, 0, Move.enmName.NullMove, null, null, null, null, 0, 0);
                val = -AlphaBeta(player.OtherPlayer, depth - R - 1, -beta, -beta + 1, verify, ref moveNull);
                if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                {
                    goto TimeExpired;
                }
                if (val >= beta)
                {
//					if (verify)
//					{
//						depth--; /* reduce the depth by one ply */
//						/* turn verification off for the sub-tree */
//						verify = false;
//						/* mark a fail-high flag, to detect zugzwangs later*/
//						failhigh = true;
//					}
//					else /* cutoff in a sub-tree with fail-high report */
//					{
//						return val;
                    return(beta);
//					}
                }
            }

            // Generate moves
            Moves movesPossible = new Moves();

            blnAllMovesWereGenerated = (depth > 0 || (moveAnalysed.IsInCheck || moveAnalysed.IsEnemyInCheck));
            if (blnAllMovesWereGenerated)
            {
                player.GenerateLazyMoves(depth, movesPossible, Moves.enmMovesType.All, null);
            }
            else
            {
                // Captures only
                player.GenerateLazyMoves(depth, movesPossible, Moves.enmMovesType.Recaptures_Promotions, moveAnalysed.To);
            }


            // Enhanced Transposition Cutoff
            foreach (Move movex in movesPossible)
            {
                if (((val = HashTable.ProbeHash(movex.HashCodeA, movex.HashCodeB, depth, alpha, beta, player.Colour)) != HashTable.UNKNOWN) && val >= beta)
                {
                    return(beta);
                }
            }

            // Sort moves
            foreach (Move movex in movesPossible)
            {
                movex.Score = 0;

                if (moveHash != null && movex.From.Ordinal == moveHash.From.Ordinal && movex.To.Ordinal == moveHash.To.Ordinal)
                {
                    movex.Score += 1000000;
                }

                if (movex.Name == Move.enmName.PawnPromotion)
                {
                    movex.Score += 10000;
                }

                if (movex.PieceTaken != null)
                {
//						if (depth>=5)
//						{
                    // SEE (Static Exchange Evaluation)
//							Move moveSee = movex.Piece.SEEMove(movex.Name, movex.To);
//							movex.Score += -SEE(player.OtherPlayer, int.MinValue, int.MaxValue, movex.To);
//							Move.SEEUndo(moveSee);
//						}
//						else
//						{
                    // MVV/LVA (Most Valuable Victim/Least Valuable Attacker)
                    movex.Score += (movex.PieceTaken.Value - movex.Piece.Value / 10);
//						}
                }
                else
                {
                    movex.Score += (History.Retrieve(player.Colour, movex.From.Ordinal, movex.To.Ordinal) >> 6);
                }
            }
            movesPossible.SortByScore();

//			ReSearch:

            foreach (Move move in movesPossible)
            {
                moveThis = move.Piece.Move(move.Name, move.To);

                if (moveThis.IsInCheck)
                {
                    Move.Undo(moveThis); continue;
                }

                intLegalMovesAttempted++;

                if (moveBest == null)
                {
                    moveBest = moveThis;
                }

/*
 *                              // Futility Pruning
 *                              switch (depth)
 *                              {
 *                                      case 2:
 *                                      case 3:
 *                                              if (move.PieceTaken==null && !moveThis.IsInCheck && !move.IsEnemyInCheck)
 *                                              {
 *                                                      if ( (val = HashTable.ProbeHash(Board.HashCodeA, Board.HashCodeB, depth, alpha, beta, player.Colour)) == HashTable.UNKNOWN )
 *                                                      {
 *                                                              val = -player.OtherPlayer.Score;	m_intEvaluations++;
 *                                                              HashTable.RecordHash(Board.HashCodeA, Board.HashCodeB, depth, val, HashTable.enmHashType.Exact, -1, -1, Move.enmName.NullMove, player.Colour);
 *                                                      }
 *
 *                                                      switch (depth)
 *                                                      {
 *                                                              case 2:
 *                                                                      // Standard Futility Pruning
 *                                                                      if (val+2500<=alpha)
 *                                                                      {
 *                                                                              depth--;
 *                                                                      }
 *                                                                      break;
 *
 *                                                              case 3:
 *                                                                      // Extended Futility Pruning
 *                                                                      if (val+6500<=alpha)
 *                                                                      {
 *                                                                              depth--;
 *                                                                      }
 *                                                                      break;
 *                                                      }
 *                                              }
 *                                              break;
 *                              }
 */
                if (Game.DisplayMoveAnalysisTree)
                {
// Add moves to post-move analysis tree, if option set by user
                    moveAnalysed.Moves.Add(moveThis);
                }
                if (blnPVNode)
                {
                    val = -AlphaBeta(player.OtherPlayer, depth - 1, -alpha - 1, -alpha, verify, ref moveThis);
                    if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                    {
                        Move.Undo(moveThis); goto TimeExpired;
                    }
                    if ((val > alpha) && (val < beta))                     /* fail */
                    {
                        val = -AlphaBeta(player.OtherPlayer, depth - 1, -beta, -alpha, verify, ref moveThis);
                        if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                        {
                            Move.Undo(moveThis); goto TimeExpired;
                        }
                    }
                }
                else
                {
                    val = -AlphaBeta(player.OtherPlayer, depth - 1, -beta, -alpha, verify, ref moveThis);
                    if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                    {
                        Move.Undo(moveThis); goto TimeExpired;
                    }
                }

                if (!blnAllMovesWereGenerated && val < intScoreAtEntry)
                {
                    // This code is executed mostly in quiescence when not all moves are tried (maybe just captures)
                    // and the best score we've got is worse than the score we had before we considered any moves
                    // then revert to that score, because we dont want the computer to think that it HAS to make a capture
                    val = intScoreAtEntry;
                }

                move.Score = moveThis.Score = val;

                Move.Undo(moveThis);

                if (val >= beta)
                {
                    alpha         = beta;
                    moveThis.Beta = beta;
                    hashType      = HashTable.enmHashType.Beta;
                    moveBest      = moveThis;
                    goto Exit;
                }

                if (val > alpha)
                {
                    blnPVNode = true;                     /* This is a PV node */
                    alpha     = val;
                    hashType  = HashTable.enmHashType.Exact;
                    moveBest  = moveThis;
                }

                moveThis.Alpha = alpha;
                moveThis.Beta  = beta;
            }

            // Check for Stalemate
            if (intLegalMovesAttempted == 0)           // depth>0 && !player.OtherPlayer.IsInCheck
            {
                //	alpha = this.Score;
                alpha = -player.OtherPlayer.Score;
            }

/*			if(failhigh && alpha < beta)
 *                      {
 *                              depth++;
 *                              failhigh = false;
 *                              verify = true;
 *                              goto ReSearch;
 *                      }
 */

Exit:

            // Record best move
            if (moveBest != null)
            {
                History.Record(player.Colour, moveBest.From.Ordinal, moveBest.To.Ordinal, 0, 1 << (depth + 6));
                HashTable.RecordHash(Board.HashCodeA, Board.HashCodeB, depth, alpha, hashType, moveBest.From.Ordinal, moveBest.To.Ordinal, moveBest.Name, player.Colour);
            }
            else
            {
                HashTable.RecordHash(Board.HashCodeA, Board.HashCodeB, depth, alpha, hashType, -1, -1, Move.enmName.NullMove, player.Colour);
            }

TimeExpired:
            return(alpha);
        }
Ejemplo n.º 3
0
        public Move ComputeBestMove()
        {
            m_blnIsThinking = true;

            Player player = this;

            m_moveBest = null;
            Move moveHash    = null;
            int  alpha_start = this.Score;

/* Uncomment to switch-on opening book moves, once we have a decent opening book!
 *                      // Query Opening Book
 *                      if ((m_moveBest = OpeningBook.SearchForGoodMove(Board.HashKey, this.Colour) )!=null)
 *                      {
 *                              m_moveCurrent = m_moveBest;
 *                              this.MoveConsidered();
 *                              return m_moveBest.Piece.Move(m_moveBest.Name, m_moveBest.To);
 *                      }
 */
            Move moveDepthBest = null;
            int  alpha         = MIN_SCORE;
            int  beta          = MAX_SCORE;

            m_intRootScore = this.Score;

            m_tsnThinkingTimeAllotted   = new TimeSpan(this.m_PlayerClock.TimeRemaining.Ticks / Math.Max(m_intGameMoves - (Game.TurnNo / 2), 1));
            m_tsnThinkingTimeMaxAllowed = new TimeSpan(m_tsnThinkingTimeAllotted.Ticks * 3);
            m_tsnThinkingTimeHalved     = new TimeSpan(m_tsnThinkingTimeAllotted.Ticks / 3);

            m_intEvaluations       = 0;
            m_intPositionsSearched = 0;

            HashTable.ResetStats();
//			HashTable.Clear();   Uncomment this to clear the hashtable at the beginning of each move
            HashTableCheck.ResetStats();
            HashTablePawn.ResetStats();
            History.Clear();

            for (m_intSearchDepth = m_intMinSearchDepth; m_intSearchDepth <= m_intMaxSearchDepth; m_intSearchDepth++)
            {
                if (Game.DisplayMoveAnalysisTree)
                {
                    Game.MoveAnalysis = new Moves();
                }
                m_intMaxQDepth = m_intSearchDepth;

                // Get last iteration's best move from the HashTable
                moveHash = HashTable.ProbeForBestMove(player.Colour);

                // Generate and sort moves
                Moves movesPossible = new Moves();
                player.GenerateLegalMoves(movesPossible);
                m_intTotalMoves = movesPossible.Count;

                // If only one move is available, then just play it!
                if (movesPossible.Count == 1)
                {
                    moveDepthBest = m_moveCurrent = movesPossible.Item(0);
                    goto MoveSelected;
                }
                // Sort moves
                foreach (Move movex in movesPossible)
                {
                    movex.Score = 0;

                    if (moveHash != null && movex.From.Ordinal == moveHash.From.Ordinal && movex.To.Ordinal == moveHash.To.Ordinal)
                    {
                        movex.Score += 1000000;
                    }

                    if (movex.Name == Move.enmName.PawnPromotion)
                    {
                        movex.Score += 10000;
                    }

                    if (movex.PieceTaken != null)
                    {
                        Move moveSee = movex.Piece.SEEMove(movex.Name, movex.To);
                        movex.Score += -SEE(player.OtherPlayer, int.MinValue, int.MaxValue, movex.To);
                        Move.SEEUndo(moveSee);
                    }
                    else
                    {
                        movex.Score += History.Retrieve(player.Colour, movex.From.Ordinal, movex.To.Ordinal);
                    }
                }
                movesPossible.SortByScore();

                alpha = MIN_SCORE;
                beta  = MAX_SCORE;

                m_intCurrentMoveNo = 0;

                foreach (Move move in movesPossible)
                {
                    m_moveCurrent = move.Piece.Move(move.Name, move.To);

                    if (m_moveCurrent.IsInCheck)
                    {
                        Move.Undo(m_moveCurrent); continue;
                    }

                    move.Score = m_moveCurrent.Score = -AlphaBeta(player.OtherPlayer, m_intSearchDepth - 1, -alpha - 1, -alpha, true, ref m_moveCurrent);
                    if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                    {
                        Move.Undo(m_moveCurrent); goto TimeExpired;
                    }

                    if ((move.Score > alpha) && (move.Score < beta))                     /* fail */
                    {
                        move.Score = m_moveCurrent.Score = -AlphaBeta(player.OtherPlayer, m_intSearchDepth - 1, -beta, -alpha, true, ref m_moveCurrent);
                        if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeMaxAllowed)
                        {
                            Move.Undo(m_moveCurrent); goto TimeExpired;
                        }
                    }

                    this.MoveConsidered();

                    if (Game.DisplayMoveAnalysisTree)
                    {
                        Game.MoveAnalysis.Add(m_moveCurrent);
                    }

                    Move.Undo(m_moveCurrent);

                    m_intCurrentMoveNo++;

                    if (m_moveCurrent.Score > alpha)
                    {
                        alpha         = m_moveCurrent.Score;
                        moveDepthBest = m_moveCurrent;
                        History.Record(player.Colour, m_moveCurrent.From.Ordinal, m_moveCurrent.To.Ordinal, alpha - alpha_start, 1 << (m_intSearchDepth + 6));                   // Update history heuristic data
                    }

                    m_moveCurrent.Alpha = alpha;
                    m_moveCurrent.Beta  = beta;
                }

MoveSelected:

                m_moveBest = moveDepthBest;

                // Record best move
                HashTable.RecordHash(Board.HashCodeA, Board.HashCodeB, m_intSearchDepth, m_moveBest.Score, HashTable.enmHashType.Exact, m_moveBest.From.Ordinal, m_moveBest.To.Ordinal, m_moveBest.Name, player.Colour);

                this.MoveConsidered();

                if ((DateTime.Now - m_PlayerClock.TurnStartTime) > m_tsnThinkingTimeHalved && m_intSearchDepth >= m_intMinimumPlys)
                {
                    goto TimeExpired;
                }

                if (m_moveBest.Score > 99999)
                {
                    break;                                           // Checkmate found so dont bother searching any deeper
                }
            }


TimeExpired:
            this.MoveConsidered();

            m_blnIsThinking = false;
            this.MoveConsidered();

            return(m_moveBest);
        }