示例#1
0
        public virtual bool HasAnyValidMoves(Position from)
        {
            ChessUtilities.ThrowIfNull(from, "from");
            ReadOnlyCollection <Move> validMoves = GetValidMoves(from, true);

            return(validMoves.Count > 0);
        }
示例#2
0
        GameStatus CalculateStatus(Player playerToValidate, bool validateHasAnyValidMoves)
        {
            if (_drawn)
            {
                return(new GameStatus(GameEvent.Draw, Player.None, _drawReason));
            }
            if (_resigned != Player.None)
            {
                return(new GameStatus(GameEvent.Resign, _resigned, _resigned + " resigned"));
            }

            var other = ChessUtilities.GetOpponentOf(playerToValidate);

            if (IsInCheck(playerToValidate))
            {
                if (validateHasAnyValidMoves && !HasAnyValidMoves(playerToValidate))
                {
                    return(new GameStatus(GameEvent.Checkmate, other, playerToValidate + " is checkmated"));
                }

                return(new GameStatus(GameEvent.Check, other, playerToValidate + " is in check"));
            }

            if (validateHasAnyValidMoves && !HasAnyValidMoves(playerToValidate))
            {
                return(new GameStatus(GameEvent.Stalemate, other, "Stalemate"));
            }

            return(new GameStatus(GameEvent.None, Player.None, "No special event"));
        }
示例#3
0
        void UseGameCreationData(GameCreationData data)
        {
            Board     = CloneBoard(data.Board);
            WhoseTurn = data.WhoseTurn;
            Piece e1 = GetPieceAt(File.E, 1);
            Piece e8 = GetPieceAt(File.E, 8);
            Piece a1 = GetPieceAt(File.A, 1);
            Piece h1 = GetPieceAt(File.H, 1);
            Piece a8 = GetPieceAt(File.A, 8);
            Piece h8 = GetPieceAt(File.H, 8);

            _whiteKingMoved  |= (!(e1 is King) || e1.Owner != Player.White);
            _blackKingMoved  |= (!(e8 is King) || e8.Owner != Player.Black);
            _whiteRookAMoved |= (!(a1 is Rook) || a1.Owner != Player.White || !data.CanWhiteCastleQueenSide);
            _whiteRookHMoved |= (!(h1 is Rook) || h1.Owner != Player.White || !data.CanWhiteCastleKingSide);
            _blackRookAMoved |= (!(a8 is Rook) || a8.Owner != Player.Black || !data.CanBlackCastleQueenSide);
            _blackRookHMoved |= (!(h8 is Rook) || h8.Owner != Player.Black || !data.CanBlackCastleKingSide);

            if (data.EnPassant != null)
            {
                var latestMove =
                    new DetailedMove(
                        new Move(new Square(data.EnPassant.File, data.WhoseTurn == Player.White ? 7 : 2),
                                 new Square(data.EnPassant.File, data.WhoseTurn == Player.White ? 5 : 4),
                                 ChessUtilities.GetOpponentOf(data.WhoseTurn)),
                        new Pawn(ChessUtilities.GetOpponentOf(data.WhoseTurn)),
                        false,
                        CastlingType.None);

                _moves.Add(latestMove);
            }

            _halfMoveClock  = data.HalfMoveClock;
            _fullMoveNumber = data.FullMoveNumber;
        }
示例#4
0
        public virtual bool WouldBeInCheckAfter(Move move, Player player)
        {
            ChessUtilities.ThrowIfNull(move, "move");
            GameCreationData gcd = new GameCreationData();

            gcd.Board = Board;
            gcd.CanWhiteCastleKingSide  = CanWhiteCastleKingSide;
            gcd.CanWhiteCastleQueenSide = CanWhiteCastleQueenSide;
            gcd.CanBlackCastleKingSide  = CanBlackCastleKingSide;
            gcd.CanBlackCastleQueenSide = CanBlackCastleQueenSide;
            gcd.EnPassant = null;
            if (_moves.Count > 0)
            {
                DetailedMove last = _moves.Last();
                if (last.Piece is Pawn && new PositionDistance(last.OriginalPosition, last.NewPosition).DistanceY == 2)
                {
                    gcd.EnPassant = new Position(last.NewPosition.File, last.Player == Player.White ? 3 : 6);
                }
            }
            gcd.HalfMoveClock  = i_halfMoveClock;
            gcd.FullMoveNumber = i_fullMoveNumber;
            ChessGame copy = new ChessGame(gcd);
            Piece     p    = copy.GetPieceAt(move.OriginalPosition);

            copy.SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null);
            copy.SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, p);
            return(copy.IsInCheck(player));
        }
示例#5
0
        public bool WouldBeInCheckAfter(Move move, Player player)
        {
            ChessUtilities.ThrowIfNull(move, nameof(move));
            var gcd = new GameCreationData();

            gcd.Board = Board;
            gcd.CanWhiteCastleKingSide  = !_whiteRookHMoved && !_whiteKingMoved;
            gcd.CanWhiteCastleQueenSide = !_whiteRookAMoved && !_whiteKingMoved;
            gcd.CanBlackCastleKingSide  = !_blackRookHMoved && !_blackKingMoved;
            gcd.CanBlackCastleQueenSide = !_blackRookAMoved && !_blackKingMoved;
            gcd.EnPassant = null;

            if (_moves.Count > 0)
            {
                var last = _moves.Last();
                if (last.Piece is Pawn && new SquareDistance(last.OriginalPosition, last.NewPosition).DistanceY == 2)
                {
                    gcd.EnPassant = new Square(last.NewPosition.File, last.Player == Player.White ? 3 : 6);
                }
            }

            gcd.HalfMoveClock  = _halfMoveClock;
            gcd.FullMoveNumber = _fullMoveNumber;

            var copy = new ChessGame(gcd);

            copy.ApplyMove(move, true);

            var status = copy.CalculateStatus(player, false);

            return(status.Event == GameEvent.Check && status.PlayerWhoCausedEvent != player);
        }
示例#6
0
        ReadOnlyCollection <Move> GetValidMoves(Square from, bool returnIfAny)
        {
            ChessUtilities.ThrowIfNull(from, nameof(from));
            var piece = GetPieceAt(from);

            return(piece == null || piece.Owner != WhoseTurn ? new ReadOnlyCollection <Move>(new List <Move>())
                                                             : piece.GetValidMoves(from, returnIfAny, this));
        }
示例#7
0
        protected virtual ReadOnlyCollection <Move> GetValidMoves(Position from, bool returnIfAny)
        {
            ChessUtilities.ThrowIfNull(from, "from");
            Piece piece = GetPieceAt(from);

            if (piece == null || piece.Owner != WhoseTurn)
            {
                return(new ReadOnlyCollection <Move>(new List <Move>()));
            }
            return(piece.GetValidMoves(from, returnIfAny, this, IsValidMove));
        }
示例#8
0
 protected static Piece[][] CloneBoard(Piece[][] originalBoard)
 {
     ChessUtilities.ThrowIfNull(originalBoard, "originalBoard");
     Piece[][] newBoard = new Piece[originalBoard.Length][];
     for (int i = 0; i < originalBoard.Length; i++)
     {
         newBoard[i] = new Piece[originalBoard[i].Length];
         Array.Copy(originalBoard[i], newBoard[i], originalBoard[i].Length);
     }
     return(newBoard);
 }
示例#9
0
        protected virtual void UseGameCreationData(GameCreationData data)
        {
            Board     = CloneBoard(data.Board);
            WhoseTurn = data.WhoseTurn;

            Piece[] eighthRank = Board[0];
            Piece[] firstRank  = Board[7];

            CanBlackCastleKingSide = CanBlackCastleQueenSide = CanWhiteCastleKingSide = CanWhiteCastleQueenSide = CastlingCanBeLegal;
            InitialWhiteKingFile   = (File)Array.IndexOf(firstRank, new King(Player.White));
            InitialBlackKingFile   = (File)Array.IndexOf(eighthRank, new King(Player.Black));
            if (CastlingCanBeLegal)
            {
                CanBlackCastleKingSide  = data.CanBlackCastleKingSide;
                CanBlackCastleQueenSide = data.CanBlackCastleQueenSide;
                CanWhiteCastleKingSide  = data.CanWhiteCastleKingSide;
                CanWhiteCastleQueenSide = data.CanWhiteCastleQueenSide;
            }
            InitialBlackRookFileQueensideCastling = CanBlackCastleQueenSide ? (File)Array.IndexOf(eighthRank, new Rook(Player.Black)) : File.None;
            InitialBlackRookFileKingsideCastling  = CanBlackCastleKingSide ? (File)Array.LastIndexOf(eighthRank, new Rook(Player.Black)) : File.None;
            InitialWhiteRookFileQueensideCastling = CanWhiteCastleQueenSide ? (File)Array.IndexOf(firstRank, new Rook(Player.White)) : File.None;
            InitialWhiteRookFileKingsideCastling  = CanWhiteCastleKingSide ? (File)Array.LastIndexOf(firstRank, new Rook(Player.White)) : File.None;

            if (InitialBlackRookFileQueensideCastling == File.None)
            {
                CanBlackCastleQueenSide = false;
            }
            if (InitialBlackRookFileKingsideCastling == File.None)
            {
                CanBlackCastleKingSide = false;
            }
            if (InitialWhiteRookFileKingsideCastling == File.None)
            {
                CanWhiteCastleKingSide = false;
            }
            if (InitialWhiteRookFileQueensideCastling == File.None)
            {
                CanWhiteCastleQueenSide = false;
            }

            if (data.EnPassant != null)
            {
                DetailedMove latestMove = new DetailedMove(new Move(new Position(data.EnPassant.File, data.WhoseTurn == Player.White ? 7 : 2),
                                                                    new Position(data.EnPassant.File, data.WhoseTurn == Player.White ? 5 : 4),
                                                                    ChessUtilities.GetOpponentOf(data.WhoseTurn)),
                                                           new Pawn(ChessUtilities.GetOpponentOf(data.WhoseTurn)),
                                                           false,
                                                           CastlingType.None);
                _moves.Add(latestMove);
            }

            i_halfMoveClock  = data.HalfMoveClock;
            i_fullMoveNumber = data.FullMoveNumber;
        }
示例#10
0
        protected virtual bool IsValidMove(Move move, bool validateCheck, bool careAboutWhoseTurnItIs)
        {
            ChessUtilities.ThrowIfNull(move, "move");
            if (move.OriginalPosition.Equals(move.NewPosition))
            {
                return(false);
            }
            Piece piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank);

            if (careAboutWhoseTurnItIs && move.Player != WhoseTurn)
            {
                return(false);
            }
            if (piece == null || piece.Owner != move.Player)
            {
                return(false);
            }
            Piece pieceAtDestination = GetPieceAt(move.NewPosition);
            bool  isCastle           = pieceAtDestination is Rook && piece is King && pieceAtDestination.Owner == piece.Owner;

            if (pieceAtDestination != null && pieceAtDestination.Owner == move.Player && !isCastle)
            {
                return(false);
            }
            if (!piece.IsValidMove(move, this))
            {
                return(false);
            }
            if (validateCheck)
            {
                if (!isCastle && WouldBeInCheckAfter(move, move.Player))
                {
                    return(false);
                }
            }

            return(true);
        }
示例#11
0
        bool IsValidMove(Move move, bool validateCheck, bool careAboutWhoseTurnItIs) // this is the weirdest bool ever. why wouldn't you care?
        {
            ChessUtilities.ThrowIfNull(move, nameof(move));
            if (move.OriginalPosition.Equals(move.NewPosition))
            {
                return(false);
            }

            var piece = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank);

            if (careAboutWhoseTurnItIs && move.Player != WhoseTurn)
            {
                return(false);
            }
            if (piece.Owner != move.Player)
            {
                return(false);
            }

            var pieceAtDestination = GetPieceAt(move.NewPosition);

            if (pieceAtDestination != null && pieceAtDestination.Owner == move.Player)
            {
                return(false);
            }
            if (!piece.IsValidMove(move, this))
            {
                return(false);
            }
            if (validateCheck && WouldBeInCheckAfter(move, move.Player))
            {
                return(false);
            }

            return(true);
        }
示例#12
0
        public virtual MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured)
        {
            ChessUtilities.ThrowIfNull(move, "move");
            captured = null;
            if (!alreadyValidated && !IsValidMove(move))
            {
                return(MoveType.Invalid);
            }
            MoveType type          = MoveType.Move;
            Piece    movingPiece   = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank);
            Piece    capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank);

            captured = capturedPiece;
            Piece        newPiece  = movingPiece;
            bool         isCapture = capturedPiece != null;
            CastlingType castle    = CastlingType.None;

            if (movingPiece is Pawn)
            {
                i_halfMoveClock = 0;
                PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition);
                if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null)
                { // en passant
                    isCapture = true;
                    captured  = GetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank);
                    SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null);
                }
                if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1))
                {
                    newPiece = MapPgnCharToPiece(move.Promotion.Value, move.Player).AsPromotion();
                    type    |= MoveType.Promotion;
                }
            }
            else if (movingPiece is King)
            {
                if (movingPiece.Owner == Player.White)
                {
                    CanWhiteCastleKingSide = CanWhiteCastleQueenSide = false;
                }
                else
                {
                    CanBlackCastleKingSide = CanBlackCastleQueenSide = false;
                }

                if (CastlingCanBeLegal &&
                    ((GetPieceAt(move.NewPosition) is Rook && GetPieceAt(move.NewPosition).Owner == move.Player) ||
                     ((move.NewPosition.File == File.C || move.NewPosition.File == File.G) &&
                      (move.Player == Player.White ? InitialWhiteKingFile : InitialBlackKingFile) == File.E &&
                      move.OriginalPosition.File == File.E)))
                {
                    castle    = ApplyCastle(move);
                    type     |= MoveType.Castling;
                    isCapture = false;
                }
            }
            else if (movingPiece is Rook)
            {
                if (move.Player == Player.White)
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1)
                    {
                        CanWhiteCastleQueenSide = false;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1)
                    {
                        CanWhiteCastleKingSide = false;
                    }
                }
                else
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8)
                    {
                        CanBlackCastleQueenSide = false;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8)
                    {
                        CanBlackCastleKingSide = false;
                    }
                }
            }
            if (isCapture)
            {
                type           |= MoveType.Capture;
                i_halfMoveClock = 0;
                if (move.NewPosition.File == File.A && move.NewPosition.Rank == 1)
                {
                    CanWhiteCastleQueenSide = false;
                }
                else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 1)
                {
                    CanWhiteCastleKingSide = false;
                }
                else if (move.NewPosition.File == File.A && move.NewPosition.Rank == 8)
                {
                    CanBlackCastleQueenSide = false;
                }
                else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 8)
                {
                    CanBlackCastleKingSide = false;
                }
            }
            if (!isCapture && !(movingPiece is Pawn))
            {
                i_halfMoveClock++;
                if (i_halfMoveClock >= 100)
                {
                    fiftyMoves = true;
                }
                else
                {
                    fiftyMoves = false;
                }
            }
            if (move.Player == Player.Black)
            {
                i_fullMoveNumber++;
            }
            if (castle == CastlingType.None)
            {
                SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece);
                SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null);
            }
            WhoseTurn = ChessUtilities.GetOpponentOf(move.Player);
            AddDetailedMove(new DetailedMove(move, movingPiece, isCapture, castle));
            return(type);
        }
示例#13
0
 protected bool IsValidMove(Move move, bool validateCheck)
 {
     ChessUtilities.ThrowIfNull(move, "move");
     return(IsValidMove(move, validateCheck, true));
 }
示例#14
0
 public bool IsValidMove(Move move)
 {
     ChessUtilities.ThrowIfNull(move, "move");
     return(IsValidMove(move, true, true));
 }
示例#15
0
 public Piece GetPieceAt(Position position)
 {
     ChessUtilities.ThrowIfNull(position, "position");
     return(GetPieceAt(position.File, position.Rank));
 }
示例#16
0
        public MoveType ApplyMove(Move move, bool alreadyValidated)
        {
            ChessUtilities.ThrowIfNull(move, nameof(move));

            if (!alreadyValidated && !IsValidMove(move))
            {
                return(MoveType.Invalid);
            }

            var type          = MoveType.Move;
            var movingPiece   = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank);
            var capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank);
            var newPiece      = movingPiece;
            var isCapture     = capturedPiece != null;
            var castle        = CastlingType.None;

            if (movingPiece is Pawn)
            {
                _halfMoveClock = 0;
                var pd = new SquareDistance(move.OriginalPosition, move.NewPosition);
                if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null)
                { // en passant
                    isCapture = true;
                    SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null);
                }
                if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1))
                {
                    newPiece = move.Promotion;
                    type    |= MoveType.Promotion;
                }
            }
            else if (movingPiece is King)
            {
                if (movingPiece.Owner == Player.White)
                {
                    _whiteKingMoved = true;
                }
                else
                {
                    _blackKingMoved = true;
                }

                if (new SquareDistance(move.OriginalPosition, move.NewPosition).DistanceX == 2)
                {
                    castle = ApplyCastle(move);
                    type  |= MoveType.Castling;
                }
            }
            else if (movingPiece is Rook)
            {
                if (move.Player == Player.White)
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1)
                    {
                        _whiteRookAMoved = true;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1)
                    {
                        _whiteRookHMoved = true;
                    }
                }
                else
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8)
                    {
                        _blackRookAMoved = true;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8)
                    {
                        _blackRookHMoved = true;
                    }
                }
            }

            if (isCapture)
            {
                type          |= MoveType.Capture;
                _halfMoveClock = 0;
            }

            if (!isCapture && !(movingPiece is Pawn))
            {
                _halfMoveClock++;
                canClaimDraw = _halfMoveClock == 100; // ahaa so THAT's the HalfMove clock .. number of Plys
            }

            if (move.Player == Player.Black)
            {
                _fullMoveNumber++;
            }

            SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece);
            SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null);
            WhoseTurn = ChessUtilities.GetOpponentOf(move.Player);
            _moves.Add(new DetailedMove(move, movingPiece, isCapture, castle));

            return(type);
        }
示例#17
0
 public virtual bool IsWinner(Player player)
 {
     return(IsCheckmated(ChessUtilities.GetOpponentOf(player)));
 }
示例#18
0
 public Piece GetPieceAt(Square position)
 {
     ChessUtilities.ThrowIfNull(position, nameof(position));
     return(GetPieceAt(position.File, position.Rank));
 }
示例#19
0
 public bool HasAnyValidMoves(Square from)
 {
     ChessUtilities.ThrowIfNull(from, nameof(from));
     return(GetValidMoves(from, true).Count > 0);
 }
示例#20
0
 bool IsValidMove(Move move, bool validateCheck)
 {
     ChessUtilities.ThrowIfNull(move, nameof(move));
     return(IsValidMove(move, validateCheck, true));
 }
示例#21
0
 public ReadOnlyCollection <Move> GetValidMoves(Square from)
 {
     ChessUtilities.ThrowIfNull(from, nameof(from));
     return(GetValidMoves(from, false));
 }
示例#22
0
 public ReadOnlyCollection <Move> GetValidMoves(Position from)
 {
     ChessUtilities.ThrowIfNull(from, "from");
     return(GetValidMoves(from, false));
 }
示例#23
0
        protected virtual string GetSanForMove(Move move, Piece movingPiece, bool isCapture, CastlingType castle, List <Position> ambiguities)
        {
            if (castle == CastlingType.KingSide)
            {
                return("O-O");
            }
            if (castle == CastlingType.QueenSide)
            {
                return("O-O-O");
            }

            bool needsUnambigFile = false;
            bool needsUnambigRank = false;

            if (ambiguities.Count > 0)
            {
                foreach (Position amb in ambiguities)
                {
                    if (amb.Rank == move.OriginalPosition.Rank)
                    {
                        needsUnambigFile = true;
                    }
                    if (amb.File == move.OriginalPosition.File)
                    {
                        needsUnambigRank = true;
                    }
                }
                if (!needsUnambigFile && !needsUnambigRank)
                {
                    needsUnambigFile = true;
                }
            }

            StringBuilder sanBuilder = new StringBuilder();

            if (!(movingPiece is Pawn))
            {
                sanBuilder.Append(char.ToUpperInvariant(movingPiece.GetFenCharacter()));
            }
            else if (isCapture)
            {
                sanBuilder.Append(move.OriginalPosition.File.ToString().ToLowerInvariant());
                needsUnambigFile = false;
                needsUnambigRank = false;
            }
            if (needsUnambigFile)
            {
                sanBuilder.Append(move.OriginalPosition.File.ToString().ToLowerInvariant());
            }
            if (needsUnambigRank)
            {
                sanBuilder.Append(move.OriginalPosition.Rank.ToString());
            }
            if (isCapture)
            {
                sanBuilder.Append("x");
            }
            sanBuilder.Append(move.NewPosition.ToString().ToLowerInvariant());
            if (move.Promotion.HasValue)
            {
                sanBuilder.Append("=");
                sanBuilder.Append(move.Promotion.Value);
            }
            if (IsWinner(ChessUtilities.GetOpponentOf(WhoseTurn)))
            {
                sanBuilder.Append("#");
            }
            else if (IsInCheck(WhoseTurn))
            {
                sanBuilder.Append("+");
            }
            return(sanBuilder.ToString());
        }
示例#24
0
        public virtual MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured)
        {
            ChessUtilities.ThrowIfNull(move, "move");
            captured = null;
            if (!alreadyValidated && !IsValidMove(move))
            {
                return(MoveType.Invalid);
            }
            MoveType type          = MoveType.Move;
            Piece    movingPiece   = GetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank);
            Piece    capturedPiece = GetPieceAt(move.NewPosition.File, move.NewPosition.Rank);

            captured = capturedPiece;
            Piece newPiece = movingPiece;

            enp = "-1";
            bool         isCapture = capturedPiece != null;
            CastlingType castle    = CastlingType.None;

            if (movingPiece is Pawn)
            {
                i_halfMoveClock = 0;
                PositionDistance pd = new PositionDistance(move.OriginalPosition, move.NewPosition);
                if (pd.DistanceX == 1 && pd.DistanceY == 1 && GetPieceAt(move.NewPosition) == null)
                { // en passant
                    isCapture = true;
                    captured  = GetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank);
                    enp       = move.NewPosition.File.ToString().ToLower() + move.OriginalPosition.Rank.ToString();
                    SetPieceAt(move.NewPosition.File, move.OriginalPosition.Rank, null);
                }
                if (move.NewPosition.Rank == (move.Player == Player.White ? 8 : 1))
                {
                    //get promotion type
                    char PromoteTo;

                    if (move.Promotion == null)
                    {
                        string promote;
                        Console.Write("enter promotion type:");
                        promote = Console.ReadLine();
                        switch (promote)
                        {
                        case "queen":
                            PromoteTo = 'Q';
                            break;

                        case "bishop":
                            PromoteTo = 'B';
                            break;

                        case "knight":
                            PromoteTo = 'N';
                            break;

                        case "rook":
                            PromoteTo = 'R';
                            break;

                        default:
                            PromoteTo = 'Q';
                            break;
                        }
                    }
                    else
                    {
                        PromoteTo = 'Q';
                    }
                    newPiece = MapPgnCharToPiece(PromoteTo, move.Player).AsPromotion();
                    type    |= MoveType.Promotion;
                }
            }
            else if (movingPiece is King)
            {
                if (movingPiece.Owner == Player.White)
                {
                    CanWhiteCastleKingSide = CanWhiteCastleQueenSide = false;
                }
                else
                {
                    CanBlackCastleKingSide = CanBlackCastleQueenSide = false;
                }

                if (CastlingCanBeLegal &&
                    ((GetPieceAt(move.NewPosition) is Rook && GetPieceAt(move.NewPosition).Owner == move.Player) ||
                     ((move.NewPosition.File == File.C || move.NewPosition.File == File.G) &&
                      (move.Player == Player.White ? InitialWhiteKingFile : InitialBlackKingFile) == File.E &&
                      move.OriginalPosition.File == File.E)))
                {
                    castle    = ApplyCastle(move);
                    type     |= MoveType.Castling;
                    isCapture = false;
                }
            }
            else if (movingPiece is Rook)
            {
                if (move.Player == Player.White)
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 1)
                    {
                        CanWhiteCastleQueenSide = false;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 1)
                    {
                        CanWhiteCastleKingSide = false;
                    }
                }
                else
                {
                    if (move.OriginalPosition.File == File.A && move.OriginalPosition.Rank == 8)
                    {
                        CanBlackCastleQueenSide = false;
                    }
                    else if (move.OriginalPosition.File == File.H && move.OriginalPosition.Rank == 8)
                    {
                        CanBlackCastleKingSide = false;
                    }
                }
            }
            if (isCapture)
            {
                type           |= MoveType.Capture;
                i_halfMoveClock = 0;
                if (move.NewPosition.File == File.A && move.NewPosition.Rank == 1)
                {
                    CanWhiteCastleQueenSide = false;
                }
                else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 1)
                {
                    CanWhiteCastleKingSide = false;
                }
                else if (move.NewPosition.File == File.A && move.NewPosition.Rank == 8)
                {
                    CanBlackCastleQueenSide = false;
                }
                else if (move.NewPosition.File == File.H && move.NewPosition.Rank == 8)
                {
                    CanBlackCastleKingSide = false;
                }
            }
            if (!isCapture && !(movingPiece is Pawn))
            {
                i_halfMoveClock++;
                if (i_halfMoveClock >= 100)
                {
                    fiftyMoves = true;
                }
                else
                {
                    fiftyMoves = false;
                }
            }
            if (move.Player == Player.Black)
            {
                i_fullMoveNumber++;
            }
            if (castle == CastlingType.None)
            {
                SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, newPiece);
                SetPieceAt(move.OriginalPosition.File, move.OriginalPosition.Rank, null);
            }
            WhoseTurn = ChessUtilities.GetOpponentOf(move.Player);
            AddDetailedMove(new DetailedMove(move, movingPiece, isCapture, castle));
            return(type);
        }