I’m making a chess game using pygame, most of the problems and bugs are solved hopefully but there’s only one more that’s bugging me out. In chess, kings cannot move to other king’s adjacent squares. I have a function called in_check it basically returns False if with the provided move, the king will be in check, i actually hopped that it’ll work as it is for the kings’ moves too but it only worked for any other piece. So i upgraded it and added a few more codes as you can see here:
<code>def in_check(self, piece: Piece, move: Move):
virtual_piece, virtual_board = deepcopy(piece), deepcopy(self) # saves a copy of the board and piece
virtual_board.move(virtual_piece, move, True) # moves the copied piece on the copied board so it won't actually move the real one, because we wanna check if the king will be in check, and then deny the move
for row in range(ROWS): # going through each row
for col in range(COLS): # going through each column
l = virtual_board.squares[row][col] # saving the square in a variable
p = l.piece # saving the piece in that square in another variable
if l.has_enemy_piece(piece.color): # if that square contains enemy piece
virtual_board.calculate_moves(p, row, col, False) # we recalculate the moves for the enemy piece to update the moves(we always update the moves everytime a piece has moved)
# -----------------------------
if isinstance(piece, King) and isinstance(p, King): # if both pieces were kings
for m in p.moves: # going through each move for each piece
for M in virtual_piece.moves: # going through each move for each piece(here i go through the virtual_piece moves since it was recently updated)
if m.final == M.final: piece.moves.remove(M) # if both end up on the same square, we remove the move from the ACTUAL piece so it won't be able to move there
# ----------------------------- These are the lines i've added to fix the bug
for m in p.moves: # going through the moves for the enemy piece(in this part we return True if the piece's move will let enemy to capture the king)
if isinstance(m.final.piece, King): # if the final square of the piece is a king
if not INSTANT_CHECKMATE: return True # this INSTANT_CHECKMATE is just a game mode that'll let players to actually capture the kings and end the game right there
return False # we reach here only if INSTANT_CHECKMATE is enabled which means we return False so the move will be valid
return False # after all the checks if we found out that the move isn't gonna put the friendly king in a check, return False so we'll accept the move as valid
<code>def in_check(self, piece: Piece, move: Move):
virtual_piece, virtual_board = deepcopy(piece), deepcopy(self) # saves a copy of the board and piece
virtual_board.move(virtual_piece, move, True) # moves the copied piece on the copied board so it won't actually move the real one, because we wanna check if the king will be in check, and then deny the move
for row in range(ROWS): # going through each row
for col in range(COLS): # going through each column
l = virtual_board.squares[row][col] # saving the square in a variable
p = l.piece # saving the piece in that square in another variable
if l.has_enemy_piece(piece.color): # if that square contains enemy piece
virtual_board.calculate_moves(p, row, col, False) # we recalculate the moves for the enemy piece to update the moves(we always update the moves everytime a piece has moved)
# -----------------------------
if isinstance(piece, King) and isinstance(p, King): # if both pieces were kings
for m in p.moves: # going through each move for each piece
for M in virtual_piece.moves: # going through each move for each piece(here i go through the virtual_piece moves since it was recently updated)
if m.final == M.final: piece.moves.remove(M) # if both end up on the same square, we remove the move from the ACTUAL piece so it won't be able to move there
# ----------------------------- These are the lines i've added to fix the bug
for m in p.moves: # going through the moves for the enemy piece(in this part we return True if the piece's move will let enemy to capture the king)
if isinstance(m.final.piece, King): # if the final square of the piece is a king
if not INSTANT_CHECKMATE: return True # this INSTANT_CHECKMATE is just a game mode that'll let players to actually capture the kings and end the game right there
return False # we reach here only if INSTANT_CHECKMATE is enabled which means we return False so the move will be valid
return False # after all the checks if we found out that the move isn't gonna put the friendly king in a check, return False so we'll accept the move as valid
</code>
def in_check(self, piece: Piece, move: Move):
virtual_piece, virtual_board = deepcopy(piece), deepcopy(self) # saves a copy of the board and piece
virtual_board.move(virtual_piece, move, True) # moves the copied piece on the copied board so it won't actually move the real one, because we wanna check if the king will be in check, and then deny the move
for row in range(ROWS): # going through each row
for col in range(COLS): # going through each column
l = virtual_board.squares[row][col] # saving the square in a variable
p = l.piece # saving the piece in that square in another variable
if l.has_enemy_piece(piece.color): # if that square contains enemy piece
virtual_board.calculate_moves(p, row, col, False) # we recalculate the moves for the enemy piece to update the moves(we always update the moves everytime a piece has moved)
# -----------------------------
if isinstance(piece, King) and isinstance(p, King): # if both pieces were kings
for m in p.moves: # going through each move for each piece
for M in virtual_piece.moves: # going through each move for each piece(here i go through the virtual_piece moves since it was recently updated)
if m.final == M.final: piece.moves.remove(M) # if both end up on the same square, we remove the move from the ACTUAL piece so it won't be able to move there
# ----------------------------- These are the lines i've added to fix the bug
for m in p.moves: # going through the moves for the enemy piece(in this part we return True if the piece's move will let enemy to capture the king)
if isinstance(m.final.piece, King): # if the final square of the piece is a king
if not INSTANT_CHECKMATE: return True # this INSTANT_CHECKMATE is just a game mode that'll let players to actually capture the kings and end the game right there
return False # we reach here only if INSTANT_CHECKMATE is enabled which means we return False so the move will be valid
return False # after all the checks if we found out that the move isn't gonna put the friendly king in a check, return False so we'll accept the move as valid
Once i added those lines, at the first look i thought it fixed the bug:
Image1 Image2 Image3
But after a few other moves i saw these(I’ve also crossed the move that is supposed to be invalid): problem1 problem2 problem3
As shown in the last three screen-shots, always 1 square is the invalid move. I tried so many different option(been on this for 3 days straight to be honest) added the same codes to different parts of the program, instead of removing the move used to just return False but didn’t work, just so many options and didn’t work. This code is only the best i did come up with.