Why is my chess engine playing sub optimal moves

Question:
Why is my chess engine playing sub optimal moves
Repl link:
https://replit.com/@jcsan/Tortoi
Full code below:

import chess
import time
import chess.polyglot

board = chess.Board()
book = chess.polyglot.open_reader("baron30.bin")
material = {
  chess.PAWN:10.0,
	chess.KNIGHT:32.0,
	chess.BISHOP:33.3,
	chess.ROOK:56.5,
	chess.QUEEN:95.5,
  chess.KING:200.0
	
}
scoring = {
 'Pawn': [
  0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 2, 3, 3, 2, 1, 1, 0, 0,
  0, 2, 2, 0, 0, 0, 0, 0, 0, -2, -2, 0, 0, 0, 1, -1, -2, 0, 0, -2, -1, 1, 1, 2,
  2, -2, -2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0
 ],
 'Knight': [
  -5, -4, -3, -3, -3, -3, -4, -5, -4, -2, 0, 0, 0, 0, -2, -4, -3, 0, 1, 1.5,
  1.5, 1, 0, -3, -3, 0.5, 1.5, 2, 2, 1.5, 0.5, -3, -3, 0.5, 1.5, 2, 2, 1.5,
  0.5, -3, -3, 0, 1, 1.5, 1.5, 1, 0, -3, -4, -2, 0, 0.5, 0.5, 0, -2, -4, -5,
  -4, -3, -3, -3, -3, -4, -5
 ],
 'Bishop': [
  -2,
  -1,
  -1,
  -1,
  -1,
  -1,
  -1,
  -2,
  -1,
  0.25,
  0,
  0,
  0,
  0,
  0.25,
  -1,
  -1,
  0,
  1,
  1,
  1,
  1,
  0,
  -1,
  -1,
  0,
  1,
  1.5,
  1.5,
  1,
  0,
  -1,
  -1,
  0,
  1,
  1.5,
  1.5,
  1,
  0,
  -1,
  -1,
  0,
  1,
  1,
  1,
  1,
  0,
  -1,
  -1,
  0.25,
  0,
  0,
  0,
  0,
  0.25,
  -1,
  -2,
  -1,
  -1,
  -1,
  -1,
  -1,
  -1,
  -2,
 ],
 'Rook': [
  0, 0, 0, 0, 0, 0, 0, 0, 0.5, 1, 1, 1, 1, 1, 1, 0.5, -0.5, 0, 0, 0, 0, 0, 0,
  -0.5, -0.5, 0, 0, 0, 0, 0, 0, -0.5, -0.5, 0, 0, 0, 0, 0, 0, -0.5, -0.5, 0, 0,
  0, 0, 0, 0, -0.5, -0.5, 1, 1, 1, 1, 1, 1, -0.5, 0, 0, 0, 0.5, 0.5, 0, 0, 0
 ],
 'Queen': [
  -2, -1, -1, -0.5, -0.5, -1, -1, -2, -1, 0, 0.5, 0, 0, 0.5, 0, -1, -1, 0.5,
  0.5, 0.5, 0.5, 0.5, 0.5, -1, -0.5, 0, 0.5, 0.5, 0.5, 0.5, 0, -0.5, 0, 0, 0.5,
  0.5, 0.5, 0, 0, 0, -0.5, 0, 0.5, 0.5, 0.5, 0.5, 0, -0.5, -1, 0.5, 0.5, 0.5,
  0.5, 0.5, 0.5, -1, -2, -1, -1, -0.5, -0.5, -1, -1, -2
 ],
 'King': [
  -3, -4, -4, -5, -5, -4, -4, -3, -3, -4, -4, -5, -5, -4, -4, -3, -3, -4, -4,
  -5, -5, -4, -4, -3, -3, -4, -4, -5, -5, -4, -4, -3, -2, -3, -3, -4, -4, -3,
  -3, -2, -1, -2, -2, -2, -2, -2, -2, -1, 2, 2, 0, 0, 0, 0, 2, 2, 2, 3, 1, 0,
  0, 1, 3, 2
 ],
}

pawn_table = scoring['Pawn']
knight_table = scoring['Knight']
bishop_table = scoring['Bishop']
rook_table = scoring['Rook']
queen_table = scoring['Queen']
king_table = scoring['King']


def evaluate(board):
	score = 0.00
	pst_score = 0.00
	pieces = board.piece_map()
	for square, piece in pieces.items():
		if piece.color:
			score += material[piece.piece_type]
			if piece.piece_type == chess.PAWN:
				pst_score += pawn_table[square]
			elif piece.piece_type == chess.KNIGHT:
				pst_score += knight_table[square]
			elif piece.piece_type == chess.BISHOP:
				pst_score += bishop_table[square]
			elif piece.piece_type == chess.ROOK:
				pst_score += rook_table[square]
			elif piece.piece_type == chess.QUEEN:
				pst_score += queen_table[square]
			elif piece.piece_type == chess.KING:
				pst_score += king_table[square]
		else:
			score -= material[piece.piece_type]
			if piece.piece_type == chess.PAWN:
				pst_score -= pawn_table[chess.square_mirror(square)]
			elif piece.piece_type == chess.KNIGHT:
				pst_score -= knight_table[chess.square_mirror(square)]
			elif piece.piece_type == chess.BISHOP:
				pst_score -= bishop_table[chess.square_mirror(square)]
			elif piece.piece_type == chess.ROOK:
				pst_score -= rook_table[chess.square_mirror(square)]
			elif piece.piece_type == chess.QUEEN:
				pst_score -= queen_table[chess.square_mirror(square)]
			elif piece.piece_type == chess.KING:
				pst_score -= king_table[chess.square_mirror(square)]
	return score + pst_score


def highest_value(BOARD, depth=15, max_time=10):
	start_time = time.time()
	best_move = None
	if BOARD.turn == chess.WHITE:
		best_value = -float("inf")
	else:
		best_value = float("inf")
	for d in range(1, depth + 1):
		if time.time() - start_time > max_time:
			break
		for move in BOARD.legal_moves:
			BOARD.push(move)
			value = alpha_beta_search(BOARD, d)
			BOARD.pop()
			if BOARD.turn == chess.WHITE:
				if value > best_value:
					best_value = value
					best_move = move
			else:
				if value < best_value:
					best_value = value
					best_move = move
	return best_move


def alpha_beta_search(board,
                      depth,
                      alpha=-float("inf"),
                      beta=float("inf"),
                      maximizing_player=True):
	if depth == 0 or board.is_game_over():
		return evaluate(board)
	if maximizing_player:
		value = -float("inf")
		for move in board.legal_moves:
			board.push(move)
			value = max(value, alpha_beta_search(board, depth - 1, alpha, beta, False))
			board.pop()
			alpha = max(alpha, value)
			if alpha >= beta:
				break
		return value
	else:
		value = float("inf")
		for move in board.legal_moves:
			board.push(move)
			value = min(value, alpha_beta_search(board, depth - 1, alpha, beta, True))
			board.pop()
			beta = min(beta, value)
			if alpha >= beta:
				break
		return value


while True:

  if (len(list(book.find_all(board))) != 0):
    board.push(book.weighted_choice(board).move)
    time.sleep(1)
    print(board)
    print("  ")
  else:
    best_move = highest_value(board)
    board.push(best_move)
    print(board)
    print("  ")
    if board.can_claim_draw() == True:
      print("draw")
      break

There’s a chess library?!

1 Like

There’s a library for Minecraft too, so there’s probably a library for everything…

1 Like

Shouldn’t this be higher if you want better moves?

def highest_value(BOARD, depth=15, max_time=10):

I think 10 seconds is not enought time to the engine look for the best move. And depth=15can work but if something more complex is needed it will lead to sub optimal moves.

Also look for better opening books:

“Richard Pijl has been kind enough to released The Baron 3.43 . This is almost identical to the version that played in the 2018 WCCC.”
https://www.chessprogramming.net/new-version-of-the-baron-v3-43-plus-the-barons-polyglot-opening-book/

Or you can access ChessBase.com to look for more information.

3 Likes

Yes, in the amount of time I spent experimenting with Stockfish, depth should be more than 18 (20+ preferably) and time should be maxed out at 30 seconds (Stockfish currently maxes out at 1 min tho)

3 Likes