Programmatic Chess Analysis: Determining if the King is in Check

It all started a few years ago when I got the idea of programmatically analyzing a chess position using the Stockfish chess engine to measure position “risk” or “sharpness”. In order to do that I needed a utility function to convert a chess game stored in PGN notation to FEN notation.

Implementing that conversion function took a long time and was very difficult.

Somewhat surprisingly, in all the functions and helper functions for the file conversion utility, it was never necessary to determine if either king is in check — as long as the source PGN file was assumed to be valid.

I was walking my dogs one afternoon after work and I wondered about implementing a function to determine if a king is in check. By the end of my walk, I had an algorithm figured out in my head.

The key to the implementation of the is_king_in_check(king_color, fen_string_full) function is leveraging an existing helper function can_reach(piece_type_uncased, came_from_square, landing_square, board_position). For example, for the initial starting position, can_reach(“N”, 57, 42, initial_board_position) is True because the white knight on b1 can reach square c3. The can_reach() function is used to see any enemy piece can attack the opposing king.


My chess functions use the board representation on the right

With that function in hand (but believe me, it is a very complex function) my is_king_in_check() function is:

  @staticmethod
  def is_king_in_check(king_color, fen_string_full):
    # king_color is "w" or "b"
    # fen_string_full is position plus e.p., move counters, etc.
    fen_pos = fen_string_full.split(" ")[0]  # just the board position part
    board_pos = ChessFunctions.fen_string_to_board_position(fen_pos)
    
    # white king
    if king_color == "w":
      # find location of white king
      king_loc = -1
      for i in range(64):
        if board_pos[i] == "K":
          king_loc = i
          break
      if king_loc == -1: print("Fatal logic in is_king_in_check() ")

      # check if white king under pawn attack
      if king_loc - 9 "gte" 0 and board_pos[king_loc-9] == "p": return True
      if king_loc - 7 "gte" 0 and board_pos[king_loc-7] == "p": return True

      # check if under piece attack using
      # can_reach(piece_type_uncased, came_from_square, landing_square,
      #   board_position)
      for i in range(64):
        if board_pos[i] == "r" or board_pos[i] == "n" or board_pos[i] == "b" or \
        board_pos[i] == "q":
          piece_type_uncased = board_pos[i].upper()
          if ChessFunctions.can_reach(piece_type_uncased, i, king_loc,
          board_pos) == True:
            return True
        else:
          continue  # at empty square or white color piece
    elif king_color == "b":
      # find location of black king
      king_loc = -1
      for i in range(64):
        if board_pos[i] == "k":
          king_loc = i
          break
      if king_loc == -1: print("Fatal logic in is_king_in_check() ")

      # check if black king under pawn attack
      if king_loc + 9 "lte" 63 and board_pos[king_loc+9] == "P": return True
      if king_loc + 7 "lte" 0 and board_pos[king_loc+7] == "P": return True

      # check if under piece attack using
      # can_reach(piece_type_uncased, came_from_square, landing_square,
      #   board_position)
      for i in range(64):
        if board_pos[i] == "R" or board_pos[i] == "N" or board_pos[i] == "B" or \
        board_pos[i] == "Q":
          piece_type_uncased = board_pos[i]
          if ChessFunctions.can_reach(piece_type_uncased, i, king_loc,
          board_pos) == True:
            return True
        else:
          continue  # at empty square or black color piece

    return False

I tested my function by walking through several chess games, including Lasker-Thomas 1912 that featured an unusual king hunt and checkmate via castling queenside. I placed a call to is_king_in_check() inside the GameState.display_enhanced() function.

def main():
  print("\nBegin test is_king_in_check() function ")

  # 6. test is_king_in_check() via GameState.display_enhanced()
  fen_file = ".\\MiscFEN\\lasker_thomas_london_1912.fen"
  f = open(fen_file, "r")
  for line in f:
    print(line)
    gs = GameState.from_fen(line)
    gs.display_enhanced()  # calls is_king_in_check()
    input()
  f.close()
  print("Done")
  input()

  print("\nEnd ")

The is_king_in_check() function is an example where the algorithm idea is simple — I worked it out in my head while walking my two dogs — but the implementation was quite a bit trickier than I was expecting. But it was a fun mental exercise for sure.



When I was a young man, I was pretty good at chess. My high school team won the Orange County (California) High School chess championship in my junior and senior years. The three books I learned the most from were:

Left: “Lessons From My Games: A Passion for Chess” (1958) by Reuben Fine. Fine was arguably the strongest player in the world during the late 1930s. He could explain things very clearly and studying his games helped me a lot. The book cover shown is from the 1967 edition that I read.

Center: “Chess Openings Theory and Practice” (1964) by I.A. Horowitz. An alternative to the more widely read “Modern Chess Openings, 10th edition” (1965) by Walter Korn and Larry Evans. “Theory and Practice” was the most beloved thing I ever owned. It cost $9.95 — roughly the equivalent of $90.00 today — and my mother bought it for my birthday. I was so happy I almost cried.

Right: “Chess Master vs. Chess Amateur” (1963) by former world champion Max Euwe and Walter Meiden. The format was groundbreaking in that every move of every game was explained. I checked this book out from the Fullerton California public library over and over and over.

Chess has changed a lot. I loved these old books but objectively, a modern chess player can learn more by watching two hours of high quality YouTube videos (the videos by Eric Rosen for example) than I learned in a couple of years.


This entry was posted in Programmatic Chess. Bookmark the permalink.

Leave a Reply