Chess programming (without AI) - move validation

I am trying to program my own chess engine (without AI). I know there is a Chess Game Starter Kit , and I watched it for inspiration.

But what I did not catch is where are the validated moves ( here the validation of the moves ) for my non-kings, which prevent me from checking?

Imagine a situation:
A5 - enemy liner
A4 - my bishop
A3 is my king

Now I cannot move my bishop, since I have to check.

Or how would you suggest checking this situation?

thanks

+6
source share
2 answers

For a given position on the board, most chess engines are only launched using pseudo-legal moves. By pseudo-legal, I mean that a move will be generated, even if it:

  • Leave the king in a cage
  • Moves the king to the check
  • Castles in the attacked squares

The reason for this is performance. Since many moves will not actually be searched due to beta reduction, you save time by avoiding a full check of the validity of the moves.

For each step that is sought, you must make sure that it is truly valid. This is usually done by passing the color and square of the King (and the squares next to the King for the castling move) to the IsAttacked method. If this method returns true, you know that this movement is not valid and therefore you should not include it in your search.

This is the IsAttacked method from my own C # chess engine. Keep in mind that my engine is a -based magic board , so the code will not directly apply to the chess starting set that you are associated with. If you are not familiar with magic bitboards, the translation will not be trivial.

// IsAttacked is primarily used as a move legality test to see if a set of // one or more squares is under attack from the side to move. // It returns true as soon as an attack is detected, otherwise returns false. // It can be used for check detection, castling legality, or simply to // detect whether a specific square is attacked. internal bool IsAttacked(Board board, UInt64 targetSquares, bool whiteAttacking) { UInt64 slidingAttackers; Int32 targetSquare; UInt64 remainingTargetSquares = targetSquares; // Test for attacks by WHITE on any of the target squares. if (whiteAttacking) { // For the remaining target squares... while (remainingTargetSquares != 0) { // Find the next square in the list. targetSquare = BitOperations.BitScanForward(remainingTargetSquares); // Is this square attacked by a pawn, knight, or king? if ((board.WhitePawns & Constants.BLACK_PAWN_ATTACKS[targetSquare]) != 0) return true; if ((board.WhiteKnights & Constants.KNIGHT_ATTACKS[targetSquare]) != 0) return true; if ((board.WhiteKing & Constants.KING_ATTACKS[targetSquare]) != 0) return true; // Is this square attacked by a queen or rook along a file or rank? slidingAttackers = board.WhiteQueens | board.WhiteRooks; if (slidingAttackers != 0) { if (this.RankMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; if (this.FileMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; } // Is this square attacked by a queen or bishop along a diagonal? slidingAttackers = board.WhiteQueens | board.WhiteBishops; if (slidingAttackers != 0) { if (this.DiagonalA8H1Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; if (this.DiagonalA1H8Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; } // This square isn't attacked - remove and move on to next target square. remainingTargetSquares ^= Constants.BITSET[targetSquare]; } } // Test for attacks by BLACK on any of the target squares. else { // For the remaining target squares... while (remainingTargetSquares != 0) { // Find the next square in the list. targetSquare = BitOperations.BitScanForward(remainingTargetSquares); // Is this square attacked by a pawn, knight, or king? if ((board.BlackPawns & Constants.WHITE_PAWN_ATTACKS[targetSquare]) != 0) return true; if ((board.BlackKnights & Constants.KNIGHT_ATTACKS[targetSquare]) != 0) return true; if ((board.BlackKing & Constants.KING_ATTACKS[targetSquare]) != 0) return true; // Is this square attacked by a queen or rook along a file or rank? slidingAttackers = board.BlackQueens | board.BlackRooks; if (slidingAttackers != 0) { if (this.RankMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; if (this.FileMoves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; } // Is this square attacked by a queen or bishop along a diagonal? slidingAttackers = board.BlackQueens | board.BlackBishops; if (slidingAttackers != 0) { if (this.DiagonalA8H1Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; if (this.DiagonalA1H8Moves(board.OccupiedSquares, slidingAttackers, targetSquare) != 0) return true; } // This square isn't attacked - remove and move on to next target square. remainingTargetSquares ^= Constants.BITSET[targetSquare]; } } // None of the target squares are attacked. return false; } 

Here is a snippet of code that generates pseudo-legal castling moves for whites:

 // If White can still castle kingside... if ((board.WhiteCastlingStatus & Board.EnumCastlingStatus.CanCastleOO) != 0) { // And the White kingside castling squares (F1/G1) aren't occupied... if ((Constants.MASK_FG[Constants.WHITE_MOVE] & board.OccupiedSquares) == 0) { board.MoveBuffer[moveIndex++] = Constants.WHITE_CASTLING_OO; } } // If White can still castle queenside... if ((board.WhiteCastlingStatus & Board.EnumCastlingStatus.CanCastleOOO) != 0) { // And the White queenside castling squares (D1/C1/B1) aren't occupied... if ((Constants.MASK_BD[Constants.WHITE_MOVE] & board.OccupiedSquares) == 0) { board.MoveBuffer[moveIndex++] = Constants.WHITE_CASTLING_OOO; } } 

And here is the code that checks if the pseudo-legal castling move is really legal:

 // Checks whether the King is moving from or into check. // Checks whether the King is moving across attacked squares. internal bool IsCastlingMoveLegal(Board board, Move move) { if (move.IsCastlingOO) { if (move.IsWhiteMove) { // Are any of the White kingside castling squares (E1/F1/G1) attacked? return !this.IsAttacked(board, Constants.MASK_EG[Constants.WHITE_MOVE], false); } else { // Are any of the Black kingside castling squares (E8/F8/G8) attacked? return !this.IsAttacked(board, Constants.MASK_EG[Constants.BLACK_MOVE], true); } } else if (move.IsCastlingOOO) { if (move.IsWhiteMove) { // Are any of the White queenside castling squares (E1/D1/C1) attacked? return !this.IsAttacked(board, Constants.MASK_CE[Constants.WHITE_MOVE], false); } else { // Are any of the Black queenside castling squares (E8/D8/C8) attacked? return !this.IsAttacked(board, Constants.MASK_CE[Constants.BLACK_MOVE], true); } } // Not a castling move! else { Debug.Assert(false, "Not a castling move!"); return true; } } 
+16
source

My chess program has a method that checks if the field is threatening. When calculating the movements for the king, he checks each field where the king can move if this field is at risk.

0
source

Source: https://habr.com/ru/post/895923/


All Articles