This question addresses building a Chess engine. I've done just that, and in my humble opinion quite elegantly. But I'm missing my ending conditions.
Here are some pseudopython functions that I use.
# Move from position old to new def move(old, new): if is_legal(old, new): # Eat and move if is_legal(new, enemy_king) or check_in_los(enemy_king, old): # Set check on enemy king if piece_type == 'Pawn' and position at the end of board: # Convert to Queen def is_legal(old, new): # Assure piece is moving, it's your own and new position not on another own piece # Based on piece type, assure it's maneuvering properly # Assure there are no pieces in between the positions if applicable if piece_type == 'King': is_checked(new) # Not moving to a checked square elif checked: # Assure check is removed else: check_in_los(own_king, old) # Moving the piece does not create a check from behind # Determine if king is checked from line of sight def check_in_los(king_pos, direction): # Divide path into single-square steps # Find next piece in direction by incrementing king position by step if is_legal(next, king_pos): # King is checked from direction # Determine if king is checked def is_checked(king_pos): # Check if knight positions around kings contain enemy knights # For every 8 directions around king, check_in_los(king, direction)
Now on to the check mate. It would be trivial to check every position around the king if it is a legal position to be in, but that's not quite enough.
Consider the following scenario where the white king is being threatened:
A B C D E F G H 1 BR | | BR | | | | | 2 | | | | | | | 3 | | | | | | | 4 | | | | | | | 5 | | | | | | | 6 | | | | | | | 7 | | | | WN | | | 8 | WK | BQ | | | | |
The king (B8) has no legal moves left, but the knight (E7) can save him by eating the queen. Similarly if the placement of the queen is switched and the knight is a rook instead:
A B C D E F G H 1 BR | | BR | | | | | 2 | | | | | | | 3 | | | | | | | 4 | BQ | | | | | | 5 | | | | | | | 6 | | | | | | | 7 | | | | WR | | | 8 | WK | | | | | |
The white rook can save the king by moving to B7.
A naïve approach to checking for a mate would I guess involve checking every possibility, but that seems wasteful.
What would be a good way of achieving this? Preferably using the functions already in place. I'm also open to other approaches if needed. It crossed my mind that maybe it would be helpful to keep track of the checking pieces or even every square that is being checked and the checking pattern of each piece individually, but I'm not sure..