Skip to content

list(board.pieces(chess.KING, chess.BLACK))[0] IndexError: list index out of range #1156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MattisIsEpic opened this issue May 21, 2025 · 0 comments

Comments

@MattisIsEpic
Copy link

Hello. I'm trying to make a chess engine using the chess library, however during testing this error occurred:

Traceback (most recent call last):
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 163, in <module>
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 159, in <module>
    move = search.minimax(board, 20, -1, -1, True, chess.BLACK)[1]
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 92, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 124, in minimax
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 111, in minimax
    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 79, in minimax
    return self.Quiescence(board, side, 4, -1, 1)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 47, in Quiescence
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 37, in Quiescence
    current = self.Quiescence(new_board, side, depth-1, alpha, beta)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 47, in Quiescence
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 37, in Quiescence
    current = self.Quiescence(new_board, side, depth-1, alpha, beta)
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 47, in Quiescence
    raise e
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 32, in Quiescence
    attack_outcome = {list(board.legal_moves)[0]: Evaluate(board, side)}
                                                  ~~~~~~~~^^^^^^^^^^^^^
  File "c:\Users\Admin\Desktop\MyFish 1.0\search.py", line 6, in Evaluate
    friendly = EvaluateSide(board, side)
  File "c:\Users\Admin\Desktop\MyFish 1.0\eval.py", line 93, in EvaluateSide
    king_location = list(board.pieces(chess.KING, side))[0]
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range

so then i used a try and except statement to findout what color the "side" argument is, and it is black like it should be.

Here's the search.py file:

from eval import EvaluateSide
import random
import chess

def Evaluate(board: chess.Board, side: chess.WHITE | chess.BLACK):
    friendly = EvaluateSide(board, side)
    enemy = EvaluateSide(board, not side)
    return ((friendly/(friendly+enemy))*2)-1


class Search:
    def __init__(self):
        self.pv_table = {}
        self.nodes = 0
    
    def Quiescence(self, board: chess.Board, side, depth, alpha = -1, beta = 1):
        if depth == 0:
            return Evaluate(board, side)
        try:
            attacks = [list(board.legal_moves)[0]]
            for move in list(board.legal_moves):
                if move.to_square in list(board.attacks(move.from_square)):
                    attacks.append(move)

            if len(attacks) == 0:
                return Evaluate(board, side)
            attack_outcome = {list(board.legal_moves)[0]: Evaluate(board, side)}
            for attack in attacks:
                self.nodes += 1
                new_board = board.copy()
                new_board.push(attack)
                current = self.Quiescence(new_board, side, depth-1, alpha, beta)
                attack_outcome[attack] = current
                if (board.turn == side):
                    alpha = max(current, alpha)
                else:
                    beta = min(current, beta)
            attacks.sort(key=lambda move: attack_outcome[move], reverse=(board.turn == side))
            return attack_outcome[attacks[0]]
        except Exception as e:
            if not board.is_game_over():
                raise e
            return Evaluate(board, side)
        
    def MoveOrdering(self, board: chess.Board):
        move_ranking = {}
        moves = list(board.legal_moves)
        key = (int(board.occupied)*2)+int(not board.turn)
        
        hit = None
        if key in self.pv_table and self.pv_table[key] in moves:
            try:
                hit = self.pv_table[key]
                moves.remove(moves.index(hit))
            except:
                hit = None

        current_board = board.copy()
        for move in moves:
            board = current_board.copy()
            board.push(move)
            score = Evaluate(board, board.turn)
            move_ranking[move] = score

        moves.sort(key=lambda move: move_ranking[move], reverse=False)

        if hit:
            moves.insert(0, hit)

        return moves
    
    def minimax(self, board: chess.Board, depth, alpha = -1, beta = 1, maximizingPlayer = False, side = chess.WHITE):
        if depth == 0:
            return self.Quiescence(board, side, 4, -1, 1)
        
        moves = self.MoveOrdering(board)
        
        try:
            if maximizingPlayer:
                key = (int(board.occupied)*2)+int(not board.turn)
                maxMove = moves[0]
                maxEval = -1
                for move in moves:
                    self.nodes += 1
                    new_board = board.copy()
                    new_board.push(move)
                    evaluation = self.minimax(new_board, depth-1, alpha, beta, False, side)
                    if type(evaluation) != float:
                        evaluation = evaluation[0]
                    if evaluation > maxEval:
                        maxEval = evaluation
                        maxMove = move
                    alpha = max(alpha, evaluation)
                    if beta <= alpha:
                        break
                self.pv_table[key] = maxMove
                return [maxEval, maxMove]
            else:
                key = (int(board.occupied)*2)+int(not board.turn)
                minMove = moves[0]
                minEval = 1
                for move in moves:
                    self.nodes += 1
                    new_board = board.copy()
                    new_board.push(move)
                    evaluation = self.minimax(new_board, depth-1, alpha, beta, True, side)
                    if type(evaluation) != float:
                        evaluation = evaluation[0]
                    if evaluation < minEval:
                        minEval = evaluation
                        minMove = move
                    beta = min(beta, evaluation)
                    if beta <= alpha:
                        break
                self.pv_table[key] = minMove
                return [minEval, minMove]
        except Exception as e:
            if not board.is_game_over():
                raise e
            return self.Quiescence(board, side, 4, -1, 1)

def Visualize(board: chess.Board):
    black = ["KQRBNP", "♔♕♖♗♘♙"]
    white = ["KQRBNP", "♚♛♜♝♞♟"]

    lines = []
    for i in range(8):
        lines.append([".", ".", ".", ".", ".", ".", ".", "."])#([".", ".", ".", ".", ".", ".", ".", "."])
    
    pieces = []
    for piece in [chess.PAWN, chess.KNIGHT, chess.BISHOP, chess.ROOK, chess.QUEEN, chess.KING]:
        pieces = pieces + list(board.pieces(piece, chess.BLACK))
        pieces = pieces + list(board.pieces(piece, chess.WHITE))
    
    for piece in pieces:
        if board.color_at(piece) == chess.BLACK:
            lines[int(chess.square_name(piece)[1])-1]["abcdefgh".index(chess.square_name(piece)[0])] = black[1][black[0].index(board.piece_at(piece).symbol().upper())]
        if board.color_at(piece) == chess.WHITE:
            lines[int(chess.square_name(piece)[1])-1]["abcdefgh".index(chess.square_name(piece)[0])] = white[1][white[0].index(board.piece_at(piece).symbol().upper())]
    string = ""
    for i in range(8):
        string = string+str(9-(i+1))+". "+(" ".join(lines[7-i]))+"\n"
    string = string + "   " + (" ".join(list("ABCDEFGH")))
    return string

board = chess.Board()
search = Search()

while True:
    try:
        print(Visualize(board))
        board.push_uci(input())
        print(Visualize(board))
        move = search.minimax(board, 20, -1, -1, True, chess.BLACK)[1]
        board.push(move)
    except Exception as e:
        print(board.fen())
        raise e

and here's the eval.py file (with one unprofessional comment removed):

import chess
import math

MG_PIECE_VALUES = {
    chess.PAWN: 82,
    chess.KNIGHT: 337,
    chess.BISHOP: 365,
    chess.ROOK: 477,
    chess.QUEEN: 1025,
    chess.KING: 24000,
}

EG_PIECE_VALUES = {
    chess.PAWN: 94,
    chess.KNIGHT: 281,
    chess.BISHOP: 297,
    chess.ROOK: 512,
    chess.QUEEN: 936,
    chess.KING: 24000,
}

Attack_Table = {
    1: 0,
    2: 50,
    3: 75,
    4: 88,
    5: 94,
    6: 97,
    7: 99,
}

def PieceEvaluation(board: chess.Board, position: int, type: any, side: chess.WHITE | chess.BLACK):
    if type == chess.PAWN:
        if side == chess.WHITE:
            if position == 0:
                position = 1
            position = math.ceil(position/8)
        else:
            position = 63-position
            if position == 0:
                position = 1
            position = math.ceil(position/8)
        return 1+(position/32)
    return 1

def EvaluateSide(board: chess.Board, side: chess.WHITE | chess.BLACK):
    # Mate-at-a-Glance detection

    board.turn = not side
    for move in list(board.legal_moves):
        board.push(move)
        if board.is_checkmate():
            return 0
        board.pop()

    # Compute Safe-Entropy / Mobility

    attacked = {}
    for attacker in chess.SquareSet(board.occupied_co[not side]):
        for attack in board.attacks(attacker):
            attacked[attack] = 0

    board.turn = side
    moves = 0
    Safe = {}
    for move in list(board.legal_moves):
        if move.from_square in Safe or board.attackers(not side, move.from_square) == chess.SquareSet():
            Safe[move.from_square] = 1
            moves += 1

    controlled = {}
    for attacker in chess.SquareSet(board.occupied_co[side]):
        if attacker in Safe:
            for attack in board.attacks(attacker):
                if not attack in attacked:
                    controlled[attack] = 1

    entropy = 140*math.log((len(list(controlled.keys()))*moves)+1)

    # Compute Material (+ entropy consideration)

    stage = (len(list(chess.SquareSet(board.occupied_co[side])))+len(list(chess.SquareSet(board.occupied_co[not side]))))/32
    material = 0
    for piece in chess.SquareSet(board.occupied_co[side]):
        piece_type = board.piece_type_at(piece)
        MG_value = MG_PIECE_VALUES[piece_type]
        EG_value = EG_PIECE_VALUES[piece_type]
        material += ((MG_value * stage) + (EG_value * (1 - stage)))*PieceEvaluation(board, piece, board.piece_type_at(piece), board.color_at(piece))

    # Compute king-safety

    attackers = 0
    king_location = list(board.pieces(chess.KING, side))[0]
    for offset in [-9, -8, -7, -1, 1, 7, 8, 9]:
        try:
            square = king_location - offset
            if chess.square_distance(king_location, square) == 1:
                attackers += len(list(board.attackers(not side, square)))
        except:
            pass

    attackers = max(1, attackers)
    attackers = min(7, attackers)

    king_safety = 1-(Attack_Table[attackers]/100)

    # Compute Final Score

    score = (material+entropy)*king_safety

    return score

this error occured on python 3.13.3 with the latest "chess" library update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant