I need help with a chess bot (python)

I’m trying to make a chess bot, and I don’t know what to do or how. I’m also not sure if what I’ve done so far is right. help would be appreciated

check = False
checkmate = False

class board:
   def __init__(self, board):
      self.board = board
      self.turn = 'white'
      self.move_log = []
      self.white_king = (7,4)
      self.black_king = (0,4)
      self.white_rooks = [(0,0),(7,0)]
      self.black_rooks = [(0,7),(7,7)]
      self.white_knights = [(1,0),(6,0)]
      self.black_knights = [(1,7),(6,7)]
      self.white_bishops = [(2,0),(5,0)]
      self.black_bishops = [(2,7),(5,7)]
      self.white_pawns = [(i,1) for i in range(8)]
      self.black_pawns = [(i,6) for i in range(8)]
      self.white_queen = (3,0)
      self.black_queen = (3,7)   

      #ascii pieces
      self.board[self.white_king] = '♔'
      self.board[self.black_king] = '♚'
      self.board[self.white_queen] = '♕'
      self.board[self.black_queen] = '♛'
      self.board[self.white_rooks[0]] = '♖'
      self.board[self.white_rooks[1]] = '♖'
      self.board[self.black_rooks[0]] = '♜'
      self.board[self.black_rooks[1]] = '♜'
      self.board[self.white_knights[0]] = '♘'
      self.board[self.white_knights[1]] = '♘'
      self.board[self.black_knights[0]] = '♞'
      self.board[self.black_knights[1]] = '♞'
      self.board[self.white_bishops[0]] = '♗'
      self.board[self.white_bishops[1]] = '♗'
      self.board[self.black_bishops[0]] = '♝'
      self.board[self.black_bishops[1]] = '♝'
      self.board[self.white_pawns[i] for i in range(8)] = '♙'
      self.board[self.black_pawns[i] for i in range(8)] = '♟︎'

   #translating data from init function onto a board
   def print_board(self):
      print('  a b c d e f g h')
      print('  ----------------')
      for i in range(8):
         print(i+1, end='|')
         for j in range(8):
            print(self.board[i,j], end=' ')
         print('|', i+1)
      print('  ----------------')
      print('  a b c d e f g h')

   #
      


class piece:
   def __init__(self, color, type, x, y):
       self.color = color
       self.type = type
       self.x = x
       self.y = y
       self.moved = False
       self.alive = True
       self.symbol = self.type[0]
       if self.color == "white":
           self.symbol = self.symbol.upper()
       self.value = self.get_value()
       moves = self.check_moves()

   def get_value(self):
      #using berliner piece values
      if self.type == "pawn":
         return 1
      elif self.type == "knight":
         return 3.25
      elif self.type == "bishop":
         return 3.33
      elif self.type == "rook":
         return 5.10
      elif self.type == "queen":
         return 8.80
      elif self.type == "king":
         return 0

   #check if path is interrupted later
   def check_moves(self):
      self.moves = []
      potential_moves = []
      if self.type == "pawn":
         if self.color == "white":
            self.moves = [self.x, self.y + 1]
         else:
            self.moves = [self.x, self.y - 1]

      elif self.type == "knight":
         potential_moves = [
            (self.x + 1, self.y + 2),
            (self.x + 2, self.y + 1),
            (self.x + 2, self.y - 1),
            (self.x + 1, self.y - 2),
            (self.x - 1, self.y - 2),
            (self.x - 2, self.y - 1),
            (self.x - 2, self.y + 1),
            (self.x - 1, self.y + 2)
         ]
         #checking if the move leaves the board
         for move in potential_moves:
            if move[0] < 0 or move[0] > 7 or move[1] < 0 or move[1] > 7:
               continue
            self.moves.append(move)

      elif self.type == "bishop":
         for i in range(1, 8):
            potential_moves.append((self.x + i, self.y + i))
            potential_moves.append((self.x + i, self.y - i))
            potential_moves.append((self.x - i, self.y + i))
            potential_moves.append((self.x - i, self.y - i))
         #checking if the move leaves the board
         for move in potential_moves:
            if move[0] < 0 or move[0] > 7 or move[1] < 0 or move[1] > 7:
               continue
            self.moves.append(move)

      elif self.type == "rook":
         for i in range(1, 8):
            potential_moves.append((self.x + i, self.y))
            potential_moves.append((self.x - i, self.y))
            potential_moves.append((self.x, self.y + i))
            potential_moves.append((self.x, self.y - i))
         #checking if the move leaves the board
         for move in potential_moves:
            if move[0] < 0 or move[0] > 7 or move[1] < 0 or move[1] > 7:
               continue
            self.moves.append(move)

      elif self.type == "queen":
         for i in range(1, 8):
            potential_moves.append((self.x + i, self.y + i))
            potential_moves.append((self.x + i, self.y - i))
            potential_moves.append((self.x - i, self.y + i))
            potential_moves.append((self.x - i, self.y - i))
            potential_moves.append((self.x + i, self.y))
            potential_moves.append((self.x - i, self.y))
            potential_moves.append((self.x, self.y + i))
            potential_moves.append((self.x, self.y - i))
         #checking if the move leaves the board
         for move in potential_moves:
            if move[0] < 0 or move[0] > 7 or move[1] < 0 or move[1] > 7:
               continue
            self.moves.append(move)

      elif self.type == "king":
         potential_moves = [
            (self.x + 1, self.y + 1),
            (self.x + 1, self.y),
            (self.x + 1, self.y - 1),
            (self.x, self.y + 1),
            (self.x, self.y - 1),
            (self.x - 1, self.y + 1),
            (self.x - 1, self.y),
            (self.x - 1, self.y - 1)
         ]
         #checking if the move leaves the board
         for move in potential_moves:
            if move[0] < 0 or move[0] > 7 or move[1] < 0 or move[1] > 7:
               continue
            self.moves.append(move)

why did only some of it get seen as a code snippet heeelllllllpp

You have to wrap it in triple backticks.

...

Raw:

```python
...
```

cc: @UMARismyname @MattDESTROYER

3 Likes

Hey there!
I’d love to help out, in fact I’m building my own chess bot at the moment! Are you experiencing any errors? Are you wondering about any faulty logic? If you could share some more info, that’d be great!

3 Likes

So, they are wondering about the structure of the code and what to do next. (I’m not sure if they are trying to make an algorithm to play chess or just making a chess game.)
It looks like they now need to check for illegal moves where king is endangered, and implement special moves.

(@RedCoder for your python algorithms, I can convert them to fast Cython if you need performance)

to clarify, i’m trying to make a bot. it doesn’t have to beat stockfish or anything though

I’ll try give you some instructions which you can either follow or not, is just that when I did the chess I went through that way.

First of, you are using tuples to represent positions, which is fine. However, it’s like a common thing to use a 2D array to represent the board. Each cell can either hold a piece object or be None to indicate an empty square.

Second one, in your current code, each piece calculates its potential moves without considering other pieces on the board. For example, a bishop’s movement is blocked by other pieces, but this isn’t accounted for in your code. You need to incorporate these kind of things.

And since I told about the bishop’s movement, another thing that you have to do is to validate the moves. Each piece should validate its moves based on the current state of the board. This includes checking if a move would put its own king in check.

I’d suggest you start to enlist those things that make the rules of the board and implement each of them step-by-step.

2 Likes

After that you start to deal with the movimentation of each piece and their complexity (like the pawn, that can move in various different ways), the board initialization, user interface, things like that.

Thank you, I’ll start doing these things

Ok, so I started over from scratch and I have this so far. I still haven’t put in check or checkmate, and I’m trying to figure out how to check for either and have the legal_moves function respond to it.

class Board:
   def __init__(self):
      self.grid = [
         ["r", "n", "b", "q", "k", "b", "n", "r"],
         ["p", "p", "p", "p", "p", "p", "p", "p"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["P", "P", "P", "P", "P", "P", "P", "P"],
         ["R", "N", "B", "Q", "K", "B", "N", "R"],
      ]
   
   def print_board(self):
      for row in self.grid:
         print(' '.join(row))
         
   def piece_at_square(self, row, col, color):
      if self.grid[row][col] == '_':
         return False
         
      if color == "white":
         if self.grid[row][col].isupper():  # Block pieces of the same color
            return True
         else:  # Block past pieces of different colors
            return False
            
      elif color == "black":
         if self.grid[row][col].islower():  # Block pieces of the same color
            return True
         else:  # Block past pieces of different colors
            return False    
      
   def legal_moves(self, row, col, piece, color):
      legal_moves = [[0] * 8 for i in range(8)]
      if color == 'white':
         
         if piece == 'pawn':
            if not self.piece_at_square(row - 1, col, None):
               legal_moves[row - 1][col] = 1 
            if row == 6 and not self.piece_at_square(row - 2, col, None):
               legal_moves[row - 2][col] = 1
            if col > 0 and self.piece_at_square(row - 1, col - 1, 'black'):
               legal_moves[row - 1][col - 1] = 1
            if col < 7 and self.piece_at_square(row - 1, col + 1, 'black'):
               legal_moves[row - 1][col + 1] = 1

         if piece == 'rook':
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
   
         if piece == 'knight':
            if row > 1 and col > 0 and not self.piece_at_square(row - 2, col - 1, "white"):
               legal_moves[row - 2][col - 1] = 1
            if row > 1 and col < 7 and not self.piece_at_square(row - 2, col + 1, "white"):
               legal_moves[row - 2][col + 1] = 1
            if row < 6 and col > 0 and not self.piece_at_square(row + 2, col - 1, "white"):
               legal_moves[row + 2][col - 1] = 1
            if row < 6 and col < 7 and not self.piece_at_square(row + 2, col + 1, "white"):
               legal_moves[row + 2][col + 1] = 1
            if row > 0 and col > 1 and not self.piece_at_square(row - 1, col - 2, "white"):
               legal_moves[row - 1][col - 2] = 1
            if row > 0 and col < 6 and not self.piece_at_square(row - 1, col + 2, "white"):
               legal_moves[row - 1][col + 2] = 1
            if row < 7 and col > 1 and not self.piece_at_square(row + 1, col - 2, "white"):
               legal_moves[row + 1][col - 2] = 1
            if row < 7 and col < 6 and not self.piece_at_square(row + 1, col + 2, "white"):
               legal_moves[row + 1][col + 2] = 1
               
         if piece == 'bishop':
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == 'queen':
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == 'king':
            if row > 0 and col > 0 and not self.piece_at_square(row - 1, col - 1, "white"):
               legal_moves[row - 1][col - 1] = 1
            if row > 0 and not self.piece_at_square(row - 1, col, "white"):
               legal_moves[row - 1][col] = 1
            if row > 0 and col < 7 and not self.piece_at_square(row - 1, col + 1, "white"):
               legal_moves[row - 1][col + 1] = 1
            if col > 0 and not self.piece_at_square(row, col - 1, "white"):
               legal_moves[row][col - 1] = 1
            if col < 7 and not self.piece_at_square(row, col + 1, "white"):
               legal_moves[row][col + 1] = 1
            if row < 7 and col > 0 and not self.piece_at_square(row + 1, col - 1, "white"):
               legal_moves[row + 1][col - 1] = 1
            if row < 7 and not self.piece_at_square(row + 1, col, "white"):
               legal_moves[row + 1][col] = 1
            if row < 7 and col < 7 and not self.piece_at_square(row + 1, col + 1, "white"):
               legal_moves[row + 1][col + 1] = 1

      if color == "black":
         
         if piece == "pawn":
            if not self.piece_at_square(row + 1, col, None):
               legal_moves[row + 1][col] = 1
            if row == 1 and not self.piece_at_square(row + 2, col, None):
               legal_moves[row + 2][col] = 1
            if col > 0 and self.piece_at_square(row + 1, col - 1, "white"):
               legal_moves[row + 1][col - 1] = 1
            if col < 7 and self.piece_at_square(row + 1, col + 1, "white"):
               legal_moves[row + 1][col + 1] = 1

         if piece == "rook":
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1

         if piece == "knight":
            if row > 1 and col > 0 and not self.piece_at_square(row - 2, col - 1, "black"):
               legal_moves[row - 2][col - 1] = 1
            if row > 1 and col < 7 and not self.piece_at_square(row - 2, col + 1, "black"):
               legal_moves[row - 2][col + 1] = 1
            if row < 6 and col > 0 and not self.piece_at_square(row + 2, col - 1, "black"):
               legal_moves[row + 2][col - 1] = 1
            if row < 6 and col < 7 and not self.piece_at_square(row + 2, col + 1, "black"):
               legal_moves[row + 2][col + 1] = 1
            if row > 0 and col > 1 and not self.piece_at_square(row - 1, col - 2, "black"):
               legal_moves[row - 1][col - 2] = 1
            if row > 0 and col < 6 and not self.piece_at_square(row - 1, col + 2, "black"):
               legal_moves[row - 1][col + 2] = 1
            if row < 7 and col > 1 and not self.piece_at_square(row + 1, col - 2, "black"):
               legal_moves[row + 1][col - 2] = 1
            if row < 7 and col < 6 and not self.piece_at_square(row + 1, col + 2, "black"):
               legal_moves[row + 1][col + 2] = 1

         if piece == "bishop":
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == "queen":
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == "king":
            if row > 0 and col > 0 and not self.piece_at_square(row - 1, col - 1, "black"):
               legal_moves[row - 1][col - 1] = 1
            if row > 0 and not self.piece_at_square(row - 1, col, "black"):
               legal_moves[row - 1][col] = 1
            if row > 0 and col < 7 and not self.piece_at_square(row - 1, col + 1, "black"):
               legal_moves[row - 1][col + 1] = 1
            if col > 0 and not self.piece_at_square(row, col - 1, "black"):
               legal_moves[row][col - 1] = 1
            if col < 7 and not self.piece_at_square(row, col + 1, "black"):
               legal_moves[row][col + 1] = 1
            if row < 7 and col > 0 and not self.piece_at_square(row + 1, col - 1, "black"):
               legal_moves[row + 1][col - 1] = 1
            if row < 7 and not self.piece_at_square(row + 1, col, "black"):
               legal_moves[row + 1][col] = 1
            if row < 7 and col < 7 and not self.piece_at_square(row + 1, col + 1, "black"):
               legal_moves[row + 1][col + 1] = 1

      return legal_moves

It looks like you are on the right track.

What I would recommend is to create a Move class that encapsulates information about a move, including its start and end, if it is special or normal, and what piece is being moved.
Then, create a Board method that applies a move and returns a new board. (Instead of returning a board, undo functionality is an alternative.)
Then, create a Board method that determines if a given side’s king is currently in check.
Then, have Board.legal_moves() return a list of moves filtered such that the color’s king is not in check when the move is applied.

1 Like

how is this? i could probably optimize it a lot, but would it work?

class Board:
   def __init__(self):
      self.grid = [
         ["r", "n", "b", "q", "k", "b", "n", "r"],
         ["p", "p", "p", "p", "p", "p", "p", "p"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["_", "_", "_", "_", "_", "_", "_", "_"],
         ["P", "P", "P", "P", "P", "P", "P", "P"],
         ["R", "N", "B", "Q", "K", "B", "N", "R"],
      ]
   
   def print_board(self):
      for row in self.grid:
         print(' '.join(row))
         
   def piece_at_square(self, row, col, color):
      if self.grid[row][col] == '_':
         return False
         
      if color == "white":
         return self.grid[row][col].isupper()  # Block pieces of the same color
            
      elif color == "black":
         return self.grid[row][col].islower()  # Block pieces of the same color  

   def king_pos(self, color):
      for row in range(8):
         for col in range(8):
            if (self.grid[row][col] == "K" and color == "white" or 
                self.grid[row][col] == "k" and color == "black"):
               return row, col
      return "this is only so it can't return None, this will NEVER be returned (if i'm right(i'm probably not))"

   def is_move_legal(self, start_row, start_col, end_row, end_col, color):
      self.grid[start_row][start_col]
      self.grid[end_row][end_col]
      #use legal_moves
      return self.possible_moves(self, start_row, start_col, color)[end_row][end_col] == "1"
         
   def is_attacked(self, row, col, color):
      opponent = "black" if color == "white" else "white"
      for r in range(8):
         for c in range(8):
            if self.piece_at_square(r, c, opponent) and self.is_move_legal(row, col, r, c, color):
                  return True
      
   def in_check(self, color):
      king_row, king_col = self.king_pos(color)
      if color == "white":
         for i in range(8):
            for j in range(8):
               if (self.grid[i][j] == "p" or 
                   self.grid[i][j] == "n" or 
                   self.grid[i][j] == "b" or 
                   self.grid[i][j] == "r" or 
                   self.grid[i][j] == "q") and self.is_attacked(i, j, color):
                  return True
         return False
      else:  
         for i in range(8):
            for j in range(8):
               if (self.grid[i][j] == "P" or 
                   self.grid[i][j] == "N" or 
                   self.grid[i][j] == "B" or 
                   self.grid[i][j] == "R" or 
                   self.grid[i][j] == "Q") and self.is_attacked(i, j, color):
                  return True
         return False
         
   def possible_moves(self, row, col, piece, color):
      legal_moves = [[0] * 8 for i in range(8)]
      if color == 'white':
         
         if piece == 'pawn':
            if not self.piece_at_square(row - 1, col, None):
               legal_moves[row - 1][col] = 1 
            if row == 6 and not self.piece_at_square(row - 2, col, None):
               legal_moves[row - 2][col] = 1
            if col > 0 and self.piece_at_square(row - 1, col - 1, 'black'):
               legal_moves[row - 1][col - 1] = 1
            if col < 7 and self.piece_at_square(row - 1, col + 1, 'black'):
               legal_moves[row - 1][col + 1] = 1

         if piece == 'rook':
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
   
         if piece == 'knight':
            if row > 1 and col > 0 and not self.piece_at_square(row - 2, col - 1, "white"):
               legal_moves[row - 2][col - 1] = 1
            if row > 1 and col < 7 and not self.piece_at_square(row - 2, col + 1, "white"):
               legal_moves[row - 2][col + 1] = 1
            if row < 6 and col > 0 and not self.piece_at_square(row + 2, col - 1, "white"):
               legal_moves[row + 2][col - 1] = 1
            if row < 6 and col < 7 and not self.piece_at_square(row + 2, col + 1, "white"):
               legal_moves[row + 2][col + 1] = 1
            if row > 0 and col > 1 and not self.piece_at_square(row - 1, col - 2, "white"):
               legal_moves[row - 1][col - 2] = 1
            if row > 0 and col < 6 and not self.piece_at_square(row - 1, col + 2, "white"):
               legal_moves[row - 1][col + 2] = 1
            if row < 7 and col > 1 and not self.piece_at_square(row + 1, col - 2, "white"):
               legal_moves[row + 1][col - 2] = 1
            if row < 7 and col < 6 and not self.piece_at_square(row + 1, col + 2, "white"):
               legal_moves[row + 1][col + 2] = 1
               
         if piece == 'bishop':
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == 'queen':
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "white"):
                  break
               if self.piece_at_square(i, col, "black"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "white"):
                  break
               if self.piece_at_square(row, i, "black"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == 'king':
            if row > 0 and col > 0 and not self.piece_at_square(row - 1, col - 1, "white"):
               legal_moves[row - 1][col - 1] = 1
            if row > 0 and not self.piece_at_square(row - 1, col, "white"):
               legal_moves[row - 1][col] = 1
            if row > 0 and col < 7 and not self.piece_at_square(row - 1, col + 1, "white"):
               legal_moves[row - 1][col + 1] = 1
            if col > 0 and not self.piece_at_square(row, col - 1, "white"):
               legal_moves[row][col - 1] = 1
            if col < 7 and not self.piece_at_square(row, col + 1, "white"):
               legal_moves[row][col + 1] = 1
            if row < 7 and col > 0 and not self.piece_at_square(row + 1, col - 1, "white"):
               legal_moves[row + 1][col - 1] = 1
            if row < 7 and not self.piece_at_square(row + 1, col, "white"):
               legal_moves[row + 1][col] = 1
            if row < 7 and col < 7 and not self.piece_at_square(row + 1, col + 1, "white"):
               legal_moves[row + 1][col + 1] = 1

      if color == "black":
         
         if piece == "pawn":
            if not self.piece_at_square(row + 1, col, None):
               legal_moves[row + 1][col] = 1
            if row == 1 and not self.piece_at_square(row + 2, col, None):
               legal_moves[row + 2][col] = 1
            if col > 0 and self.piece_at_square(row + 1, col - 1, "white"):
               legal_moves[row + 1][col - 1] = 1
            if col < 7 and self.piece_at_square(row + 1, col + 1, "white"):
               legal_moves[row + 1][col + 1] = 1

         if piece == "rook":
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1

         if piece == "knight":
            if row > 1 and col > 0 and not self.piece_at_square(row - 2, col - 1, "black"):
               legal_moves[row - 2][col - 1] = 1
            if row > 1 and col < 7 and not self.piece_at_square(row - 2, col + 1, "black"):
               legal_moves[row - 2][col + 1] = 1
            if row < 6 and col > 0 and not self.piece_at_square(row + 2, col - 1, "black"):
               legal_moves[row + 2][col - 1] = 1
            if row < 6 and col < 7 and not self.piece_at_square(row + 2, col + 1, "black"):
               legal_moves[row + 2][col + 1] = 1
            if row > 0 and col > 1 and not self.piece_at_square(row - 1, col - 2, "black"):
               legal_moves[row - 1][col - 2] = 1
            if row > 0 and col < 6 and not self.piece_at_square(row - 1, col + 2, "black"):
               legal_moves[row - 1][col + 2] = 1
            if row < 7 and col > 1 and not self.piece_at_square(row + 1, col - 2, "black"):
               legal_moves[row + 1][col - 2] = 1
            if row < 7 and col < 6 and not self.piece_at_square(row + 1, col + 2, "black"):
               legal_moves[row + 1][col + 2] = 1

         if piece == "bishop":
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == "queen":
            for i in range(row - 1, -1, -1):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(row + 1, 8):
               if self.piece_at_square(i, col, "black"):
                  break
               if self.piece_at_square(i, col, "white"):
                  legal_moves[i][col] = 1
                  break
               legal_moves[i][col] = 1
            for i in range(col - 1, -1, -1):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(col + 1, 8):
               if self.piece_at_square(row, i, "black"):
                  break
               if self.piece_at_square(row, i, "white"):
                  legal_moves[row][i] = 1
                  break
               legal_moves[row][i] = 1
            for i in range(1, 8):
               if row - i < 0 or col - i < 0:
                  break
               if self.piece_at_square(row - i, col - i, "black"):
                  break
               if self.piece_at_square(row - i, col - i, "white"):
                  legal_moves[row - i][col - i] = 1
                  break
               legal_moves[row - i][col - i] = 1
            for i in range(8):
               if row - i < 0 or col + i > 7:
                  break
               if self.piece_at_square(row - i, col + i, "black"):
                  break
               if self.piece_at_square(row - i, col + i, "white"):
                  legal_moves[row - i][col + i] = 1
                  break
               legal_moves[row - i][col + i] = 1
            for i in range(1, 8):
               if row + i > 7 or col - i < 0:
                  break
               if self.piece_at_square(row + i, col - i, "black"):
                  break
               if self.piece_at_square(row + i, col - i, "white"):
                  legal_moves[row + i][col - i] = 1
                  break
               legal_moves[row + i][col - i] = 1
            for i in range(8):
               if row + i > 7 or col + i > 7:
                  break
               if self.piece_at_square(row + i, col + i, "black"):
                  break
               if self.piece_at_square(row + i, col + i, "white"):
                  legal_moves[row + i][col + i] = 1
                  break
               legal_moves[row + i][col + i] = 1
            legal_moves[row][col] = 0

         if piece == "king":
            if row > 0 and col > 0 and not self.piece_at_square(row - 1, col - 1, "black"):
               legal_moves[row - 1][col - 1] = 1
            if row > 0 and not self.piece_at_square(row - 1, col, "black"):
               legal_moves[row - 1][col] = 1
            if row > 0 and col < 7 and not self.piece_at_square(row - 1, col + 1, "black"):
               legal_moves[row - 1][col + 1] = 1
            if col > 0 and not self.piece_at_square(row, col - 1, "black"):
               legal_moves[row][col - 1] = 1
            if col < 7 and not self.piece_at_square(row, col + 1, "black"):
               legal_moves[row][col + 1] = 1
            if row < 7 and col > 0 and not self.piece_at_square(row + 1, col - 1, "black"):
               legal_moves[row + 1][col - 1] = 1
            if row < 7 and not self.piece_at_square(row + 1, col, "black"):
               legal_moves[row + 1][col] = 1
            if row < 7 and col < 7 and not self.piece_at_square(row + 1, col + 1, "black"):
               legal_moves[row + 1][col + 1] = 1

      return legal_moves

class move:
   def __init__(self, start_row, start_col, end_row, end_col):
      self.start_row = start_row
      self.start_col = start_col
      self.end_row = end_row
      self.end_col = end_col

   def make_move(self, board, piece, color):
      # Check if legal move
      if not board.is_legal_move(self.start_row, self.start_col, self.end_row, self.end_col, piece, color):
         print("Invalid move")
         pass
      # Make move
      board.board[self.end_row][self.end_col] = board.board[self.start_row, self.start_col]
      board.board[self.start_row][self.start_col] = "_"

The design looks good so far.
A few things though:

There is too much code duplication.
You should have just one piece of code for both sides.
I’d also recommend making these functions to reduce code duplication:

Board.all_pieces()
opposite_color(color)

Using classes instead of raw string characters as pieces is more clear but not completely necessary:

class Piece:
    def __init__(self, color, piece):
        self.color = color
        self.piece = piece

Consider learning about Enum so that you don’t have to use raw strings like “white”.

The next, and harder part, of creating chess is implementing the special moves:

  • castling
  • en passant
  • promotion (including underpromotion)

Then, implement checkmate and stalemate, which is easy: just see if there are no legal moves and if king is in check.
There are harder to implement rules such as three-fold repetition, 50 move rule.
For the AI part, you may want to consult a guide for the algorithm.
If you want to go further, implement PGN, undoing, etc.

3 Likes