Exemplo n.º 1
0
        private ValidateMoveResult CanMove(ChessBoard board, string source, string dest, PlayerTypeEnum player, string lastMoveNotation, bool playerInCheck)
        {
            var result = new ValidateMoveResult();

            var sourceTuple = NotationHelper.Translate(source);

            if (!BoardLogic.IsOnBoard(sourceTuple))
                return result.SetMessage(source + " is not on board");

            var destTuple = NotationHelper.Translate(dest);

            if (!BoardLogic.IsOnBoard(destTuple))
                return result.SetMessage(dest + " is not on board");

            if (source.Equals(dest, StringComparison.OrdinalIgnoreCase))
                return result.SetMessage("source and dest are the same");

            var sourcePiece = board.Get(sourceTuple);

            if (sourcePiece == null)
                return result.SetMessage("source piece is null");

            if (sourcePiece.Player != player)
                return result.SetMessage("piece does not belong to player.");

            var destPiece = board.Get(destTuple);

            if (destPiece != null && sourcePiece.Player == destPiece.Player)
                return result.SetMessage("cannot move on top of own piece");

            var relativeMoves = m_relativeMoveProviderFactory
                .GetProviderByPieceType(sourcePiece.Type)
                .GetRelativePaths(sourcePiece);
            var absoluteMoves = BoardLogic.ConvertToAbsolutePaths(sourceTuple, relativeMoves);
            bool destInPath = BoardLogic.IsInAtleastOnePath(destTuple, absoluteMoves);

            if (!destInPath)
                return result.SetMessage("destination not in available path");

            string takenPiece = null;
            string additionalMove = null;

            switch (sourcePiece.Type)
            {
                case PieceTypeEnum.Pawn:
                    {
                        bool isRankOnlyMove = BoardLogic.IsRankOnlyMove(sourceTuple, destTuple);

                        if (isRankOnlyMove)
                        {
                            var pathContaingDestination = BoardLogic.GetPathContaining(destTuple, absoluteMoves);

                            if (!BoardLogic.IsPathClear(board, pathContaingDestination))
                                return result.SetMessage("path blocked");

                            var absDelta = BoardLogic.GetAbsoluteDelta(sourceTuple, destTuple);
                            if (absDelta.Item1 == 2 && sourcePiece.HasMoved)
                                return result.SetMessage("pawn has already moved, cannot jump 2 squares");
                        }
                        else
                        {
                            // en-passant
                            // > is piece in source *rank, destination *file an enemy pawn?
                            // > if yes, was its last move two squares?e
                            var pieceBehindTuple = new Tuple<int, int>(
                                sourceTuple.Item1,
                                destTuple.Item2);

                            var pieceBehind = board.Get(pieceBehindTuple);
                            bool targetWasLastMove = false;
                            bool twoSquareLastMove = false;

                            Tuple<string, string> lastMove = null;
                            if (lastMoveNotation != null)
                            {
                                lastMove = NotationHelper.Breakdown(lastMoveNotation);
                                var lastMoveSourceTuple = NotationHelper.Translate(lastMove.Item1);
                                var lastMoveDestTuple = NotationHelper.Translate(lastMove.Item2);
                                var lastMoveAbsDelta = BoardLogic.GetAbsoluteDelta(lastMoveSourceTuple, lastMoveDestTuple);

                                twoSquareLastMove = lastMoveAbsDelta.Item1 == 2;

                                targetWasLastMove =
                                    pieceBehindTuple.Item1 == lastMoveDestTuple.Item1 &&
                                    pieceBehindTuple.Item2 == lastMoveDestTuple.Item2;
                            }

                            bool enPassant =
                                pieceBehind != null &&
                                pieceBehind.Player != player &&
                                pieceBehind.Type == PieceTypeEnum.Pawn &&
                                twoSquareLastMove &&
                                targetWasLastMove
                                ;

                            if (enPassant)
                            {
                                takenPiece = lastMove.Item2;
                                break;
                            }

                            if (destPiece == null)
                                return result.SetMessage("enemy piece not present at destination");
                        }

                        break;
                    }
                case PieceTypeEnum.King:
                    {
                        // castle

                        if (BoardLogic.IsFileOnlyMove(sourceTuple, destTuple) &&
                            BoardLogic.GetAbsoluteDelta(sourceTuple, destTuple).Item2 == 2)
                        {
                            if (sourcePiece.HasMoved)
                                return result.SetMessage("king has already moved.");

                            ChessPiece rook = null;
                            Tuple<int, int> rookTuple = null;
                            Tuple<int, int> toRookDelta = null;
                            var rookNotations = board.GetPiecesOfType(player, PieceTypeEnum.Rook);
                            if (rookNotations != null && rookNotations.Count > 0)
                            {
                                var moveDelta = BoardLogic.GetDelta(sourceTuple, destTuple);

                                foreach (var rn in rookNotations)
                                {
                                    rookTuple = NotationHelper.Translate(rn);
                                    toRookDelta = BoardLogic.GetDelta(sourceTuple, rookTuple);
                                    if (BoardLogic.IsFileOnlyMove(sourceTuple, rookTuple) &&
                                        BoardLogic.AreDeltasInSameDirection(moveDelta.Item2, toRookDelta.Item2))
                                    {
                                        rook = board.Get(rn);
                                        break;
                                    }
                                }
                            }

                            if (rook == null)
                                return result.SetMessage("no rook present on rank " + sourceTuple.Item1);

                            if (rook.HasMoved)
                                return result.SetMessage("rook has moved.");

                            Tuple<int, int>[] kingToRookPath = BoardLogic.GetRankPath(sourceTuple, rookTuple);
                            Tuple<int, int>[] trimmedPath = BoardLogic.TrimToBeforeDestination(rookTuple,
                                kingToRookPath);

                            bool isPathClear = BoardLogic.IsPathClear(board, trimmedPath);

                            if (!isPathClear)
                                return result.SetMessage("path blocked");

                            if (playerInCheck)
                                return result.SetMessage("cannot castle out of check");

                            bool moveToLeft = toRookDelta.Item2 < 0;
                            additionalMove = NotationHelper.Translate(rookTuple) +
                                                NotationHelper.Translate(new Tuple<int, int>(rookTuple.Item1,
                                                    destTuple.Item2 + (moveToLeft ? 1 : -1)));
                        }

                        break;
                    }
                case PieceTypeEnum.Knight:
                    {
                        break;
                    }
                case PieceTypeEnum.Bishop:
                case PieceTypeEnum.Rook:
                case PieceTypeEnum.Queen:
                    {
                        // cases handled in general

                        var pathContaingDestination = BoardLogic.GetPathContaining(destTuple, absoluteMoves);
                        var trimmedPath = BoardLogic.TrimToBeforeDestination(destTuple, pathContaingDestination);

                        if (!BoardLogic.IsPathClear(board, trimmedPath))
                            return result.SetMessage("path blocked");

                        break;
                    }
            }

            if (destPiece != null)
                takenPiece = dest;

            result.Success = true;
            result.TakenPiece = takenPiece;
            result.Moves = new[] { source + dest, additionalMove }.Where(x => x != null).ToArray();
            return result;
        }