Exemple #1
0
        /// <summary>
        /// Determines if the neighboring square is empty.
        /// Returns true if the neighboring square exists and is empty. Otherwise returns false.
        /// </summary>
        /// <param name="boardLocation"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public bool NeighboringLocationIsEmpty(BoardLocation boardLocation, Direction direction)
        {
            var neighbor = boardLocation.Neighbor(direction);

            if (neighbor.HasValue && this[neighbor.Value] == ChessPiece.None)
            {
                return(true);
            }

            return(false);
        }
Exemple #2
0
        /// <summary>
        /// Determines if the neighboring square is occupied by the given player.
        /// Returns true if the neighboring square exists and is occupied by the given player. Otherwise returns false.
        /// </summary>
        /// <param name="boardLocation"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public bool NeighboringLocationIsOccupiedBy(BoardLocation boardLocation, Direction direction, Player player)
        {
            var neighbor = boardLocation.Neighbor(direction);

            if ((neighbor.HasValue) &&
                (this[neighbor.Value].BelongsTo(player)))
            {
                return(true);
            }

            return(false);
        }
Exemple #3
0
        /// <summary>
        /// Determines if the neighboring square is empty or occupied by the supplied player.
        /// Returns true if the neighboring square exists and is either empty or has a piece belonging to the given player. Otherwise returns false.
        /// </summary>
        /// <param name="boardLocation"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public bool NeighboringLocationIsEmptyOrOccupiedBy(BoardLocation boardLocation, Direction direction, Player player)
        {
            var neighbor = boardLocation.Neighbor(direction);
            var piece    = this[neighbor.Value];

            if ((neighbor.HasValue) &&
                (piece.BelongsTo(player) || piece == ChessPiece.None))
            {
                return(true);
            }

            return(false);
        }
Exemple #4
0
        public static List <BoardLocation> Neighbors(this BoardLocation currentLocation)
        {
            List <BoardLocation> boardLocations = new List <BoardLocation>();

            foreach (Direction dir in Enum.GetValues(typeof(Direction)))
            {
                var result = currentLocation.Neighbor(dir);

                if (result.HasValue)
                {
                    boardLocations.Add(result.Value);
                }
            }

            return(boardLocations);
        }
Exemple #5
0
        private bool PieceIsPinned(Board board, BoardLocation piecesLocation, BoardLocation kingsLocation, Direction direction)
        {
            BoardLocation?currentLocation = piecesLocation.Neighbor(direction);

            while (currentLocation != null)
            {
                //get the piece
                var piece = board[currentLocation.Value];

                if (currentLocation == kingsLocation)
                {
                    return(true);
                }
                else if (board[currentLocation.Value] != ChessPiece.None)
                {
                    break;
                }

                currentLocation = currentLocation.Neighbor(direction);
            }

            return(false);
        }
Exemple #6
0
 public static BoardLocation?Neighbor(this BoardLocation?currentLocation, Direction direction) => currentLocation?.Neighbor(direction);
Exemple #7
0
        private void AddDirectionalThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            Direction direction,
            ThreatMatrix threatMatrix)
        {
            //get the next square in the given direction
            BoardLocation?currentLocation = opposingPieceBoardLocation.Neighbor(direction);

            //for directional threats the king might be pinned...
            var kingCouldBePinned = playerKingLocation.IsInGivenDirectionFrom(opposingPieceBoardLocation, direction);
            var threatDirection   = direction.ToThreatDirection();

            while (currentLocation != null)
            {
                //get the piece
                var piece = board[currentLocation.Value];

                //as long as we are empty we can keep moving!
                if (piece == ChessPiece.None)
                {
                    //empty square, no pin possible
                    AddThreat(threatMatrix, playerKingLocation, opposingPieceBoardLocation, currentLocation.Value, threatDirection);
                }
                else
                {
                    ThreatDirection?pinDirection = null;

                    //our piece which MIGHT have a pin if our king is on the same directional vector..check for it
                    if ((piece.BelongsTo(player)) &&
                        (kingCouldBePinned) &&
                        PieceIsPinned(board, currentLocation.Value, playerKingLocation, direction))
                    {
                        pinDirection = direction.ToThreatDirection();
                    }

                    AddThreat(
                        threatMatrix,
                        playerKingLocation,
                        opposingPieceBoardLocation,
                        currentLocation.Value,
                        threatDirection,
                        pinDirection);

                    //NOTE: This is a hack, but its a domain hack. From a threat perspective, we can pretend
                    //that the enemy king is 'invisible'. This will allow long range threats to penetrate the king
                    //and proceed to any columns, rows, or diagonals he is on. This in turn will help us
                    //when determining the kings moves by making 'backing up' an invalid strategy for him.
                    //without this check, a king himself would demarcate the end of a long range threat (since a piece is like a stop)
                    //but THAT would create the problem of making it seem like the square behind him was 'safe'. For Example:
                    //   |  |  |  |  |         |  |  |  |  |
                    //   |  |WR|BK|  |  To=>   |  |WR|  |BK|  would be allowed
                    //   |  |  |  |  |         |  |  |  |  |
                    //Where it is kind of a hack is by treating the king as invisible it means the white rook is threatening
                    //'beyond' a piece. Theoretically, this would then also allow it to move into those spaces, in essence just
                    //'hoping over' the king. This would be a HUGE problem if not for the golden rule of chess that it is impossible
                    //to make a move that actually captures a king. The game literally ends as soon as a board state emerges where
                    //a king is able to captured on the next turn. Not sure why this is, I am sure it harkens back to some
                    //haughty rule about how 'ignoble' it would be to ever allow the capture of a royal.
                    if (piece.IsKing(player) == false)
                    {
                        //short circuit search since we are done
                        break;
                    }
                }

                currentLocation = currentLocation.Neighbor(direction);
            }
        }
Exemple #8
0
        private void FindPawnMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPieceThreatDirection)
        {
            var opposingPlayer       = player.OpposingPlayer();
            var marchDirection       = player == Player.White ? Direction.North : Direction.South;
            var gradeAttackDirection = player == Player.White ? Direction.NorthEast : Direction.SouthWest;
            var slopeAttackDirection = player == Player.White ? Direction.NorthWest : Direction.SouthEast;

            //check to see if we can move up/down
            //note that any diagonal or horizontal threats will block these moves
            if ((playerPieceThreatDirection.HasThreats(ThreatDirection.Horizontal | ThreatDirection.Diagonal) == false) &&
                (_board.NeighboringLocationIsEmpty(playerPieceLocation, marchDirection)))
            {
                var firstMarchLocation = playerPieceLocation.Neighbor(marchDirection).Value;
                var row = firstMarchLocation.Row();
                if (row == 0 || row == 7)//we can assume this is a pawn promotion
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionKnight));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionBishop));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionRook));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionQueen));
                }
                else
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation));
                }

                //we can also move up two spaces if the next northern square is empty
                if ((playerPieceLocation.IsPawnStartingLocation(player)) &&
                    (_board.NeighboringLocationIsEmpty(firstMarchLocation, marchDirection)))
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation.Neighbor(marchDirection).Value));
                }
            }

            //check to see if we can move along the grade
            //note that any line or slope threats will block this move
            if (playerPieceThreatDirection.HasThreats(ThreatDirection.Line | ThreatDirection.Slope) == false)
            {
                //if we have an opposing piece in the next square, make hte move
                if (_board.NeighboringLocationIsOccupiedBy(playerPieceLocation, gradeAttackDirection, opposingPlayer))
                {
                    var neighbor = playerPieceLocation.Neighbor(gradeAttackDirection).Value;
                    var row      = neighbor.Row();

                    //capture pawn promotion
                    if (row == 0 || row == 7)
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionKnight));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionBishop));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionRook));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionQueen));
                    }
                    else//normal capture
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor]));
                    }
                }
                else if (LastMoveAllowsEnPassantFor(playerPieceLocation, gradeAttackDirection))
                {//we can do an en passant.
                    var neighbor = playerPieceLocation.Neighbor(gradeAttackDirection).Value;
                    moves.Add(new Move(playerPieceLocation, neighbor, CurrentPlayer == Player.White ? ChessPiece.BlackPawn : ChessPiece.WhitePawn, SpecialMoveType.AuPassant));
                }
            }

            //check to see if we can move along the slope
            //note that any line or grade threats will block this move
            if (playerPieceThreatDirection.HasThreats(ThreatDirection.Line | ThreatDirection.Grade) == false)
            {
                //if we have an opposing piece in the next square, make hte move
                if (_board.NeighboringLocationIsOccupiedBy(playerPieceLocation, slopeAttackDirection, opposingPlayer))
                {
                    var neighbor = playerPieceLocation.Neighbor(slopeAttackDirection).Value;
                    var row      = neighbor.Row();

                    //capture pawn promotion
                    if (row == 0 || row == 7)
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionKnight));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionBishop));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionRook));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionQueen));
                    }
                    else//normal capture
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor]));
                    }
                }
                else if (LastMoveAllowsEnPassantFor(playerPieceLocation, slopeAttackDirection))
                {//we can do an en passant.
                    var neighbor = playerPieceLocation.Neighbor(slopeAttackDirection).Value;
                    moves.Add(new Move(playerPieceLocation, neighbor, CurrentPlayer == Player.White ? ChessPiece.BlackPawn : ChessPiece.WhitePawn, SpecialMoveType.AuPassant));
                }
            }
        }