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..