Пример #1
0
        internal void UndoMove()
        {
            if (!CanUndoMove())
            {
                throw new InvalidOperationException("Undo cannot be performed: no moves.");
            }

            var data = _undoMoveDatas.Pop();

            PiecePosition.SetPiece(data.Move.From, data.MovedPiece);
            PiecePosition.SetPiece(data.Move.To, Piece.None);

            if (data.CapturedPiece != Piece.None)
            {
                PiecePosition.SetPiece(data.CapturedPieceSquare, data.CapturedPiece);
            }
            else if (data.CastlingRookMove != null)
            {
                var castlingRook = PiecePosition.SetPiece(data.CastlingRookMove.To, Piece.None);
                if (castlingRook.GetPieceType() != PieceType.Rook ||
                    castlingRook.GetSide() != data.MovedPiece.GetSide())
                {
                    throw ChessPlatformException.CreateInconsistentStateError();
                }

                PiecePosition.SetPiece(data.CastlingRookMove.From, castlingRook);
            }

            PiecePosition.EnsureConsistency();
        }
Пример #2
0
        internal MakeMoveData MakeMove(
            [NotNull] GameMove move,
            GameSide movingSide,
            [CanBeNull] EnPassantCaptureInfo enPassantCaptureInfo,
            ref CastlingOptions castlingOptions)
        {
            if (move is null)
            {
                throw new ArgumentNullException(nameof(move));
            }

            var piece = PiecePosition[move.From];

            if (piece == Piece.None || piece.GetSide() != movingSide)
            {
                throw new ArgumentException($@"Invalid move '{move}' in the position.", nameof(move));
            }

            GameMove castlingRookMove             = null;
            Square?  enPassantCapturedPieceSquare = null;

            var movingSideAllCastlingOptions = ChessHelper.GameSideToCastlingOptionsMap[movingSide];

            // Performing checks before actual move!
            var castlingInfo       = CheckCastlingMove(move);
            var isEnPassantCapture = IsEnPassantCapture(move.From, move.To, enPassantCaptureInfo);
            var isPawnPromotion    = IsPawnPromotion(move.From, move.To);

            var moveData      = MovePieceInternal(move);
            var capturedPiece = moveData.CapturedPiece;

            if (isEnPassantCapture)
            {
                if (enPassantCaptureInfo is null)
                {
                    throw ChessPlatformException.CreateInconsistentStateError();
                }

                enPassantCapturedPieceSquare = enPassantCaptureInfo.TargetPieceSquare;
                capturedPiece = PiecePosition.SetPiece(enPassantCaptureInfo.TargetPieceSquare, Piece.None);
                if (capturedPiece.GetPieceType() != PieceType.Pawn)
                {
                    throw ChessPlatformException.CreateInconsistentStateError();
                }
            }
            else if (isPawnPromotion)
            {
                if (move.PromotionResult == PieceType.None)
                {
                    throw new ChessPlatformException($@"Promoted piece type is not specified ({move}).");
                }

                var previousPiece = PiecePosition.SetPiece(move.To, move.PromotionResult.ToPiece(movingSide));
                if (previousPiece.GetPieceType() != PieceType.Pawn)
                {
                    throw ChessPlatformException.CreateInconsistentStateError();
                }
            }
            else if (castlingInfo != null)
            {
                if (!castlingOptions.IsAllSet(castlingInfo.Option))
                {
                    throw new ChessPlatformException(
                              $@"The castling {{{move}}} ({castlingInfo.CastlingType.GetName()}) is not allowed.");
                }

                castlingRookMove = castlingInfo.RookMove;
                var rookMoveData = MovePieceInternal(castlingRookMove);
                if (rookMoveData.CapturedPiece != Piece.None)
                {
                    throw ChessPlatformException.CreateInconsistentStateError();
                }

                castlingOptions &= ~movingSideAllCastlingOptions;
            }

            var movingSideCurrentCastlingOptions = castlingOptions & movingSideAllCastlingOptions;

            if (movingSideCurrentCastlingOptions != CastlingOptions.None)
            {
                switch (piece.GetPieceType())
                {
                case PieceType.King:
                    castlingOptions &= ~movingSideAllCastlingOptions;
                    break;

                case PieceType.Rook:
                {
                    var castlingInfoByRook =
                        ChessConstants.AllCastlingInfos.SingleOrDefault(obj => obj.RookMove.From == move.From);

                    if (castlingInfoByRook != null)
                    {
                        castlingOptions &= ~castlingInfoByRook.Option;
                    }
                }

                break;
                }
            }

            var oppositeSide = movingSide.Invert();
            var oppositeSideAllCastlingOptions     = ChessHelper.GameSideToCastlingOptionsMap[oppositeSide];
            var oppositeSideCurrentCastlingOptions = castlingOptions & oppositeSideAllCastlingOptions;

            if (oppositeSideCurrentCastlingOptions != CastlingOptions.None &&
                capturedPiece.GetPieceType() == PieceType.Rook)
            {
                var oppositeCastlingInfo =
                    ChessConstants.AllCastlingInfos.SingleOrDefault(obj => obj.RookMove.From == move.To);

                if (oppositeCastlingInfo != null)
                {
                    castlingOptions &= ~oppositeCastlingInfo.Option;
                }
            }

            var undoMoveData = new MakeMoveData(
                move,
                moveData.MovedPiece,
                capturedPiece,
                castlingRookMove,
                enPassantCapturedPieceSquare);

            _undoMoveDatas.Push(undoMoveData);

            PiecePosition.EnsureConsistency();

            return(undoMoveData);
        }