Exemple #1
0
 public Player(ChessGame game)
 {
     this.Game  = game;
     IsComputer = false;
 }
        /// <summary>
        /// Recursive method to find the best move in a given position. Min-max algorithm alternates
        /// between black and white.
        /// </summary>
        /// <param name="board"></param>
        /// <param name="turn"></param>
        /// <param name="possibleMoves"></param>
        /// <param name="level">Number of half moves to look forward.</param>
        /// <param name="topLevel">True if this is the outermost call.</param>
        /// <param name="alpha"></param>
        /// <param name="beta"></param>
        /// <param name="bestMove"></param>
        /// <returns></returns>
        private int CalculateMove(ChessBoard board, ChessPieceColor turn, List <ChessMove> possibleMoves, int level, bool topLevel,
                                  int alpha, int beta, out ChessMove bestMove, int initialDepth)
        {
            int best_score = -INFINITY;

            bestMove = null;

            if (!Stop)
            {
                int i = 0;
                foreach (ChessMove possibleMove in possibleMoves)
                {
                    if (topLevel && ((depthToVisualize != 0 && initialDepth >= depthToVisualize) || (depthToVisualize == 0 && initialDepth > 2)))
                    {
                        RaiseConsideringMoveEvent(possibleMove);
                    }

                    i++;

                    ChessBoard resBoard = new ChessBoard(board);
                    resBoard.ApplyMove(turn, possibleMove, null);

                    int move_score = 0;
                    if (level == 0)
                    {
#if PROF
                        prof.Start("StaticEval");
#endif
                        move_score = StaticEvaluation(resBoard, turn);
#if PROF
                        prof.End("StaticEval");
#endif
                    }
                    else
                    {
                        ChessMove        m       = null;
                        ChessPieceColor  newTurn = ChessGame.InvertColor(turn);
                        List <ChessMove> moves   = ChessGame.GetPossibleMoves(resBoard, newTurn);
                        bool             abort   = false;

                        if (moves.Count == 0)
                        {
                            if (!ChessGame.IsInCheck(board, newTurn))
                            {
                                // Stale mate, good depending on piece value.
                                int whiteValue = 0;
                                int blackValue = 0;
                                board.GetPiecesValue(out whiteValue, out blackValue);

                                int delta = (turn == ChessPieceColor.White ? whiteValue - blackValue : blackValue - whiteValue);
                                if (delta > 0)
                                {
                                    move_score = -10000;
                                }
                                else
                                {
                                    move_score = 10000;
                                }
                            }
                            else
                            {
                                int checkMateScore = 50000 + level * 100; // Prioritize early check mate.

                                move_score = checkMateScore;              // Check mate.
                            }
                        }
                        else
                        {
                            move_score = -CalculateMove(resBoard, newTurn, moves, level - 1, false, -beta, -alpha, out m, initialDepth);
                            if (m == null)  // Abort
                            {
                                abort = true;
                            }
                        }

                        if (abort)  // Abort
                        {
                            bestMove   = null;
                            best_score = -INFINITY;
                            break;
                        }
                    }

                    if (topLevel)
                    {
                        // Decrease score for repetition moves.
                        if (Game.ChessMoves.Count >= 3)
                        {
                            ChessMove myLastMove     = Game.ChessMoves[Game.ChessMoves.Count - 2];
                            ChessMove oppLastMove    = Game.ChessMoves[Game.ChessMoves.Count - 1];
                            ChessMove oppSecLastMove = Game.ChessMoves[Game.ChessMoves.Count - 3];

                            if (myLastMove.FromIndex == possibleMove.ToIndex &&
                                myLastMove.ToIndex == possibleMove.FromIndex &&
                                !myLastMove.IsCapture &&
                                oppLastMove.FromIndex == oppSecLastMove.ToIndex &&
                                oppLastMove.ToIndex == oppSecLastMove.FromIndex &&
                                !oppLastMove.IsCapture && !oppSecLastMove.IsCapture)    // TODO: check for IsCapture in possibleMove
                            {
                                move_score -= 30;
                            }
                        }
                    }

#if LOGGING
                    Debug.WriteLine(string.Format("{0}Level {1} {2} {3} alpha {4} beta {5}", GetIndent(level), level, possibleMove.ToString(), move_score, alpha, beta));
#endif
                    if (move_score > best_score)
                    {
                        best_score = move_score;
                        bestMove   = possibleMove;
                    }

                    if (best_score > alpha)
                    {
                        alpha = best_score;
                    }

                    if (alpha >= beta)
                    {
                        return(alpha);   // This means the move is as good as or worse than a previous move.
                    }
                }
            }

            return(best_score);
        }
        private ChessMove GetNextMove()
        {
            int startTicks = (int)DateTime.Now.Ticks;

            ChessMove move = null;

            Progress = 0;
            Aborted  = false;
            Stop     = false;

            // Try opening book first.
            move = openingBook.GetNextMove(Game.ChessMoves);
            if (move != null && Game.MakeMove(move, true))
            {
#if !NETFX_CORE
                Thread.Sleep(200);
#endif
            }
            else
            {
#if LOGGING
                Debug.WriteLine(string.Format("Calc start"));
#endif

#if NETFX_CORE
                MyTimer timer = null;
                if (TimeLimit > 0)
                {
                    timer = new MyTimer(OutOfTime, null, TimeLimit, System.Threading.Timeout.Infinite);
                    Debug.WriteLine("Timer " + TimeLimit);
                }
#else
                Timer timer = null;
                if (TimeLimit > 0)
                {
                    timer = new Timer(OutOfTime, null, TimeLimit, System.Threading.Timeout.Infinite);
                    Debug.WriteLine("Timer " + TimeLimit);
                }
#endif

                List <ChessMove> possibleMoves = ChessGame.GetPossibleMoves(Game.Board, Game.Turn);
                // Iterative deepening.
                int depth = 0;
                while (true)
                {
                    ChessMove bestMove = null;

                    Game.AddLog(string.Format("lvl {0} start depth {1}", (int)DifficultyLevel, depth));

                    int calcStartTicks = (int)DateTime.Now.Ticks;
                    CalculateMove(Game.Board, Game.Turn, possibleMoves, depth, true, -INFINITY, INFINITY, out bestMove, depth);

                    int calcTimeTicks = (int)DateTime.Now.Ticks - calcStartTicks;
                    Game.AddLog(string.Format("end depth {0} ticks {1} bestMove {2}", depth, calcTimeTicks, (bestMove == null ? 0 :1)));

                    Debug.WriteLine(string.Format("dTV: {0} time: {1}", depthToVisualize, calcTimeTicks / TimeSpan.TicksPerSecond));
                    if (depthToVisualize == 0 && ((float)calcTimeTicks / (float)TimeSpan.TicksPerSecond) > 0.3f)
                    {
                        depthToVisualize = depth;
                    }

                    if (bestMove != null)
                    {
                        move = bestMove;
                    }

                    if (bestMove == null || DepthLimit > 0 && depth >= DepthLimit)
                    {
                        if (timer != null)
                        {
                            timer.Dispose();
                        }
                        break;
                    }
                    else
                    {
                        // Move the move to the beginning of the list.
                        if (possibleMoves.Remove(move))
                        {
                            possibleMoves.Insert(0, move);
                        }
                    }
                    depth++;
                }

#if LOGGING
                Debug.WriteLine(string.Format("Calc end."));
#endif
            }

            gameTicks += (int)DateTime.Now.Ticks - startTicks;

            return(move);
        }
Exemple #4
0
 /// <summary>
 /// Creates a new board.
 /// </summary>
 public ChessBoard(ChessGame game)
 {
     this.Game = game;
     InitBoardState();
     this.capturedPieces = new List <ChessPiece>();
 }
Exemple #5
0
        public void ApplyMove(ChessPieceColor color, ChessMove move, ChessMoveInfo moveInfo)
        {
            // Make the move...
            ulong fromPos = Precomputed.IndexToBitBoard[(int)move.FromIndex];
            ulong toPos   = Precomputed.IndexToBitBoard[(int)move.ToIndex];

            ulong capturePos = toPos;

            if (moveInfo != null)
            {
                moveInfo.MovedBy = color;
            }

            count50MoveRule++;

            ChessBoardColorState boardState = GetBoardState(color);

            boardState.Pieces &= ~fromPos;  // Move the piece.
            boardState.Pieces |= toPos;     // Move the piece.
            switch (move.PieceType)
            {
            case ChessPieceType.Pawn:
                count50MoveRule = 0;

                boardState.Pawns &= ~fromPos;
                switch (move.PromotionPieceType)
                {
                case ChessPieceType.Knight:
                    boardState.Knights |= toPos;
                    break;

                case ChessPieceType.Bishop:
                    boardState.Bishops |= toPos;
                    break;

                case ChessPieceType.Rook:
                    boardState.Rooks |= toPos;
                    break;

                case ChessPieceType.Queen:
                    boardState.Queens |= toPos;
                    break;

                default:
                    boardState.Pawns |= toPos;
                    break;
                }

                if (color == ChessPieceColor.White)
                {
                    if ((Precomputed.WhitePawnCaptureMoves[(int)move.FromIndex] & toPos & (enPassantTarget << 8)) != 0)
                    {
                        capturePos      = enPassantTarget;
                        enPassantTarget = 0;
                    }
                    else if ((Precomputed.WhitePawnDoubleMoves[(int)move.FromIndex] & toPos) != 0)
                    {
                        enPassantTarget = toPos;
                    }
                    else
                    {
                        enPassantTarget = 0;
                    }
                }
                else
                {
                    if ((Precomputed.BlackPawnCaptureMoves[(int)move.FromIndex] & toPos & (enPassantTarget >> 8)) != 0)
                    {
                        capturePos      = enPassantTarget;
                        enPassantTarget = 0;
                    }
                    else if ((Precomputed.BlackPawnDoubleMoves[(int)move.FromIndex] & toPos) != 0)
                    {
                        enPassantTarget = toPos;
                    }
                    else
                    {
                        enPassantTarget = 0;
                    }
                }

                break;

            case ChessPieceType.Knight:
                enPassantTarget     = 0;
                boardState.Knights &= ~fromPos;
                boardState.Knights |= toPos;
                break;

            case ChessPieceType.Bishop:
                enPassantTarget     = 0;
                boardState.Bishops &= ~fromPos;
                boardState.Bishops |= toPos;
                break;

            case ChessPieceType.Rook:
                enPassantTarget   = 0;
                boardState.Rooks &= ~fromPos;
                boardState.Rooks |= toPos;

                if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A1]) != 0)
                {
                    whiteBoardState.QueensideCastlingPossible = false;
                }
                else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H1]) != 0)
                {
                    whiteBoardState.KingsideCastlingPossible = false;
                }
                else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A8]) != 0)
                {
                    blackBoardState.QueensideCastlingPossible = false;
                }
                else if ((fromPos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H8]) != 0)
                {
                    blackBoardState.KingsideCastlingPossible = false;
                }

                break;

            case ChessPieceType.Queen:
                enPassantTarget    = 0;
                boardState.Queens &= ~fromPos;
                boardState.Queens |= toPos;
                break;

            case ChessPieceType.King:
                enPassantTarget  = 0;
                boardState.King &= ~fromPos;
                boardState.King |= toPos;

                boardState.KingsideCastlingPossible  = false;
                boardState.QueensideCastlingPossible = false;

                if (move.IsKingsideCastling)
                {
                    if (color == ChessPieceColor.White)
                    {
                        MoveRookWhenCastling(color, ChessPositionIndex.H1, ChessPositionIndex.F1, moveInfo);
                    }
                    else
                    {
                        MoveRookWhenCastling(color, ChessPositionIndex.H8, ChessPositionIndex.F8, moveInfo);
                    }
                }
                else if (move.IsQueensideCastling)
                {
                    if (color == ChessPieceColor.White)
                    {
                        MoveRookWhenCastling(color, ChessPositionIndex.A1, ChessPositionIndex.D1, moveInfo);
                    }
                    else
                    {
                        MoveRookWhenCastling(color, ChessPositionIndex.A8, ChessPositionIndex.D8, moveInfo);
                    }
                }

                break;
            }

            ChessPieceColor      invertedColor      = ChessGame.InvertColor(color);
            ChessBoardColorState invertedBoardState = GetBoardState(invertedColor);

            if ((invertedBoardState.Pieces & capturePos) != 0)   // Check if there is a capture.
            {
                invertedBoardState.Pieces  &= ~capturePos;       // Remove the piece from all black pieces.
                invertedBoardState.Pawns   &= ~capturePos;
                invertedBoardState.Knights &= ~capturePos;
                invertedBoardState.Bishops &= ~capturePos;
                invertedBoardState.Rooks   &= ~capturePos;
                invertedBoardState.Queens  &= ~capturePos;

                move.IsCapture  = true;
                count50MoveRule = 0;
                if (moveInfo != null)
                {
                    moveInfo.CapturedPiecePos = (ChessPositionIndex)Util.fastBitScanForward(capturePos);
                }

                // PP 2012-12-24: when a rook is captured, castling is no longer possible.
                if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A1]) != 0)
                {
                    whiteBoardState.QueensideCastlingPossible = false;
                }
                else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H1]) != 0)
                {
                    whiteBoardState.KingsideCastlingPossible = false;
                }
                else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.A8]) != 0)
                {
                    blackBoardState.QueensideCastlingPossible = false;
                }
                else if ((capturePos & Precomputed.IndexToBitBoard[(int)ChessPositionIndex.H8]) != 0)
                {
                    blackBoardState.KingsideCastlingPossible = false;
                }
            }
        }
Exemple #6
0
 public void HookUp(ChessGame game)
 {
     this.Game = game;
 }