Exemplo n.º 1
0
        public void PawnSwap()
        {
            ChessBoard b = new ChessBoard();
            b.Set("e1", new ChessPiece() { Player = PlayerTypeEnum.White, Type = PieceTypeEnum.King });
            b.Set("f7", new ChessPiece() { Player = PlayerTypeEnum.White, Type = PieceTypeEnum.Pawn });

            b.Set("e8", new ChessPiece() { Player = PlayerTypeEnum.Black, Type = PieceTypeEnum.King });

            ChessGame g = new ChessGame(b, PlayerTypeEnum.White, null);
            var moveResult = g.PlayerMove(PlayerTypeEnum.White, "f7f8");
            ChessPiece queen = b.Get("f8");

            Assert.IsTrue(moveResult.Success);
            Assert.IsTrue(queen.Type == PieceTypeEnum.Queen);
        }
Exemplo n.º 2
0
        private bool CanMoveIntoAttackersPath(PlayerTypeEnum player, string lastMoveNotation, ChessBoard board, List<string> attackers, Tuple<int, int> opponentKingTuple)
        {
            if (attackers.Count > 1)
                return false;

            bool canBlockPathOfAttackers = false;

            string attackerNotation = attackers.First();
            Tuple<int, int> attackerTuple = NotationHelper.Translate(attackerNotation);
            ChessPiece attackerPiece = board.Get(attackerTuple);

            if (attackerPiece.Type == PieceTypeEnum.Knight)
                return false;

            // get star pattern of each attacker
            List<Tuple<int, int>[]> relativePaths = new QueenRelativePathProvider().GetRelativePaths(
                new ChessPiece() { Player = player });

            var absolutePaths = BoardLogic.ConvertToAbsolutePaths(attackerTuple, relativePaths);

            // get path that leads to king
            var pathOfAttacker = BoardLogic.GetPathContaining(opponentKingTuple, absolutePaths);
            var trimmedPathOfAttacker = BoardLogic.TrimToBeforeDestination(opponentKingTuple, pathOfAttacker);

            // can any opponents move into path and block?
            var opponentPlayerSquares = board.GetPiecesForPlayer(GetOppositePlayer(player));
            foreach (var opponentSquare in opponentPlayerSquares)
            {
                bool canMoveIntoAttackersPath =
                    trimmedPathOfAttacker.Any(location =>
                    {
                        string dest = NotationHelper.Translate(location);
                        return CanMove(board, opponentSquare + dest, GetOppositePlayer(player), lastMoveNotation).Success;
                    });

                if (canMoveIntoAttackersPath)
                {
                    canBlockPathOfAttackers = true;
                    break;
                }
            }

            return canBlockPathOfAttackers;
        }
Exemplo n.º 3
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;
        }
Exemplo n.º 4
0
        public ValidateMoveResult CanMove(ChessBoard board, string move, PlayerTypeEnum player,
            string lastMoveNotation)
        {
            Tuple<string, string> breakdown = NotationHelper.Breakdown(move);
            string source = breakdown.Item1;
            string destination = breakdown.Item2;

            bool playerInCheck = IsInCheck(player, board, lastMoveNotation).Item1;
            ValidateMoveResult canMoveResult = CanMove(board, source, destination, player, lastMoveNotation, playerInCheck);

            if (canMoveResult.Success)
            {
                // pawn to queen swap
                ChessPiece sourceBeforeSimulate = board.Get(source);
                bool pawnSwap =
                    sourceBeforeSimulate != null &&
                    sourceBeforeSimulate.Type == PieceTypeEnum.Pawn &&
                    (sourceBeforeSimulate.Direction == -1 ? (int.Parse(destination[1].ToString()) == 8) : (int.Parse(destination[1].ToString()) == 1));

                string swap = pawnSwap ? destination : null;
                canMoveResult.Swap = swap;

                ChessBoard boardAfterMove = board.SimulateMoves(move, canMoveResult.TakenPiece, swap);

                // did player move into check?
                var movedIntoCheckResult = IsInCheck(player, boardAfterMove, lastMoveNotation);
                if (movedIntoCheckResult.Item1)
                {
                    canMoveResult.Success = false;
                    return canMoveResult.SetMessage("cannot move into check.");
                }

                // did player put opponent in check?
                var isOpponentInCheckResult = IsInCheck(GetOppositePlayer(player), boardAfterMove, lastMoveNotation);
                bool isOpponentInCheck = isOpponentInCheckResult.Item1;
                canMoveResult.MoveType = isOpponentInCheck ? MoveTypeEnum.Check : MoveTypeEnum.Normal;

                // if player checked opponent, can opponent get out of check? if not, check mate
                if (isOpponentInCheck)
                {
                    string opponentKingNotation = boardAfterMove.GetKing(GetOppositePlayer(player));
                    Tuple<int, int> opponentKingTuple = NotationHelper.Translate(opponentKingNotation);

                    // can checked king move out of check?
                    bool canMoveOutOfCheck = CanMoveOutOfCheck(player, lastMoveNotation, boardAfterMove, opponentKingNotation, opponentKingTuple);

                    // can opponent kill piece that put king in check? is still in check afterwards?
                    bool canTakedownAttacker = false;
                    if (!canMoveOutOfCheck)
                        canTakedownAttacker = CanTakedownAttackers(player, lastMoveNotation, boardAfterMove, isOpponentInCheckResult.Item2);

                    // can block path of piece that put king in check? (brute force method)
                    bool canBlockPathOfAttackers = false;
                    if (!canMoveOutOfCheck && !canTakedownAttacker)
                        canBlockPathOfAttackers = CanMoveIntoAttackersPath(player, lastMoveNotation, boardAfterMove, isOpponentInCheckResult.Item2, opponentKingTuple);

                    if (!canMoveOutOfCheck && !canTakedownAttacker && !canBlockPathOfAttackers)
                        canMoveResult.MoveType = MoveTypeEnum.Checkmate;
                }
            }

            return canMoveResult;
        }
Exemplo n.º 5
0
        private bool CanMoveOutOfCheck(PlayerTypeEnum player, string lastMoveNotation, ChessBoard board, string opponentKingNotation, Tuple<int, int> opponentKingTuple)
        {
            bool canMoveOutOfCheck = false;
            ChessPiece opponentKingPiece = board.Get(opponentKingTuple);
            var relativeMoves = m_relativeMoveProviderFactory
                .GetProviderByPieceType(opponentKingPiece.Type)
                .GetRelativePaths(opponentKingPiece);

            var absolutePaths = BoardLogic.ConvertToAbsolutePaths(opponentKingTuple, relativeMoves);

            var flattenedAbsoluteMoves = absolutePaths.SelectMany(x => x);
            foreach (var square in flattenedAbsoluteMoves)
            {
                // simulate move of king to available move
                string destinationNotation = NotationHelper.Translate(square);
                var getKingOutOfCheckMoveResult = CanMove(board, opponentKingNotation + destinationNotation,
                    GetOppositePlayer(player), lastMoveNotation);

                if (getKingOutOfCheckMoveResult.Success)
                {
                    canMoveOutOfCheck = true;
                    break;
                }
            }

            return canMoveOutOfCheck;
        }
Exemplo n.º 6
0
        public static bool IsPathClear(ChessBoard board, Tuple<int, int>[] path)
        {
            foreach (var move in path)
            {
                if (board.Get(move) != null)
                    return false;
            }

            return true;
        }