Overview
A chess program is nothing without a function that checks the validity of moves. This function allows the program to play legal moves and without it, nothing would be possible.
In this chapter we will analyze this function.
The computer utilizes this function at two points:
- When the human opponent enters his/ her move, in order to check the validity of that move.
- When the computer thinks, in order to check the validity of moves and try only the legal ones.
This can be illustrated better in the program algorithm below.

Chess program algorithm outline
In both of these cases the checking of the move’s legality works in exactly the same way; there is actually one function that performs these checks. This function is called whenever the user makes a move or whenever the computer itself ‘thinks’ of a move.
But how does this checking of moves’ legality works?
Check moves: The Bishop
Let’s start with an example: The bishop.
Checking the legality and validity of a move entails two things:
- Move validity: The piece is moving as it should. In the case of the bishop this means that the piece is ordered to move diagonally. Any other move should be discarded as invalid.
- Move legality: The movement of the piece does not break any other chess rules (yes, the move validity mentioned above is also a chess rule, I just like to differentiate that one – one could just name all these checks as ‘move legality’ check). The piece’s move should not be hindered by other pieces in its path. A piece of the same colour should not be in the destination square.
Let us explore a little bit further how these two facets of checking moves can be dealt with in a chess program.
Is the movement valid?
A bishop moves only in diagonals. The following schema shows the valid moves for a bishop in specific setup of the chessboard.

The program needs to scan the coordinates of the move and determine if the bishop moves in a diagonal.
Is the movement legal?
As mentioned above, the system should also check whether any other rules of chess are broken. When it comes to pieces moving, these are the main things to keep in mind:
- There should be no interference. No other piece should stand between the starting and the final square of the movement.
- There should be no piece of the same colour at the destination square.
- The movement should take place withing the boundaries of the chessboard (this is obvious, but just remember that for the computer nothing is obvious).
The schema below shows an example of an illegal move because a color of the same colour exists at the destination square.

Performing these checks could be difficult for someone starting to program, but if you get your mind to it you will see that there is not much in that. You just have to take it step by step and by consistent coding and unit testing you will get there.
Code Examples
Below you can see the source code of Huo Chess performing the legality check for a bishop.
Greek note: Legality is ‘Nomimotita’ (Νομιμότητα) and Validity is Orthotita (Ορθότητα) in Greek. Hence the names of the relevant functions in the C# version.
QBasic code
' ------------------------------------ BISHOP ------------------------------------
IF (MovingPieceEN$ = "wbishop" OR MovingPieceEN$ = "bbishop") THEN
'Check correctness of move (Bishop only moves in diagonals)
IF ((startRank = finishRank) OR (startColumn = finishColumn)) THEN NomimotitaEN = 0
IF (ABS(startColumn - finishColumn) <> ABS(startRank - finishRank)) THEN NomimotitaEN = 0
'Check if the piece moves beyond the limits of the chessboard
IF ((finishColumn < 1) OR (finishRank < 1)) THEN NomimotitaEN = 0
IF ((finishColumn > 8) OR (finishRank > 8)) THEN NomimotitaEN = 0
'Check if another piece is between the current and the target square
'Move down-left
IF (finishColumn < startColumn) AND (finishRank < startRank) THEN
FOR I = 1 TO 7
IF (startColumn - I) > 0 AND (startRank - I) > 0 THEN
IF (startColumn - I) > finishColumn AND (startRank - I) > finishRank AND ENSkakiera(startColumn - I, startRank - I) <> "" THEN NomimotitaEN = 0
END IF
NEXT I
END IF
'Move up-left
IF (finishColumn < startColumn) AND (finishRank > startRank) THEN
FOR I = 1 TO 7
IF (startColumn - I) > 0 AND (startRank + I) < 9 THEN
IF (startColumn - I) > finishColumn AND (startRank + I) < finishRank AND ENSkakiera(startColumn - I, startRank + I) <> "" THEN NomimotitaEN = 0
END IF
NEXT I
END IF
'Move up-right
IF (finishColumn > startColumn) AND (finishRank > startRank) THEN
FOR I = 1 TO 7
IF (startColumn + I) < 9 AND (startRank + I) < 9 THEN
IF (startColumn + I) < finishColumn AND (startRank + I) < finishRank AND ENSkakiera(startColumn + I, startRank + I) <> "" THEN NomimotitaEN = 0
'IF MovingPieceEN$ = "wbishop" AND startColumn = 2 AND startRank = 4 AND finishColumn = 5 AND finishRank = 7 THEN
' PRINT "Checkpoint 3.0 - Nomimotita = " + STR$(NomimotitaEN) + " (i = " + STR$(I) + ")"
' INPUT C$
'END IF
END IF
NEXT I
END IF
'Move down-right
IF (finishColumn > startColumn) AND (finishRank < startRank) THEN
FOR I = 1 TO 7
IF (startColumn + I) < 9 AND (startRank - I) > 0 THEN
IF (startColumn + I) < finishColumn AND (startRank - I) > finishRank AND ENSkakiera(startColumn + I, startRank - I) <> "" THEN NomimotitaEN = 0
END IF
NEXT I
END IF
IF debugMode = 1 AND NomimotitaEN = 0 THEN PRINT "Bishop - Checkpoint C"
'If the start square is the same as the destination...
IF startColumn = finishColumn AND startRank = finishRank THEN NomimotitaEN = 0
'Check if a piece of the same colour is at the destination square
IF MID$(ENSkakiera$(finishColumn, finishRank), 1, 1) = MID$(ENSkakiera$(startColumn, startRank), 1, 1) THEN NomimotitaEN = 0
END IF
C# code
(Check validity)
// Bishop
if ((MovingPiece_EO.CompareTo("White Bishop") == 0) || (MovingPiece_EO.CompareTo("Black Bishop") == 0))
{
if (((Math.Abs(finishColumn - startColumn)) == (Math.Abs(finishRank - startRank))) && (finishColumn != startColumn) && (finishRank != startRank))
Orthotita = true;
}
(Check legality)
...
else if ((MovingPiece_EN.CompareTo("White Rook") == 0) || (MovingPiece_EN.CompareTo("White Queen") == 0) || (MovingPiece_EN.CompareTo("White Bishop") == 0) || (MovingPiece_EN.CompareTo("Black Rook") == 0) || (MovingPiece_EN.CompareTo("Black Queen") == 0) || (MovingPiece_EN.CompareTo("Black Bishop") == 0))
{
h = 0;
p = 0;
//hhh = 0;
how_to_move_Rank = 0;
how_to_move_Column = 0;
// Determing the way the piece moves in ranks and in columns
if (((finishRank - 1) > (startRank - 1)) || ((finishRank - 1) < (startRank - 1)))
how_to_move_Rank = ((finishRank - 1) - (startRank - 1)) / System.Math.Abs((finishRank - 1) - (startRank - 1));
if (((finishColumn - 1) > (startColumn - 1)) || ((finishColumn - 1) < (startColumn - 1)))
how_to_move_Column = ((finishColumn - 1) - (startColumn - 1)) / System.Math.Abs((finishColumn - 1) - (startColumn - 1));
exit_elegxos_nomimothtas = false;
do
{
h = h + how_to_move_Rank;
p = p + how_to_move_Column;
if ((((startRank - 1) + h) == (finishRank - 1)) && ((((startColumn - 1) + p)) == (finishColumn - 1)))
exit_elegxos_nomimothtas = true;
// The movement should not exceed the chessboard boundaries
if ((startColumn - 1 + p) < 0)
exit_elegxos_nomimothtas = true;
else if ((startRank - 1 + h) < 0)
exit_elegxos_nomimothtas = true;
else if ((startColumn - 1 + p) > 7)
exit_elegxos_nomimothtas = true;
else if ((startRank - 1 + h) > 7)
exit_elegxos_nomimothtas = true;
// If a piece exists between the initial and the destination square, then the move is illegal!
if (exit_elegxos_nomimothtas == false)
{
if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White Rook") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White Knight") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White Bishop") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White Queen") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White King") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("White Pawn") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black Rook") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black Knight") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black Bishop") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black Queen") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black King") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if (ENSkakiera[(startColumn - 1 + p), (startRank - 1 + h)].CompareTo("Black Pawn") == 0)
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
}
} while (exit_elegxos_nomimothtas == false);
Java code
(Check validity)
// bishop
if ((MovingPiece_2.equals("WB")) || (MovingPiece_2.equals("BB")))
{
if (((Math.abs(finishColumn - startColumn)) == (Math.abs(finishRank - startRank))) && (finishColumn != startColumn) && (finishRank != startRank))
Orthotita = true;
}
(Check legality)
...
else if( (MovingPiece_2.equals("WR")) || (MovingPiece_2.equals("WQ")) || (MovingPiece_2.equals("WB")) || (MovingPiece_2.equals("BR")) || (MovingPiece_2.equals("BQ")) || (MovingPiece_2.equals("BB")) )
{
h = 0;
p = 0;
//hhh = 0;
how_to_move_Rank = 0;
how_to_move_Column = 0;
if(((finishRank-1) > (startRank-1)) || ((finishRank-1) < (startRank-1)))
how_to_move_Rank = ((finishRank-1) - (startRank-1))/ Math.abs((finishRank-1) - (startRank-1));
if(((finishColumn-1) > (startColumn-1)) || ((finishColumn-1) < (startColumn-1)) )
how_to_move_Column = ((finishColumn-1) - (startColumn-1))/Math.abs((finishColumn-1) - (startColumn-1));
exit_elegxos_nomimothtas = false;
do
{
h = h + how_to_move_Rank;
p = p + how_to_move_Column;
if( (((startRank-1) + h) == (finishRank-1)) && ((((startColumn-1) + p)) == (finishColumn-1)) )
exit_elegxos_nomimothtas = true;
if((startColumn - 1 + p)<0)
exit_elegxos_nomimothtas = true;
else if((startRank - 1 + h)<0)
exit_elegxos_nomimothtas = true;
else if((startColumn - 1 + p)>7)
exit_elegxos_nomimothtas = true;
else if((startRank - 1 + h)>7)
exit_elegxos_nomimothtas = true;
// if a piece exists between the initial and the destination square,
// then the move is illegal!
if( exit_elegxos_nomimothtas == false )
{
if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WR"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WN"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WB"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WQ"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WK"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("WP"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BR"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BN"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BB"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BQ"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BK"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
else if(ENSkakiera[(startColumn - 1 + p)][(startRank - 1 + h)].equals("BP"))
{
Nomimotita = false;
exit_elegxos_nomimothtas = true;
}
}
}while(exit_elegxos_nomimothtas == false);
}
You can study the examples to see how they work or you can just find your own (and better) way of doing the checks! Remember that Huo Chess is not optimized for performance but for education!
Epilogue
Having a working function to check for the legality of moves is a step forward our goal: To create an algorithm that scans through all potential moves, finds the legal ones and then from those it selects the best.
Keep tuned…
And keep coding!
Leave a Reply