Beispiel #1
0
        private IEnumerable <ChessDraw> getForewardDraws(IChessBoard board, ChessPosition drawingPiecePosition)
        {
            var draws = new List <ChessDraw>();
            var piece = board.GetPieceAt(drawingPiecePosition);

            var coordsPosOneForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column);
            var coordsPosTwoForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 2 : -2), drawingPiecePosition.Column);

            if (ChessPosition.AreCoordsValid(coordsPosOneForeward))
            {
                var  posOneForeward = new ChessPosition(coordsPosOneForeward);
                bool oneForeward    = !board.IsCapturedAt(posOneForeward);

                if (oneForeward)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posOneForeward));

                    if (!piece.WasMoved && ChessPosition.AreCoordsValid(coordsPosTwoForeward))
                    {
                        var posTwoForeward = new ChessPosition(coordsPosTwoForeward);

                        if (!board.IsCapturedAt(posTwoForeward))
                        {
                            draws.Add(new ChessDraw(board, drawingPiecePosition, posTwoForeward));
                        }
                    }
                }
            }

            return(draws);
        }
Beispiel #2
0
        private IEnumerable <ChessDraw> getRochadeDraws(IChessBoard board, ChessColor drawingSide)
        {
            // TODO: do optimizations!!!

            // get enemy capturable positions
            var enemyKing = (drawingSide == ChessColor.White) ? board.BlackKing : board.WhiteKing;
            var enemyCapturablePositions =
                board.GetPiecesOfColor(drawingSide.Opponent()).Where(x => x.Piece.Type != ChessPieceType.King)
                .SelectMany(x => ChessDrawGenerator.Instance.GetDraws(board, x.Position, null, false)).Select(x => x.NewPosition)
                .Concat(getStandardDrawPositions(enemyKing.Position));

            // get the allied king and towers
            int row                = (drawingSide == ChessColor.White) ? 0 : 7;
            var alliedKing         = (drawingSide == ChessColor.White) ? board.WhiteKing : board.BlackKing;
            var farAlliedTowerPos  = new ChessPosition(row, 0);
            var farAlliedTower     = board.GetPieceAt(farAlliedTowerPos);
            var nearAlliedTowerPos = new ChessPosition(row, 7);
            var nearAlliedTower    = board.GetPieceAt(nearAlliedTowerPos);

            // define the fields that must not be capturable by the opponent
            var bigRochadeKingPassagePositions   = (drawingSide == ChessColor.White) ? whiteKingBigRochadePassagePositions   : blackKingBigRochadePassagePositions;
            var smallRochadeKingPassagePositions = (drawingSide == ChessColor.White) ? whiteKingSmallRochadePassagePositions : blackKingSmallRochadePassagePositions;

            bool canBigRochade =
                // check for preconditions of big rochade
                (board.IsCapturedAt(farAlliedTowerPos) && !alliedKing.Piece.WasMoved && !farAlliedTower.WasMoved &&
                 bigRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King)) &&
                 !board.IsCapturedAt(new ChessPosition(row, 1)))
                // make sure that no rochade field can be captured by the opponent
                && !enemyCapturablePositions.Any(pos => bigRochadeKingPassagePositions.Contains(pos));

            bool canSmallRochade =
                // check for preconditions of small rochade
                (board.IsCapturedAt(nearAlliedTowerPos) && !alliedKing.Piece.WasMoved && !nearAlliedTower.WasMoved &&
                 smallRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King)))
                // make sure that no rochade field can be captured by the opponent and the rochade field on the B-line is not captured
                && !enemyCapturablePositions.Any(pos => smallRochadeKingPassagePositions.Contains(pos));

            // write result draws
            int index      = 0;
            int drawsCount = (canSmallRochade ? 1 : 0) + (canBigRochade ? 1 : 0);

            ChessDraw[] draws = new ChessDraw[drawsCount];
            if (canSmallRochade)
            {
                draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 6));
            }
            if (canBigRochade)
            {
                draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 2));
            }

            return(draws);
        }
Beispiel #3
0
        /// <summary>
        /// Compute whether the draw is valid or not. If it is invalid, an exception with an according message is thrown.
        /// </summary>
        /// <param name="board">the chess board where the draw should be applied to</param>
        /// <param name="predecedingEnemyDraw">The last draw that the oponent made</param>
        /// <returns>boolean whether the draw is valid</returns>
        public bool IsValid(IChessBoard board, ChessDraw?predecedingEnemyDraw = null)
        {
            // TODO: refactor this function!!!

            // get the piece to be drawn
            var piece = board.GetPieceAt(OldPosition);

            // make sure that there is a chess piece of the correct color that can be drawn
            if (!board.IsCapturedAt(OldPosition))
            {
                throw new ArgumentException($"There is no chess piece on { OldPosition.FieldName }.");
            }
            if (piece.Color != DrawingSide)
            {
                throw new ArgumentException($"The chess piece on { OldPosition.FieldName } is owned by the opponent.");
            }

            // compute the possible chess draws for the given chess piece
            var possibleDraws = ChessDrawGenerator.Instance.GetDraws(board, OldPosition, predecedingEnemyDraw, true);

            // check if there is a possible draw with the same new position and type (this implies that the given draw is valid)
            var  type     = Type;
            var  position = NewPosition;
            bool ret      = (possibleDraws?.Count() > 0) && possibleDraws.Any(x => x.Type == type && x.NewPosition == position);

            return(ret);
        }
Beispiel #4
0
        private static ChessDrawType getDrawType(IChessBoard board, ChessPosition oldPos,
                                                 ChessPosition newPos, ChessPieceType?peasantPromotionType)
        {
            var piece = board.GetPieceAt(oldPos);
            var type  = ChessDrawType.Standard;

            // check for a peasant promotion
            if (peasantPromotionType != null && piece.Type == ChessPieceType.Peasant &&
                ((newPos.Row == 7 && piece.Color == ChessColor.White) ||
                 (newPos.Row == 0 && piece.Color == ChessColor.Black)))
            {
                type = ChessDrawType.PeasantPromotion;
            }
            // check for a rochade
            else if (piece.Type == ChessPieceType.King && Math.Abs(oldPos.Column - newPos.Column) == 2)
            {
                type = ChessDrawType.Rochade;
            }
            // check for an en-passant
            else if (piece.Type == ChessPieceType.Peasant && !board.IsCapturedAt(newPos) &&
                     Math.Abs(oldPos.Column - newPos.Column) == 1)
            {
                type = ChessDrawType.EnPassant;
            }

            return(type);
        }
Beispiel #5
0
        public void UpdatePieces(IChessBoard board)
        {
            for (byte pos = 0; pos < 64; pos++)
            {
                var field = Fields[pos];
                field.UpdatePiece(board.IsCapturedAt(pos) ? (ChessPiece?)board.GetPieceAt(pos) : null);
            }

            _board = (IChessBoard)((ICloneable)board).Clone();
        }
Beispiel #6
0
        public ChessDraw(IChessBoard board, ChessPosition oldPos, ChessPosition newPos, ChessPieceType?peasantPromotionType = null)
        {
            // get the drawing piece
            var piece = board.GetPieceAt(oldPos);

            // determine all property values
            var type             = getDrawType(board, oldPos, newPos, peasantPromotionType);
            var drawingSide      = piece.Color;
            var drawingPieceType = piece.Type;

            var takenPieceType =
                (type == ChessDrawType.EnPassant)
                    ? (ChessPieceType?)ChessPieceType.Peasant
                    : (board.IsCapturedAt(newPos) ? (ChessPieceType?)board.GetPieceAt(newPos).Type : null);

            // transform property values to a hash code
            _hashCode = toHashCode(type, drawingSide, drawingPieceType, takenPieceType, peasantPromotionType, oldPos, newPos, !piece.WasMoved);
        }
Beispiel #7
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is a knight
            if (piece.Type != ChessPieceType.Knight)
            {
                throw new InvalidOperationException("The chess piece is not a knight.");
            }

            // get positions next to the current position of the king (all permutations of { -1, 0, +1 }^2 except (0, 0))
            var coords = new Tuple <int, int>[]
            {
                new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column - 1),
                new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column + 1),
                new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column - 2),
                new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column + 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column - 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column + 2),
                new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column - 1),
                new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column + 1),
            };

            // only retrieve positions that are actually onto the chess board (and not off scale)
            var positions = coords.Where(x => ChessPosition.AreCoordsValid(x)).Select(x => new ChessPosition(x));

            // do not draw into positions captured by allied chess pieces
            positions = positions.Where(x => !board.IsCapturedAt(x) || board.GetPieceAt(x).Color != piece.Color);

            // transform positions to chess draws
            var draws = positions.Select(newPos => new ChessDraw(board, drawingPiecePosition, newPos));

            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                // remove draws that would draw into a check situation
                draws = draws.Where(x => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, x));
            }

            return(draws);
        }
        /// <summary>
        /// Make a human user put the next draw via CLI.
        /// </summary>
        /// <param name="board">The chess board representing the current game situation.</param>
        /// <param name="previousDraw">The preceding draw made by the enemy.</param>
        /// <returns>the next chess draw</returns>
        public ChessDraw GetNextDraw(IChessBoard board, ChessDraw?previousDraw)
        {
            ChessPosition  oldPosition;
            ChessPosition  newPosition;
            ChessPieceType?promotionPieceType = null;

            do
            {
                // get draw from user input
                Console.Write("Please make your next draw (e.g. 'e2-e4): ");
                string userInput = Console.ReadLine().Trim().ToLower();

                // parse user input
                if (userInput.Length == 5)
                {
                    // parse coord strings
                    string oldPosString = userInput.Substring(0, 2);
                    string newPosString = userInput.Substring(3, 2);

                    // validate coord strings
                    if (ChessPosition.AreCoordsValid(oldPosString) && ChessPosition.AreCoordsValid(newPosString))
                    {
                        // init chess positions
                        oldPosition = new ChessPosition(oldPosString);
                        newPosition = new ChessPosition(newPosString);

                        // make sure that the player possesses the the chess piece he is moving (simple validation)
                        if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Color == Side)
                        {
                            break;
                        }
                        else
                        {
                            Console.Write("There is no chess piece to be moved onto the field you put! ");
                        }
                    }
                }
                else
                {
                    Console.Write("Your input needs to be of the syntax in the example! ");
                }
            }while (true);

            // handle peasant promotion
            if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Type == ChessPieceType.Peasant &&
                (Side == ChessColor.White && newPosition.Row == 7) || (Side == ChessColor.Black && newPosition.Row == 0))
            {
                do
                {
                    // get draw from user input
                    Console.Write("You have put a promotion draw. Please choose the type you want to promote to (options: Bishop=B, Knight=N, Rook=R, Queen=Q): ");
                    string userInput = Console.ReadLine().Trim().ToLower().ToLower();

                    if (userInput.Length == 1)
                    {
                        switch (userInput[0])
                        {
                        case 'b': promotionPieceType = ChessPieceType.Bishop; break;

                        case 'n': promotionPieceType = ChessPieceType.Knight; break;

                        case 'r': promotionPieceType = ChessPieceType.Rook; break;

                        case 'q': promotionPieceType = ChessPieceType.Queen; break;
                        }

                        if (promotionPieceType == null)
                        {
                            Console.Write("Your input needs to be a letter like in the example! ");
                        }
                    }
                }while (promotionPieceType == null);
            }

            return(new ChessDraw(board, oldPosition, newPosition, promotionPieceType));
        }
Beispiel #9
0
        private IEnumerable <ChessDraw> getCatchDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null)
        {
            var draws = new List <ChessDraw>();
            var piece = board.GetPieceAt(drawingPiecePosition);

            // get the possible chess field positions (info: right / left from the point of view of the white side player)
            var coordsPosCatchLeft  = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column + 1);
            var coordsPosCatchRight = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column - 1);

            // check for en-passant precondition
            bool wasLastDrawPeasantDoubleForeward =
                precedingEnemyDraw != null && precedingEnemyDraw.Value.DrawingPieceType == ChessPieceType.Peasant &&
                Math.Abs(precedingEnemyDraw.Value.OldPosition.Row - precedingEnemyDraw.Value.NewPosition.Row) == 2;

            // check if left catch / en-passant is possible
            if (ChessPosition.AreCoordsValid(coordsPosCatchLeft))
            {
                var posCatchLeft = new ChessPosition(coordsPosCatchLeft);

                bool catchLeft = board.IsCapturedAt(posCatchLeft) && board.GetPieceAt(posCatchLeft).Color != piece.Color;
                if (catchLeft)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft));
                }

                if (wasLastDrawPeasantDoubleForeward)
                {
                    // get the positions of an enemy chess piece taken by a possible en-passant
                    var posEnPassantEnemyLeft = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column + 1);

                    bool isLeftFieldCapturedByEnemy =
                        precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyLeft && board.IsCapturedAt(posEnPassantEnemyLeft) &&
                        board.GetPieceAt(posEnPassantEnemyLeft).Color != piece.Color;

                    bool enPassantLeft = isLeftFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyLeft.Column - drawingPiecePosition.Column) == 1;
                    if (enPassantLeft)
                    {
                        draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft));
                    }
                }
            }

            // check if right catch / en-passant is possible
            if (ChessPosition.AreCoordsValid(coordsPosCatchRight))
            {
                var posCatchRight = new ChessPosition(coordsPosCatchRight);

                bool catchRight = board.IsCapturedAt(posCatchRight) && board.GetPieceAt(posCatchRight).Color != piece.Color;
                if (catchRight)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight));
                }

                if (wasLastDrawPeasantDoubleForeward)
                {
                    // get the positions of an enemy chess piece taken by a possible en-passant
                    var posEnPassantEnemyRight = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column - 1);

                    bool isRightFieldCapturedByEnemy =
                        precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyRight &&
                        board.IsCapturedAt(posEnPassantEnemyRight) && board.GetPieceAt(posEnPassantEnemyRight).Color != piece.Color;

                    bool enPassantRight = isRightFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyRight.Column - drawingPiecePosition.Column) == 1;
                    if (enPassantRight)
                    {
                        draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight));
                    }
                }
            }

            return(draws);
        }
Beispiel #10
0
        /// <summary>
        /// Compute the field positions that can be captured by the given chess piece.
        /// </summary>
        /// <param name="board">The chess board representing the game situation</param>
        /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param>
        /// <param name="precedingEnemyDraw">The last draw made by the opponent</param>
        /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param>
        /// <returns>a list of all possible chess draws</returns>
        public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false)
        {
            var piece = board.GetPieceAt(drawingPiecePosition);

            // make sure the chess piece is bishop-like
            if (piece.Type != ChessPieceType.Bishop && piece.Type != ChessPieceType.Queen)
            {
                throw new InvalidOperationException("The chess piece is not a bishop.");
            }

            var draws = new List <ChessDraw>();

            // get upper left-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column - i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get lower left-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column - i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get upper right-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column + i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // get lower right-side draws
            for (int i = 1; i < 8; i++)
            {
                // get position and make sure it is valid (otherwise exit loop)
                var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column + i);
                if (!ChessPosition.AreCoordsValid(coords))
                {
                    break;
                }

                var newPos = new ChessPosition(coords);

                if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color)
                {
                    draws.Add(new ChessDraw(board, drawingPiecePosition, newPos));
                }
                if (board.IsCapturedAt(newPos))
                {
                    break;
                }
            }

            // analyze draw into a check situation
            if (analyzeDrawIntoCheck && draws?.Count() > 0)
            {
                draws = draws.Where(draw => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw)).ToList();
            }

            return(draws);
        }