def quickEvaluate(self, history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle, depth, playerIsWhite): Moves = self.Moves counter = 0 self.currKing = whiteKing self.currQueen = whiteQueen self.currBishop = whiteBishop self.currKnight = whiteKnight self.currRook = whiteRook self.currPawn = whitePawn self.altKing = blackKing self.altQueen = blackQueen self.altBishop = blackBishop self.altKnight = blackKnight self.altRook = blackRook self.altPawn = blackPawn whitePossibleMoves = Moves.white_legalMoves( history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle) blackPossibleMoves = Moves.black_legalMoves( history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle) numOfWhitePossibleMoves = len(whitePossibleMoves.split()) numOfBlackPossibleMoves = len(blackPossibleMoves.split()) boardFlipped = False if (playerIsWhite): pass elif (not playerIsWhite): self.flipBoard() boardFlipped = True """ -> Our internal board is always represented with black pieces on top, white pieces at the bottom. -> Our method usually will just evaluate white pieces, add it to our counter; flip the board, evaluate white pieces again, and deduct them from our counter. -> If player is white and if it's white turn to move, there's no problem at all with this approach, since we will add white pieces' score to our counter, and deduct black pieces' score from our counter. -> If player is white and if it's black turn to move, observe that there is still no problem with this approach. In particular, we'll add white pieces' score to our counter, and deduct black pieces' score from our counter. This is okay, because we want our board evaluation to be based on white player's perspective. We want to see if when black makes a move, how does it affect white player. -> When player is black, we just need to flip board before computing. The rest of the procedure remains the same. """ #give each piece on the board a score, rate the board #Player's perspective material = self.rateMaterial(self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn) counter = counter + material #score for white pieces (player is white) if (not boardFlipped): #rate Moveability counter = counter + self.rateMoveability( self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn, self.altKing, self.altQueen, self.altBishop, self.altKnight, self.altRook, self.altPawn, depth, material, numOfWhitePossibleMoves) #score for black pieces (player is black) elif (boardFlipped): #rate Moveability counter = counter + self.rateMoveability( self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn, self.altKing, self.altQueen, self.altBishop, self.altKnight, self.altRook, self.altPawn, depth, material, numOfBlackPossibleMoves) self.flipBoard() #we need to update our board flipped variable according to if our board is flipped now #if board is not flipped before, since we just do flipBoard(), our board is flipped now. if (boardFlipped == False): boardFlipped = True #if board is flipped before, since we just do flipBoard(), board is now back to its original state. So board is not flipped now. elif (boardFlipped == True): boardFlipped = False #Opponent's perspective material = self.rateMaterial(self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn) counter = counter - material #score for black pieces (player is white) if (boardFlipped): counter = counter - self.rateMoveability( self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn, self.altKing, self.altQueen, self.altBishop, self.altKnight, self.altRook, self.altPawn, depth, material, numOfBlackPossibleMoves) #score for white pieces (player is black) elif (not boardFlipped): counter = counter - self.rateMoveability( self.currKing, self.currQueen, self.currBishop, self.currKnight, self.currRook, self.currPawn, self.altKing, self.altQueen, self.altBishop, self.altKnight, self.altRook, self.altPawn, depth, material, numOfWhitePossibleMoves) self.flipBoard() #we need to update our board flipped variable according to if our board is flipped now #if board is not flipped before, since we just do flipBoard(), our board is flipped now. if (boardFlipped == False): boardFlipped = True #if board is flipped before, since we just do flipBoard(), board is now back to its original state. So board is not flipped now. elif (boardFlipped == True): boardFlipped = False #restore board to original state. black pieces on top, white pieces at bottom if (boardFlipped): self.flipBoard() boardFlipped = False return (counter + depth * 500)
def principalVariationSearch(self, alpha, beta, history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle, whiteTurn, depth): Moves = self.Moves Rating = self.Rating #if we reach our max search depth, return the best score for the board at that level if (depth == self.maxDepth): bestScore = Rating.evaluate( history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle, depth, self.playerIsWhite) return bestScore, "No Move" if (whiteTurn): moves = Moves.white_legalMoves( history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle) else: moves = Moves.black_legalMoves( history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle) #get the first legal move for the current player. After the moves have been sorted, we assume that the first move is always the best move. moves = self.sanitizeMove(moves, history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle, whiteTurn) #if no legal move for current player, then it must be checkmate or stalemate #if this is player's turn, this is really bad. return -5000 #if this is opponent's turn, this is good. we want this. return 5000 #TODO: Check this AND FIX THIS! if (len(moves) == 0): if (self.playerIsWhite == whiteTurn): return -5000, "No Move" else: return 5000, "No Move" moves = self.sortMoves(moves, history, whiteKing, whiteQueen, whiteBishop, whiteKnight, whiteRook, whitePawn, blackKing, blackQueen, blackBishop, blackKnight, blackRook, blackPawn, whiteQueenCastle, whiteKingCastle, blackQueenCastle, blackKingCastle, whiteTurn, depth) firstLegalMoveIndex = 0 b = beta bestScore = -math.inf ####################################### throughroughly search firstLegalMove firstLegalMove = moves[firstLegalMoveIndex] try: originalX = int(firstLegalMove[0]) originalY = int(firstLegalMove[1]) newX = int(firstLegalMove[2]) newY = int(firstLegalMove[3]) except (ValueError): raise ValueError( "Error in principalVariationSearch: the first four character of firstLegalMove string must be integer." ) start = (originalX * 8) + originalY end = (newX * 8) + newY #white pieces tempWhiteKing = Moves.makeMove(whiteKing, firstLegalMove, "K") tempWhiteQueen = Moves.makeMove(whiteQueen, firstLegalMove, "Q") tempWhiteBishop = Moves.makeMove(whiteBishop, firstLegalMove, "B") tempWhiteKnight = Moves.makeMove(whiteKnight, firstLegalMove, "H") tempWhiteRook = Moves.makeMove(whiteRook, firstLegalMove, "R") tempWhitePawn = Moves.makeMove(whitePawn, firstLegalMove, "P") #if castling, make castling move if ("WL" in firstLegalMove or "WR" in firstLegalMove): tempWhiteKing, tempWhiteRook = Moves.makeCastlingMove( whiteKing, whiteRook, firstLegalMove) #black pieces tempBlackKing = Moves.makeMove(blackKing, firstLegalMove, "k") tempBlackQueen = Moves.makeMove(blackQueen, firstLegalMove, "q") tempBlackBishop = Moves.makeMove(blackBishop, firstLegalMove, "b") tempBlackKnight = Moves.makeMove(blackKnight, firstLegalMove, "h") tempBlackRook = Moves.makeMove(blackRook, firstLegalMove, "r") tempBlackPawn = Moves.makeMove(blackPawn, firstLegalMove, "p") if ("BL" in firstLegalMove or "BR" in firstLegalMove): tempBlackKing, tempBlackRook = Moves.makeCastlingMove( blackKing, blackRook, firstLegalMove) tempHistory = firstLegalMove ###update castling variables #copy castling variables from previous tempWhiteQueenCastle = whiteQueenCastle tempWhiteKingCastle = whiteKingCastle tempBlackQueenCastle = blackQueenCastle tempBlackKingCastle = blackKingCastle #update castling variable based on the firstLegalMove we made #if firstLegalMove is making white castling move, we can no longer castle again for white if ("WL" in firstLegalMove or "WR" in firstLegalMove): tempWhiteQueenCastle = False tempWhiteKingCastle = False #if firstLegalMove is making black castling move, we can no longer castle again for black elif ("BL" in firstLegalMove or "BR" in firstLegalMove): tempBlackQueenCastle = False tempBlackKingCastle = False else: #if firstLegalMove is moving whiteKing, white queen and king side castle become False if (((1 << start) & whiteKing) != 0): tempWhiteQueenCastle = False tempWhiteKingCastle = False #if firstLegalMove is moving blackKing, black queen and king side castle become False elif (((1 << start) & blackKing) != 0): tempBlackQueenCastle = False tempBlackKingCastle = False #if firstLegalMove is moving white left rook, white queenside castling become False elif (((1 << start) & whiteRook & (1 << 56)) != 0): tempWhiteQueenCastle = False #if firstLegalMove is moving white right rook, white kingside castling become False elif (((1 << start) & whiteRook & (1 << 63)) != 0): tempWhiteKingCastle = False elif (((1 << start) & blackRook & (1 << 0)) != 0): tempBlackQueenCastle = False elif (((1 << start) & blackRook & (1 << 7)) != 0): tempBlackKingCastle = False """ # original algorithm score,bestMove=-self.principalVariationSearch(-b,-alpha,tempHistory,tempWhiteKing,tempWhiteQueen,tempWhiteBishop,tempWhiteKnight,tempWhiteRook,tempWhitePawn,tempBlackKing,tempBlackQueen,tempBlackBishop,tempBlackKnight,tempBlackRook,tempBlackPawn,tempWhiteQueenCastle,tempWhiteKingCastle,tempBlackQueenCastle,tempBlackKingCastle,not whiteTurn,depth+1) """ #Alternate way of writing to original algorithm score, bestMove = self.principalVariationSearch( -b, -alpha, tempHistory, tempWhiteKing, tempWhiteQueen, tempWhiteBishop, tempWhiteKnight, tempWhiteRook, tempWhitePawn, tempBlackKing, tempBlackQueen, tempBlackBishop, tempBlackKnight, tempBlackRook, tempBlackPawn, tempWhiteQueenCastle, tempWhiteKingCastle, tempBlackQueenCastle, tempBlackKingCastle, not whiteTurn, depth + 1) score = -score #In principal variation search, we assume that our first move is the best move, and thus yield the best score. bestScore = self.max(bestScore, score) #can also write bestScore=score alpha = self.max(alpha, score) bestMoveIndex = firstLegalMoveIndex if (alpha >= beta): return alpha, moves[bestMoveIndex] b = alpha + 1 ####################################### simply and quickly search through remaining move to confirm our assumption that firstLegalMove is the best move for i in range(len(moves)): #if current iteration is firstLegalMoveIndex, skip, since we already thoroughly searched this move. if (i == firstLegalMoveIndex): continue #if current iteration is not firstLegalMoveIndex, simply and quickly search through current move. currentMove = moves[i] try: originalX = int(currentMove[0]) originalY = int(currentMove[1]) newX = int(currentMove[2]) newY = int(currentMove[3]) except (ValueError): raise ValueError( "Error in principalVariationSearch: the first four character of currentMove string must be integer." ) start = (originalX * 8) + originalY end = (newX * 8) + newY #white pieces tempWhiteKing = Moves.makeMove(whiteKing, currentMove, "K") tempWhiteQueen = Moves.makeMove(whiteQueen, currentMove, "Q") tempWhiteBishop = Moves.makeMove(whiteBishop, currentMove, "B") tempWhiteKnight = Moves.makeMove(whiteKnight, currentMove, "H") tempWhiteRook = Moves.makeMove(whiteRook, currentMove, "R") tempWhitePawn = Moves.makeMove(whitePawn, currentMove, "P") #if castling, make castling move if ("WL" in currentMove or "WR" in currentMove): tempWhiteKing, tempWhiteRook = Moves.makeCastlingMove( whiteKing, whiteRook, currentMove) #black pieces tempBlackKing = Moves.makeMove(blackKing, currentMove, "k") tempBlackQueen = Moves.makeMove(blackQueen, currentMove, "q") tempBlackBishop = Moves.makeMove(blackBishop, currentMove, "b") tempBlackKnight = Moves.makeMove(blackKnight, currentMove, "h") tempBlackRook = Moves.makeMove(blackRook, currentMove, "r") tempBlackPawn = Moves.makeMove(blackPawn, currentMove, "p") if ("BL" in currentMove or "BR" in currentMove): tempBlackKing, tempBlackRook = Moves.makeCastlingMove( blackKing, blackRook, currentMove) tempHistory = currentMove ###update castling variables #copy castling variables from previous tempWhiteQueenCastle = whiteQueenCastle tempWhiteKingCastle = whiteKingCastle tempBlackQueenCastle = blackQueenCastle tempBlackKingCastle = blackKingCastle #update castling variable based on the currentMove we made #if currentMove is making white castling move, we can no longer castle again for white if ("WL" in currentMove or "WR" in currentMove): tempWhiteQueenCastle = False tempWhiteKingCastle = False #if currentMove is making black castling move, we can no longer castle again for black elif ("BL" in currentMove or "BR" in currentMove): tempBlackQueenCastle = False tempBlackKingCastle = False else: #if currentMove is moving whiteKing, white queen and king side castle become False if (((1 << start) & whiteKing) != 0): tempWhiteQueenCastle = False tempWhiteKingCastle = False #if currentMove is moving blackKing, black queen and king side castle become False elif (((1 << start) & blackKing) != 0): tempBlackQueenCastle = False tempBlackKingCastle = False #if currentMove is moving white left rook, white queenside castling become False elif (((1 << start) & whiteRook & (1 << 56)) != 0): tempWhiteQueenCastle = False #if currentMove is moving white right rook, white kingside castling become False elif (((1 << start) & whiteRook & (1 << 63)) != 0): tempWhiteKingCastle = False elif (((1 << start) & blackRook & (1 << 0)) != 0): tempBlackQueenCastle = False elif (((1 << start) & blackRook & (1 << 7)) != 0): tempBlackKingCastle = False #TODO: check this! """ # original algorithm score,bestMove=-self.principalVariationSearch(-b,-alpha,tempHistory,tempWhiteKing,tempWhiteQueen,tempWhiteBishop,tempWhiteKnight,tempWhiteRook,tempWhitePawn,tempBlackKing,tempBlackQueen,tempBlackBishop,tempBlackKnight,tempBlackRook,tempBlackPawn,tempWhiteQueenCastle,tempWhiteKingCastle,tempBlackQueenCastle,tempBlackKingCastle,not whiteTurn,depth+1) """ #Alternate way of writing to original algorithm score, bestMove = self.principalVariationSearch( -b, -alpha, tempHistory, tempWhiteKing, tempWhiteQueen, tempWhiteBishop, tempWhiteKnight, tempWhiteRook, tempWhitePawn, tempBlackKing, tempBlackQueen, tempBlackBishop, tempBlackKnight, tempBlackRook, tempBlackPawn, tempWhiteQueenCastle, tempWhiteKingCastle, tempBlackQueenCastle, tempBlackKingCastle, not whiteTurn, depth + 1) score = -score if (score > alpha and score < beta): """ # original algorithm score,bestMove=-self.principalVariationSearch(-beta,-score,tempHistory,tempWhiteKing,tempWhiteQueen,tempWhiteBishop,tempWhiteKnight,tempWhiteRook,tempWhitePawn,tempBlackKing,tempBlackQueen,tempBlackBishop,tempBlackKnight,tempBlackRook,tempBlackPawn,tempWhiteQueenCastle,tempWhiteKingCastle,tempBlackQueenCastle,tempBlackKingCastle,not whiteTurn,depth+1) """ #alternate way of writing to original algorithm score, bestMove = self.principalVariationSearch( -beta, -score, tempHistory, tempWhiteKing, tempWhiteQueen, tempWhiteBishop, tempWhiteKnight, tempWhiteRook, tempWhitePawn, tempBlackKing, tempBlackQueen, tempBlackBishop, tempBlackKnight, tempBlackRook, tempBlackPawn, tempWhiteQueenCastle, tempWhiteKingCastle, tempBlackQueenCastle, tempBlackKingCastle, not whiteTurn, depth + 1) score = -score ##For debugging # print("researched") if (score > bestScore): bestMoveIndex = i bestScore = score alpha = self.max(alpha, score) if (alpha >= beta): return alpha, moves[bestMoveIndex] b = alpha + 1 return bestScore, moves[bestMoveIndex]
def getAllCurrentLegalMoves(self, whiteTurn): Moves = self.Moves if (whiteTurn): moves = Moves.white_legalMoves( self.history, self.whiteKing, self.whiteQueen, self.whiteBishop, self.whiteKnight, self.whiteRook, self.whitePawn, self.blackKing, self.blackQueen, self.blackBishop, self.blackKnight, self.blackRook, self.blackPawn, self.whiteQueenCastle, self.whiteKingCastle, self.blackQueenCastle, self.blackKingCastle) else: moves = Moves.black_legalMoves( self.history, self.whiteKing, self.whiteQueen, self.whiteBishop, self.whiteKnight, self.whiteRook, self.whitePawn, self.blackKing, self.blackQueen, self.blackBishop, self.blackKnight, self.blackRook, self.blackPawn, self.whiteQueenCastle, self.whiteKingCastle, self.blackQueenCastle, self.blackKingCastle) moves = moves.split() li = [] for i in range(len(moves)): currentMove = moves[i] #white pieces tempWhiteKing = Moves.makeMove(self.whiteKing, currentMove, "K") tempWhiteQueen = Moves.makeMove(self.whiteQueen, currentMove, "Q") tempWhiteBishop = Moves.makeMove(self.whiteBishop, currentMove, "B") tempWhiteKnight = Moves.makeMove(self.whiteKnight, currentMove, "H") tempWhiteRook = Moves.makeMove(self.whiteRook, currentMove, "R") tempWhitePawn = Moves.makeMove(self.whitePawn, currentMove, "P") #if castling, make castling move if ("WL" in currentMove or "WR" in currentMove): tempWhiteKing, tempWhiteRook = Moves.makeCastlingMove( self.whiteKing, self.whiteRook, currentMove) #black pieces tempBlackKing = Moves.makeMove(self.blackKing, currentMove, "k") tempBlackQueen = Moves.makeMove(self.blackQueen, currentMove, "q") tempBlackBishop = Moves.makeMove(self.blackBishop, currentMove, "b") tempBlackKnight = Moves.makeMove(self.blackKnight, currentMove, "h") tempBlackRook = Moves.makeMove(self.blackRook, currentMove, "r") tempBlackPawn = Moves.makeMove(self.blackPawn, currentMove, "p") if ("BL" in currentMove or "BR" in currentMove): tempBlackKing, tempBlackRook = Moves.makeCastlingMove( self.blackKing, self.blackRook, currentMove) tempHistory = currentMove if (whiteTurn): if ((tempWhiteKing & Moves.whiteKing_illegalMoves( tempWhiteKing, tempWhiteQueen, tempWhiteBishop, tempWhiteKnight, tempWhiteRook, tempWhitePawn, tempBlackKing, tempBlackQueen, tempBlackBishop, tempBlackKnight, tempBlackRook, tempBlackPawn)) == 0): li.append(currentMove) elif (not whiteTurn): if ((tempBlackKing & Moves.blackKing_illegalMoves( tempWhiteKing, tempWhiteQueen, tempWhiteBishop, tempWhiteKnight, tempWhiteRook, tempWhitePawn, tempBlackKing, tempBlackQueen, tempBlackBishop, tempBlackKnight, tempBlackRook, tempBlackPawn)) == 0): li.append(currentMove) self.currentAllLegalMoves = li