Skip to content

Instantly share code, notes, and snippets.

@InputBlackBoxOutput
Created June 18, 2021 12:03
Show Gist options
  • Save InputBlackBoxOutput/a6b02166128273b5f01e10acaa74a2b4 to your computer and use it in GitHub Desktop.
Save InputBlackBoxOutput/a6b02166128273b5f01e10acaa74a2b4 to your computer and use it in GitHub Desktop.
Chess engine using minimax with alpha beta pruning
# Chess bot
# Caution: This code is not optimized hence takes tremendous amount of time to run
# If you are looking for an open source chess engine, try stockfish or sunfish
# Code originally written by AnthonyASanchez
# Modified by Rutuparn Pawar (InputBlackBoxOutput) to implement parallel processing
import chess
import sys
import random
import concurrent.futures
import itertools
#-----------------------------------------------------------------------------------
# Computes score for a particular board state
def getValue(x, depth, board, isMaximizing):
move = chess.Move.from_uci(str(x))
board.push(move)
value = minimax(depth - 1, board,-10000,10000, not isMaximizing)
board.pop()
return (value, move)
#-----------------------------------------------------------------------------------
def minimaxRoot(depth, board,isMaximizing):
possibleMoves = board.legal_moves
bestMove = -9999
bestMoveFinal = None
with concurrent.futures.ProcessPoolExecutor() as executor:
values = executor.map(getValue, list(possibleMoves), itertools.repeat(depth), itertools.repeat(board), itertools.repeat(isMaximizing))
# print(list(values))
for value, move in values:
if( value > bestMove):
bestMove = value
bestMoveFinal = move
if all(element == values[0] for element in values):
bestMoveFinal = None
return bestMoveFinal
#-----------------------------------------------------------------------------------
def minimax(depth, board, alpha, beta, is_maximizing):
if(depth == 0):
return -evaluation(board)
possibleMoves = board.legal_moves
if(is_maximizing):
bestMove = -9999
for x in possibleMoves:
move = chess.Move.from_uci(str(x))
board.push(move)
bestMove = max(bestMove,minimax(depth - 1, board,alpha,beta, not is_maximizing))
board.pop()
alpha = max(alpha,bestMove)
if beta <= alpha:
return bestMove
return bestMove
else:
bestMove = 9999
for x in possibleMoves:
move = chess.Move.from_uci(str(x))
board.push(move)
bestMove = min(bestMove, minimax(depth - 1, board,alpha,beta, not is_maximizing))
board.pop()
beta = min(beta,bestMove)
if(beta <= alpha):
return bestMove
return bestMove
#-----------------------------------------------------------------------------------
def calculateMove(board):
possible_moves = board.legal_moves
if(len(possible_moves) == 0):
print("No more possible moves...Game Over")
sys.exit()
bestMove = None
bestValue = -9999
n = 0
for x in possible_moves:
move = chess.Move.from_uci(str(x))
board.push(move)
boardValue = -evaluation(board)
board.pop()
if(boardValue > bestValue):
bestValue = boardValue
bestMove = move
return bestMove
#-----------------------------------------------------------------------------------
def evaluation(board):
i = 0
evaluation = 0
x = True
try:
x = bool(board.piece_at(i).color)
except AttributeError as e:
x = x
while i < 63:
i += 1
evaluation = evaluation + (getPieceValue(str(board.piece_at(i))) if x else -getPieceValue(str(board.piece_at(i))))
return evaluation
#-----------------------------------------------------------------------------------
def getPieceValue(piece):
if(piece == None):
return 0
value = 0
if piece == "P" or piece == "p":
value = 10
if piece == "N" or piece == "n":
value = 30
if piece == "B" or piece == "b":
value = 30
if piece == "R" or piece == "r":
value = 50
if piece == "Q" or piece == "q":
value = 90
if piece == 'K' or piece == 'k':
value = 900
#value = value if (board.piece_at(place)).color else -value
return value
#-----------------------------------------------------------------------------------
randomStart = ["d7d5", "b8c6", "g8f6", "f8b4", "c8g4", "b7b6", "g7g6", "c8a6", "f8h6", "e7e5"]
def randomMove(board):
start = [chess.Move.from_uci(x) for x in randomStart]
possibleMoves = board.legal_moves
for move in start:
if move in possibleMoves:
return move
return list(possibleMoves)[random.randint(0, possibleMoves.count()-1)]
#-----------------------------------------------------------------------------------
def showHelp():
print("\nHelp:")
print("\nRows are 8 to 1 from top to bottom")
print("Columns are a to h from left to right")
print("\nIf you wish to move a piece from column b row 2 to column b row 3,")
print("Enter your move as b2b3\n")
#-----------------------------------------------------------------------------------
def main():
print("----- Chess -----")
print("-> Enter q to quit")
print("-> Enter h for help \n")
board = chess.Board()
n = 0
print(board)
while n < 200:
usr_move = input("\nEnter move: ")
if usr_move == 'q':
sys.exit()
if usr_move == 'h':
showHelp()
if(len(usr_move) == 4):
try:
move = chess.Move.from_uci(str(usr_move))
except:
print("Invalid move")
if(move in board.legal_moves):
board.push(move)
print("\nComputers Turn:")
move = minimaxRoot(4,board,True)
if move == None:
move = chess.Move.from_uci(str(randomMove(board)))
else:
move = chess.Move.from_uci(str(move))
board.push(move)
print(board)
if board.is_stalemate():
print("Game Over: Stalemate")
break
if board.is_insufficient_material():
print("Game Over: Insufficient Pieces")
break
if board.is_game_over():
print("Game Over: Checkmate")
break
if board.is_check():
print("Check")
else:
print("Illegal move")
n += 1
#-----------------------------------------------------------------------------------
if __name__ == "__main__":
main()
#-----------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment