您好,登錄后才能下訂單哦!
今天小編給大家分享一下怎么使用Python在2秒內評估國際象棋位置的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
使用 OpenCV (開源計算機視覺庫)和 NumPy 庫來截取棋盤,可視化棋盤方格,并比較圖像之間的差異。
如果你不熟悉OpenCV,鼓勵你了解有關它的更多信息。接下來,使用 PIL(Pillow)庫來修改圖像(例如,裁剪)。CompareImages 模塊使用 OpenCV 來查找并突出顯示兩個圖像之間的差異。
mss 庫是一種快速簡便的方法來獲取監視器的屏幕截圖并將圖像保存為 PNG 文件。接下來,使用chess庫,用于移動生成、驗證和可視化。
最后,使用stockfish 引擎來評估國際象棋的位置并確定最佳走法。
在 Windows 中為這個項目使用 Stockfish 14.1 (AVX2)。
import cv2 # OpenCV library import numpy as np import time from PIL import Image # Pillow library will be used to open and crop images from CompareImages import compare_images # This code compares and detects differences # between images. from mss import mss # will be used for grabbing screenshots sct=mss() import chess #used for chess baord visualization, move generation, and move validation. from stockfish import Stockfish # The Stockfish chess engine will be used to evaluate # a given position and identify the top moves. stockfish = Stockfish(r"Enter Your Path Here//stockfish.exe")
接下來,創建了一個函數來定位顯示器上的棋盤。該函數接受三個輸入:棋盤左上角的 X 和 Y 坐標以及棋盤上每個方格的寬度。
在顯示器上,X 和 Y 坐標為像素(585、163),每個正方形的寬度為 90 像素(圖 1)。你需要為你的顯示器配置這些輸入。
圖 1:lichess.org 上棋盤的方向。左上角位于我屏幕的像素 (585, 163) 處,棋盤內的每個正方形都是 90 像素寬。
當你運行“capture_board”功能時,它將打開一個窗口,根據輸入參數顯示監視器的實時視圖。它還將繪制一個 8x8 網格。確保藍色框與棋盤格緊密對齊(圖 2)。
左側的圖像可能會導致對棋位的評估不佳或根本不起作用。
相反,請確保藍線與棋盤格對齊以準確捕獲棋子(右圖)。
def capture_board(y_coords=163,x_coords=585, box_widths=90): global y_coord, x_coord, box_width y_coord, x_coord, box_width = y_coords, x_coords, box_widths ''' This functions grabs a screenshot of your monitor based on the specified parameters. It then draws an 8x8 grid based on the specified box width parameter. Make sure that each blue square aligns closely with the chessboard squares. x_coord: This x coordinate is for the top left corner of the board. You will need to modify it for your monitor. y_coord: This y coordinate is for the top left corner of the board. You will need to modify it for your monitor. box_width: This is the width of each square on the chessboard. You may need to modify it based on the size of your board. ''' with mss() as sct: monitor = {"top": y_coord, "left": x_coord, "width": (box_width)*8, "height": box_width*8} while True: screenshot = np.array(sct.grab(monitor)) for i in range(1,8): # Draw 7 vericle blue lines with thickness of 3 px cv2.line(screenshot,((box_width)*i,0),((box_width)*i, y_coord+(box_width)*8), (255,0,0),3) # Draw 7 horizontal blue lines with thickness of 3 px cv2.line(screenshot,(0,(box_width)*i),(x_coord+(box_width)*8, (box_width)*i), (255,0,0),3) cv2.imshow('Chess Board', screenshot) if cv2.waitKey(1) == ord('q'): # press any key to quit. cv2.destroyAllWindows() break ## Run the above function capture_board(y_coords=163,x_coords=585, box_widths=90)
在第三步中,創建了一個函數,該函數根據 capture_board 函數的輸入獲取棋盤位置的單個屏幕截圖。此屏幕截圖將保存在本地目錄中,并在接下來的步驟中進行處理。
def take_screenshot(filename): ## Screen shot and then crop image filename1 = sct.shot(output=filename) im = Image.open(filename1) # (left, upper, right , lower ) im1 = im.crop(( x_coord , y_coord, x_coord+box_width*8, y_coord+box_width*8)) # Saves image in local directory im1.save(filename1)[]()
下面的函數檢測棋盤是否翻轉。它通過檢測棋盤左上角的車(黑色或白色)來工作。如果游戲開始并且車已經從原來的位置移動,此函數可能無法正常工作。
你可以通過在棋盤翻轉時取消注釋“is_board_flipped=True”或在棋盤未翻轉時取消注釋“is_board_flipped=False”(即,棋盤底部為白色)來覆蓋此函數。
def flipped_board(): # Take a screenshot of the chessboard and save the image in local library. take_screenshot('InitialBoard.png') im = Image.open('InitialBoard.png') # Crop the upper left-hand sqaure and process it. im1 = im.crop((5, 5, 70, 70)) im1.save('CurrentRook.png') image = cv2.imread('CurrentRook.png') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # Assume the rook is white if the upper left-hand square has more than 300 white pixels. # otherwise, the rook is black and the board is not flipped. is_board_flipped=True if np.sum(gray==255)>300 else False return is_board_flipped is_board_flipped=flipped_board() # is_board_flipped=True # is_board_flipped=False print('Is the board flipped?', is_board_flipped)
下面的數組將根據棋盤是否翻轉來排列。我在下一步中使用該數組來檢測棋盤上哪個方格上的棋子。如果棋盤沒有翻轉,方塊 A1 將在左下角;否則,A1 方塊將位于右上角。
myList=[list(range(56,64)), list(range(48,56)), list(range(40,48)), list(range(32,40)), list(range(24,32)), list(range(16,24)), list(range(8,16)), list(range(0,8))] if is_board_flipped: myList.reverse() for i in range(8): myList[i].reverse() myList
這一步只運行一次(假設棋盤的大小在游戲之間沒有變化)。確定每個棋子的像素數后,你可以刪除此部分。
想找到一種簡單、高效且一致的方法來檢測和識別棋子。計算每個棋格上的黑/白像素數效果很好。
下面的代碼集按照構成每個塊的黑白像素的數量來排列黑白塊;請注意,我手動執行了此步驟,但你的順序應該相同。你會注意到黑色國王擁有最少的黑色像素,而黑色騎士擁有最多的黑色像素。白象的白色像素數最少,而白騎士的白色像素數最多。BPieceType和WPieceType與 Chess 庫分配的棋子類型一致。
棋子類型
Pawn = 1
Knight = 2
Bisphop = 3
Rook = 4
Queen = 5
King = 6
# The pieces are arranged by the total number of black pixels. The black king has # the fewest number of black pixels, and the black knight has the largest number # of black pixels. BPieces=['BlackKing','BlackBishop','BlackPawn','BlackRook','BlackQueen','BlackKnight'] BPieceType=[6,3,1,4,5,2] # The pieces are arranged by the total number of white pixels. The white bishop has # the smallest number of white pixels, and the white knight has the largest number # of white pixels. WPieces=['WhiteBishop','WhiteQueen','WhiteRook','WhitePawn','WhiteKing','WhiteKnight'] WPieceType=[3,5,4,1,6,2]
下面的 for 循環將從提供的棋盤圖像中裁剪并保存 64 張圖像。64 個圖像中的每一個都將根據步驟 5 中指定的方向與特定的正方形對齊。確保在主目錄中創建一個“Pieces”文件夾;裁剪后的圖像將保存在此文件夾中。
BlackPixelList, WhitePixelList=[],[] nn=0; n=0 # Take a screenshot of the entire chessboard and save the image take_screenshot('image1.png') #Read the chessboard into memory image = cv2.imread('image1.png') # Convert the color image to a gray scale image and save it. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imwrite('gray image.png', gray) im = Image.open('gray image.png') # Crop each squre of the chess board and save the 64 gray scale images. Each image # will align with a specific square on the chessboard. for i in range(8): for j in range(8): im1=im.crop( (j*(box_width), i*(box_width), (j+1)*(box_width-0), (i+1)*(box_width-0))) im1.save('pieces//'+str(nn)+'.png') n+=1 n=myList[i][j] image = cv2.imread('pieces//'+str(nn)+'.png') # count the number of black pixels per image BlackPiece=np.sum(image==0) BlackPixelList.append(BlackPiece) # count the number of white pixels per image WhitePiece=np.sum(image==255) WhitePixelList.append(WhitePiece) nn+=1
下面的代碼旨在識別每個棋子的黑白像素數。我已經從上面創建了一個包含黑白像素數量的列表。
對于每種顏色,我執行以下操作:
保留唯一的像素值
以升序對列表進行排序,并保留六個最大的像素值
每個像素值將與BPieces / Wpieces中指定的部分對齊
# Filter out values equal 0 and keep unique pixel values # sort the list in ascending order # keep the six largest pixel values BlackPixelList=set(list(filter(lambda x: x > 0, BlackPixelList))) BlackPixelList=list(BlackPixelList) BlackPixelList.sort() BlackPixelList=BlackPixelList[-6:] WhitePixelList=set(list(filter(lambda x: x > 0, WhitePixelList))) WhitePixelList=list(WhitePixelList) WhitePixelList.sort() WhitePixelList=WhitePixelList[-6:] # Create a dictionary for each color and assign # pixel value to each chess piece, piece type, # and piece color (False=Black, True=White). BlackPieces={} for i, val in enumerate(BPieces): BlackPieces[val] = (BlackPixelList[i],BPieceType[i],False) WhitePieces={} for i, val in enumerate(WPieces): WhitePieces[val] = (WhitePixelList[i],WPieceType[i],True)
如果這是第一次運行代碼,請使用步驟 6 輸出為“BlackPieces”分配黑色像素數,為“WhitePieces”分配白色像素數。下面的代碼以我的顯示器為例。
BlackPieces=\ {'BlackKing': (5028, 6, False), 'BlackBishop': (5052, 3, False), 'BlackPawn': (5679, 1, False), 'BlackRook': (6489, 4, False), 'BlackQueen': (6495, 5, False), 'BlackKnight': (7623, 2, False)} WhitePieces=\ {'WhiteBishop': (2520, 3, True), 'WhiteQueen': (3039, 5, True), 'WhiteRook': (3741, 4, True), 'WhitePawn': (3933, 1, True), 'WhiteKing': (4410, 6, True), 'WhiteKnight': (6057, 2, True)} BlackPixelValues=[i[0] for i in list(BlackPieces.values())] WhitePixelValues=[i[0] for i in list(WhitePieces.values())]
我們已經完成了所有的設置步驟。我們首先將 stockfish 的等級設置為 3000 ELO,并將深度設置為 15。你可以將深度設置為 26,但這會顯著增加處理時間。然后我們創建“evaluate_position”函數。該函數將:
截屏
將彩色圖像轉換為灰度并保存圖像
確定每個棋子在棋盤上的位置,并使用國際象棋庫將這些棋子放置在棋盤上的適當位置
將該回合分配給指定的顏色。默認是輪到白棋。
根據國際象棋庫中的位置分配 stockfish 中的 FEN 位置
生成請求的輸出
stockfish.set_elo_rating(3000) stockfish.set_depth(15) def evaluate_position(white_turn=True, board_flipped=is_board_flipped): start_time = time.time() # take a screenshot of the board take_screenshot('image1.png') image = cv2.imread('image1.png') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imwrite('gray image.png', gray) im = Image.open('gray image.png') # Set up the board from the Chess library board = chess.Board() # Remove all the pieces because they will be specified in the next step board.clear() # Set the turn to White to play, unless otherwise specified board.turn = white_turn nn=0; n=0 for i in range(8): for j in range(8): im1=im.crop((j*(box_width), i*(box_width), (j+1)*(box_width-0), (i+1)*(box_width-0))) im1.save('pieces//'+str(nn)+'.png') n+=1 n=myList[i][j] # Read each cropped chess square and identify the chess piece and color. image = cv2.imread('pieces//'+str(nn)+'.png') BlackPiece=np.sum(image==0) WhitePiece=np.sum(image==255) res_val=(0,0,True) if BlackPiece>min(BlackPixelValues)-50: # Identify the chess piece based on he number of black pixels closest to the # values from the BlackPieces dictionary. col_key, res_val = min(BlackPieces.items(), key=lambda x: abs(BlackPiece - x[1][0])) if WhitePiece>min(WhitePixelValues)-50: # Identify the chess piece based on he number of white pixels closest to the # values from the BlackPieces dictionary. col_key, res_val = min(WhitePieces.items(), key=lambda x: abs(WhitePiece - x[1][0])) # set the chess piece on the board based on it position, piece type, and color. board.set_piece_at(n,piece=chess.Piece(piece_type=res_val[1],color=res_val[2])) nn+=1 #create the FEN based on the current position turn_fen=' w - - 1 0' if board.turn == True else ' b - - 0 1' current_fen=board.board_fen()+turn_fen # Assign the postion in Stockfish based on FEN stockfish.set_fen_position(current_fen) # Get the top moves top_moves=stockfish.get_top_moves() #Get the best move my_move=top_moves[0]['Move'] # Move the chess piece based on the best move board.push(chess.Move.from_uci(my_move)) #Create output print('Time:',time.time()-start_time) print('Best Move:', my_move) print('Evaluation:', stockfish.get_evaluation()) print('Top moves:') for i in top_moves: print(i) if board_flipped: board.apply_transform(chess.flip_vertical) board.apply_transform(chess.flip_horizontal) display(board) else: display(board)
恭喜,你完成了!指定是輪到白(設置 white_turn=True)還是輪到黑(white_turn=False)并運行評估函數。該函數將輸出:
Time:運行函數所花費的時間
Best Move:最明智的一步
Evaluation:對當前位置的評估
Top moves:最佳移動
當前位置和下一個最佳移動的視覺效果
如果位置發生變化,重新運行evaluate_postition函數;你不需要重新運行前面的步驟。
evaluate_position(white_turn=True)
evaluate_position 輸出示例。
以上就是“怎么使用Python在2秒內評估國際象棋位置”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。