/// <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); }
/// <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); }
/// <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); }
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); }
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); }
public static BoardLocation?Neighbor(this BoardLocation?currentLocation, Direction direction) => currentLocation?.Neighbor(direction);
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); } }
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)); } } }