-
-
Notifications
You must be signed in to change notification settings - Fork 556
Open
Description
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.
Metadata
Metadata
Assignees
Labels
No labels