Skip to content

Instantly share code, notes, and snippets.

@estebanthi
Last active July 11, 2023 18:42
Show Gist options
  • Save estebanthi/80c5fe48715e74fced5220f44ad43f9a to your computer and use it in GitHub Desktop.
Save estebanthi/80c5fe48715e74fced5220f44ad43f9a to your computer and use it in GitHub Desktop.
import chess
import random
import chess.svg
def random_move(board):
moves = list(board.legal_moves)
move = random.choice(moves)
return move
piece_values = {
chess.PAWN: 1,
chess.KNIGHT: 3,
chess.BISHOP: 3,
chess.ROOK: 5,
chess.QUEEN: 9,
chess.KING: 0
}
def evaluate_board(board):
score = 0
for square in chess.SQUARES:
piece = board.piece_at(square)
if piece is not None:
if piece.color == chess.WHITE:
score += piece_values[piece.piece_type]
else:
score -= piece_values[piece.piece_type]
return score
def try_evaluation_function():
board = chess.Board()
evaluation = evaluate_board(board)
print(f"Evaluation with all pieces: {evaluation}")
# remove a white pawn
board.remove_piece_at(chess.E2)
evaluation = evaluate_board(board)
print(f"Evaluation without a white pawn: {evaluation}")
# remove a black rook
board.remove_piece_at(chess.A8)
evaluation = evaluate_board(board)
print(f"Evaluation without a black rook: {evaluation}")
def best_move_using_simple_evaluation(board):
white_to_play = board.turn
best_score = -99999 if white_to_play else 99999
best_move = random_move(board)
for move in board.legal_moves:
board.push(move)
score = evaluate_board(board)
board.pop()
if score > best_score and white_to_play:
best_score = score
best_move = move
elif score < best_score and not white_to_play:
best_score = score
best_move = move
return best_move
def minimax_without_alpha_beta_pruning(board, depth, white_to_play):
if depth == 0 or board.is_game_over():
return evaluate_board(board)
if white_to_play:
best_score = -99999
for move in board.legal_moves:
board.push(move)
score = minimax_without_alpha_beta_pruning(board, depth - 1, False)
board.pop()
best_score = max(score, best_score)
return best_score
else:
best_score = 99999
for move in board.legal_moves:
board.push(move)
score = minimax_without_alpha_beta_pruning(board, depth - 1, True)
board.pop()
best_score = min(score, best_score)
return best_score
def best_move_using_minimax_without_alpha_beta_pruning(board, depth):
white_to_play = board.turn
best_score = -99999 if white_to_play else 99999
best_move = random_move(board)
for move in board.legal_moves:
board.push(move)
score = minimax_without_alpha_beta_pruning(board, depth - 1, not white_to_play)
board.pop()
if score > best_score and white_to_play:
best_score = score
best_move = move
elif score < best_score and not white_to_play:
best_score = score
best_move = move
return best_move
def minimax_with_alpha_beta_pruning(board, depth, alpha, beta, white_to_play):
if depth == 0 or board.is_game_over():
return evaluate_board(board)
if white_to_play:
best_score = -99999
for move in board.legal_moves:
board.push(move)
score = minimax_with_alpha_beta_pruning(board, depth - 1, alpha, beta, False)
board.pop()
best_score = max(score, best_score)
alpha = max(alpha, score)
if alpha >= beta:
break
return best_score
else:
best_score = 99999
for move in board.legal_moves:
board.push(move)
score = minimax_with_alpha_beta_pruning(board, depth - 1, alpha, beta, True)
board.pop()
best_score = min(score, best_score)
beta = min(beta, score)
if alpha >= beta:
break
return best_score
def best_move_using_minimax_with_alpha_beta_pruning(board, depth):
white_to_play = board.turn
best_score = -99999 if white_to_play else 99999
best_moves = []
for move in board.legal_moves:
board.push(move)
score = minimax_with_alpha_beta_pruning(board, depth - 1, -99999, 99999, not white_to_play)
board.pop()
if score >= best_score and white_to_play:
if len(best_moves) > 0 and score > best_score:
best_moves.clear()
best_score = score
best_moves.append(move)
elif score <= best_score and not white_to_play:
if len(best_moves) > 0 and score < best_score:
best_moves.clear()
best_score = score
best_moves.append(move)
return random.choice(best_moves)
piece_values_with_position = {
chess.PAWN: [
[0, 0, 0, 0, 0, 0, 0, 0],
[50, 50, 50, 50, 50, 50, 50, 50],
[10, 10, 20, 30, 30, 20, 10, 10],
[5, 5, 10, 25, 25, 10, 5, 5],
[0, 0, 0, 20, 20, 0, 0, 0],
[5, -5, -10, 0, 0, -10, -5, 5],
[5, 10, 10, -20, -20, 10, 10, 5],
[0, 0, 0, 0, 0, 0, 0, 0]
],
chess.KNIGHT: [
[-50, -40, -30, -30, -30, -30, -40, -50],
[-40, -20, 0, 0, 0, 0, -20, -40],
[-30, 0, 10, 15, 15, 10, 0, -30],
[-30, 5, 15, 20, 20, 15, 5, -30],
[-30, 0, 15, 20, 20, 15, 0, -30],
[-30, 5, 10, 15, 15, 10, 5, -30],
[-40, -20, 0, 5, 5, 0, -20, -40],
[-50, -40, -30, -30, -30, -30, -40, -50]
],
chess.BISHOP: [
[-20, -10, -10, -10, -10, -10, -10, -20],
[-10, 0, 0, 0, 0, 0, 0, -10],
[-10, 0, 5, 10, 10, 5, 0, -10],
[-10, 5, 5, 10, 10, 5, 5, -10],
[-10, 0, 10, 10, 10, 10, 0, -10],
[-10, 10, 10, 10, 10, 10, 10, -10],
[-10, 5, 0, 0, 0, 0, 5, -10],
[-20, -10, -10, -10, -10, -10, -10, -20]
],
chess.ROOK: [
[0, 0, 0, 0, 0, 0, 0, 0],
[5, 10, 10, 10, 10, 10, 10, 5],
[-5, 0, 0, 0, 0, 0, 0, -5],
[-5, 0, 0, 0, 0, 0, 0, -5],
[-5, 0, 0, 0, 0, 0, 0, -5],
[-5, 0, 0, 0, 0, 0, 0, -5],
[-5, 0, 0, 0, 0, 0, 0, -5],
[0, 0, 0, 5, 5, 0, 0, 0]
],
chess.QUEEN: [
[-20, -10, -10, -5, -5, -10, -10, -20],
[-10, 0, 0, 0, 0, 0, 0, -10],
[-10, 0, 5, 5, 5, 5, 0, -10],
[-5, 0, 5, 5, 5, 5, 0, -5],
[0, 0, 5, 5, 5, 5, 0, -5],
[-10, 5, 5, 5, 5, 5, 0, -10],
[-10, 0, 5, 0, 0, 0, 0, -10],
[-20, -10, -10, -5, -5, -10, -10, -20]
],
chess.KING: [
[-30, -40, -40, -50, -50, -40, -40, -30],
[-30, -40, -40, -50, -50, -40, -40, -30],
[-30, -40, -40, -50, -50, -40, -40, -30],
[-30, -40, -40, -50, -50, -40, -40, -30],
[-20, -30, -30, -40, -40, -30, -30, -20],
[-10, -20, -20, -20, -20, -20, -20, -10],
[20, 20, 0, 0, 0, 0, 20, 20],
[20, 30, 10, 0, 0, 10, 30, 20]
]
}
def get_piece_value(piece, x, y):
if piece.piece_type == chess.PAWN:
return 100 + piece_values_with_position[piece.piece_type][x][y]
elif piece.piece_type == chess.KNIGHT:
return 320 + piece_values_with_position[piece.piece_type][x][y]
elif piece.piece_type == chess.BISHOP:
return 330 + piece_values_with_position[piece.piece_type][x][y]
elif piece.piece_type == chess.ROOK:
return 500 + piece_values_with_position[piece.piece_type][x][y]
elif piece.piece_type == chess.QUEEN:
return 900 + piece_values_with_position[piece.piece_type][x][y]
elif piece.piece_type == chess.KING:
return 20000 + piece_values_with_position[piece.piece_type][x][y]
else:
return 0
def evaluate_board(board):
score = 0
for i in range(8):
for j in range(8):
piece = board.piece_at(chess.square(i, j))
if piece is not None:
if piece.color == chess.WHITE:
score += get_piece_value(piece, i, j)
else:
score -= get_piece_value(piece, i, j)
return score
if __name__ == "__main__":
white_wins = 0
black_wins = 0
draws = 0
n = 10
depth = 3
for i in range(n):
board = chess.Board()
while not board.is_game_over():
print("White to move" if board.turn else "Black to move")
if board.turn == chess.WHITE:
move = best_move_using_minimax_with_alpha_beta_pruning(board, depth)
board.push(move)
else:
move = best_move_using_minimax_with_alpha_beta_pruning(board, depth)
board.push(move)
print(board)
print()
if board.result() == "1-0":
white_wins += 1
elif board.result() == "0-1":
black_wins += 1
else:
draws += 1
print(f"Game {i+1} finished, result: {board.result()}")
print(f"White winrate: {white_wins/n * 100}%")
print(f"Black winrate: {black_wins/n * 100}%")
print(f"Draw rate: {draws/n * 100}%")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment