Example #1
0
        /// <summary>
        /// Converts BoardSide enum castling rights into a FEN compliant string
        /// </summary>
        /// <param name="castlingRights">Rights to convert</param>
        /// <param name="color">Color (for casing)</param>
        /// <returns>FEN compliant string for the BoardSide, e.g. "KQ"</returns>
        private static string TokenizeCastlingRights(BoardSide castlingRights, PieceColor color)
        {
            string result = String.Empty;

            if (castlingRights.HasFlag(BoardSide.King) & castlingRights.HasFlag(BoardSide.Queen))
            {
                result = String.Concat(result, "kq");
            }
            else if (castlingRights.HasFlag(BoardSide.King))
            {
                result = String.Concat(result, "k");
            }
            else if (castlingRights.HasFlag(BoardSide.Queen))
            {
                result = String.Concat(result, "q");
            }
            else
            {
                result = "-";
            }

            if (color == PieceColor.White)
            {
                result = result.ToUpper();
            }
            return(result);
        }
Example #2
0
        /// <summary>
        /// Checks if a given player is allowed to castle
        /// </summary>
        /// <param name="playerColor">Player to check</param>
        /// <param name="side">Side of the board to validate.</param>
        /// <returns>True if the player can castle on the given side</returns>
        public bool CanPlayerCastle(PieceColor playerColor, BoardSide side)
        {
            BoardSide playerSide = (playerColor == PieceColor.White) ? whiteCastlingRights : blackCastlingRights;

            return(playerSide.HasFlag(side));
        }
Example #3
0
        /// <summary>
        /// Returns a list of valid squares a king can move to.  The list can be empty
        /// </summary>
        /// <param name="piece">ChessPiece to examine</param>
        /// <param name="board">ChessBoard the piece exists within</param>
        /// <returns>List of valid squares, or empty list</returns>
        public static List <BoardSquare> GetLegalMoves_King(ChessPiece piece, ChessBoard board)
        {
            List <BoardSquare> moves = new List <BoardSquare>();

            /* The King is special.  He can move one square in any direction
             * (provided it is on the board) so long as the square is empty or
             * it has an opponent piece on it.  However, the King can never
             * move into check, even if the square or capture would be legal
             * otherwise, so it requires some extra checking.
             *
             * Further complicating things, if the king is castling, he cannot
             * move THROUGH check either (basically check those squares as if
             * they were final destinations)
             *
             * +---+---+---+---+---+---+---+---+
             * |   |   |   |   |   |   |   |   |
             * +---+---+---+---+---+---+---+---+  r = enemy rook (block)
             * |   |   |   |   |   | p |   |   |  T = Move or capture
             * +---+---+---+---+---+---+---+---+  p = enemy pawn (block)
             * |   |   | T | T | X |   | b |   |  b = enemy bishop (block)
             * +---+---+---+---+---+---+---+---+  X = illegal move
             * |   |   | T | K | T |   |   |   |
             * +---+---+---+---+---+---+---+---+     +---+---+---+---+---+---+
             * |   |   | T | T | X |   |   |   |     | K | T |   |   |   |   |
             * +---+---+---+---+---+---+---+---+     +---+---+---+---+---+---+
             * |   |   |   |   |   |   |   |   |     | X | X |   |   |   | r |
             * +---+---+---+---+---+---+---+---+     +---+---+---+---+---+---+
             * |   |   |   |   |   |   |   |   |     |   |   |   |   |   |   |
             * +---+---+---+---+---+---+---+---+     +---+---+---+---+---+---+
             */

            // Cannot castle if in check
            if (!IsSquareInCheck(board, piece.File, piece.Rank, piece.Color))
            {
                /* Castling may only be done if the king has never moved, the rook involved has never moved,
                 * the squares between the king and the rook involved are unoccupied, the king is not in check,
                 * and the king does not cross over or end on a square in which it would be in check.
                 *
                 * The ChessBoard will keep track of the castling rights when various pieces move, but it
                 * won't constantly update the legality of the move
                 */

                // Build a list of squares to check
                BoardSide   castlingRights = (piece.Color == PieceColor.White) ? board.WhiteCastlingRights : board.BlackCastlingRights;
                BoardSide[] sidesToCheck   = new BoardSide[2] {
                    BoardSide.King, BoardSide.Queen
                };
                foreach (BoardSide sideToCheck in sidesToCheck)
                {
                    // Backrank depends on color
                    int           kingRank = (piece.Color == PieceColor.White) ? 1 : 8;
                    BoardSquare[] squares  = null;

                    // First check if we still have the right, if not, no need to persue it
                    if (castlingRights.HasFlag(sideToCheck))
                    {
                        squares = new BoardSquare[2];
                        // The target Files depend on the side of the board we're checking
                        // put the final target in [0]
                        if (sideToCheck == BoardSide.King)
                        {
                            squares[0] = new BoardSquare(new PieceFile(7), kingRank);
                            squares[1] = new BoardSquare(new PieceFile(6), kingRank);
                        }
                        else // Queenside
                        {
                            squares[0] = new BoardSquare(new PieceFile(3), kingRank);
                            squares[1] = new BoardSquare(new PieceFile(4), kingRank);
                        }
                    }

                    // There should be 2 and only 2 from above if we found potential targets
                    if (squares != null)
                    {
                        // must be empty and not in check - empty is faster so verify it first
                        if ((board.FindPieceAt(squares[0].File, squares[0].Rank) == null) &&
                            (board.FindPieceAt(squares[1].File, squares[1].Rank) == null))
                        {
                            // Now make sure neither square is in check
                            if (!IsSquareInCheck(board, squares[0].File, squares[0].Rank, piece.Color) &&
                                !IsSquareInCheck(board, squares[1].File, squares[1].Rank, piece.Color))
                            {
                                // King can still castle to this side, add the move option
                                moves.Add(squares[0]);
                            }
                        }
                    }
                }
            }
            // Check each of the 8 squares around the king.  If it's free or has
            // an enemy piece, then check if it's targetable by the opponent
            // (moving into check)  If not, then add it to the list
            CheckPieceTargets checkKingTargets = (p, fileDelta, rankDelta, b, m) =>
            {
                // Verify targets are reachable (not off edge)
                int startCol = p.File.ToInt();
                int startRow = p.Rank;

                int  endCol = startCol + (fileDelta);
                int  endRow = startRow + (rankDelta);
                bool occupied; // ignored here
                if (SquareIsFreeOrContainsOpponent(endCol, endRow, b, p.Color, out occupied))
                {
                    m.Add(new BoardSquare(new PieceFile(endCol), endRow));
                }
            };

            // Check all 8 squares around the king
            checkKingTargets(piece, 0, 1, board, moves);
            checkKingTargets(piece, 0, -1, board, moves);
            checkKingTargets(piece, 1, 0, board, moves);
            checkKingTargets(piece, -1, 0, board, moves);
            checkKingTargets(piece, 1, 1, board, moves);
            checkKingTargets(piece, -1, -1, board, moves);
            checkKingTargets(piece, 1, -1, board, moves);
            checkKingTargets(piece, -1, 1, board, moves);

            // Check violations are handled by the common caller for regulatr moves
            return(moves);
        }