Checking to see if any square is threatened is a useful function that you may use not only for direct King attacks but also for castling since a King is not allowed to castle "through" check.
This means you have to ensure up to three squares are free from an opponent's direct line of attack to castle the King legally.
With this is mind, you might want to construct a method such as this:
public static final boolean isThreatenedSquare(
Color threatenedColor,
Square threatenedSquare,
Chessboard board)
The algorithm for sliding pieces might employ parallel arrays to define the 8 directions (lines of attack or "rays") that radiate out from origin (the threatened square). For example:
int[] rowDirections = {-1, -1, -1, 0, 0, 1, 1, 1};
int[] colDirections = {-1, 0, 1, -1, 1, -1, 0, 1};
- the first index set (-1, -1) represents a diagoanl "ray" moving in a "northwest" direction
- the second index set (-1, 0) represents a vertical "ray" moving in a "north" direction
- the third index set (-1, 1) represents a diagonal "ray" moving in a "northeast" direction
- the fourth index set (0, -1) represents a horizontal "ray" moving in a "west" direction
... and so on. By radiating out one square at a time, you would simply inspect the square (ensuring you are within chessboard boundaries) and see if it is occupied. If it is, determine whether it is a friendly or opponent piece. Just because we have hit an opponent's piece does not necessarily mean our threatened square is under attack.
Bishops, for example can only attack along diagonal rays so finding one along a vertical ray stops our ray from radiating out any further however the Bishop does not threaten the square.
We can neatly describe the attacking capabilities for any sliding piece with respect to the parallel directional arrays we defined earlier. For example:
boolean bishopThreats[] = {true, false, true, false, false, true, false, true};
boolean rookThreats[] = {false, true, false, true, true, false, true, false};
boolean queenThreats[] = {true, true, true, true, true, true, true, true};
boolean kingThreats[] = {true, true, true, true, true, true, true, true};
The arrays above show that Bishops can only threaten along diagonals, Rooks along vertical and horizontal lines, Queens and Kings can attack in any direction.
Pawns are somewhat tricky because they attack along diagonals but only in northeast + northwest directions (for white), and southeast + southwest directions (for black).
boolean kill = threatenedColor.equals(Color.black) ? true : false;
boolean pawnThreats[] = {kill, false, kill, false, false, !kill, false, !kill};
With everything in place, all that is required is to use a couple of nested for loops. The outer one to iterate through all directions, the inner one to radiate out one square at a time until we hit the edge of the chessboard or hit a piece, whichever comes first. Here is the algorithm for sliding pieces. Knight are abit different than sliding pieces but the general ideas presented here also apply.
boolean threatDetected = false;
int threatenedRow = threatenedSquare.getRow();
int threatenedCol = threatenedSquare.getCol();
for(int direction = 0; direction < 8 && !threatDetected; direction++) {
// RESET OUR COORDINATES TO PROCESS CURRENT LINE OF ATTACK.
// INCREMENT VALUES ARE SAME AS DIRECTION ARRAY VALUES
int row = threatenedRow;
int col = threatenedCol;
int rowIncrement = rowDirections[direction];
int colIncrement = colDirections[direction];
// RADIATE OUTWARDS STARTING FROM ORIGIN UNTIL WE HIT A PIECE OR ARE OUT OF BOUNDS
for(int step = 0; step < 8; step++) {
row = row + rowIncrement;
col = col + colIncrement;
// IF WE ARE OUT OF BOUNDS, WE STOP RADIATING OUTWARDS FOR
// THIS RAY AND TRY THE NEXT ONE
if(row < 0 || row > 7 || col < 0 || col > 7) {
break;
}
else {
// LOOK AT CURRENT SQUARE AND SEE IF IT IS OCCUPIED BY A PIECE
Square square = board.getSquare(row, col);
IPiece piece = square.getPiece();
if(piece != null) {
// RADIATING OUTWARDS MUST STOP SINCE WE HIT A PIECE, ONLY
// QUESTION IS WHAT DID WE HIT? FRIEND OR FOE?
if(!piece.getColor.equals(threatenedColor)) {
// WE ARE FACING AN OPPONENT, DOES IT HAVE THE CAPABILITY
// TO ATTACK US GIVEN THE DIRECTIONAL LINE OF ATTACK
// WE ARE CURRENTLY ANALYZING
if(piece instanceof Bishop && bishopThreats[direction])
threatDetected = true;
else if(piece instanceof Rook && rookThreats[direction])
threatDetected = true;
else if(piece instanceof Queen && queenThreats[direction])
threatDetected = true;
else {
if(step == 0) {
// PAWNS AND KINGS DONT HAVE THE REACH OF OTHER SLIDING
// PIECES; THEY CAN ONLY ATTACK SQUARES THAT ARE CLOSEST
// TO ORIGIN
if(piece instanceof Pawn && pawnThreats[direction])
threatDetected = true;
if(piece instanceof King && kingThreats[direction])
threatDetected = true;
}
}
}
break;
}
}
}
}