Created
June 18, 2021 12:03
-
-
Save InputBlackBoxOutput/a6b02166128273b5f01e10acaa74a2b4 to your computer and use it in GitHub Desktop.
Chess engine using minimax with alpha beta pruning
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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