【AI出牌器】第一次见这么“刺激”的斗地主,胜率高的关键因素竟是......
前言
🚀 作者 :“程序員梨子”
🚀 **文章簡介 **:本篇文章主要制作一款AI斗地主自動出牌器啦。
🚀 **文章源碼獲取 **: 為了感謝每一個關注我的小可愛💓每篇文章的項目源碼都是無償分
享滴💓👇👇👇👇
點這里藍色這行字體自取,需要什么源碼記得說標題名字哈!私信我也可!
🚀 歡迎小伙伴們 點贊👍、收藏?、留言💬
?
正文
作為一款全民休閑娛樂游戲,斗地主從來不缺少關注。
?小編閑暇之余就喜歡斗斗地主,開個小黑,還記得大學的時候一個宿舍可以開兩桌子啦~哈哈
哈.jpg 作為小粉絲,小編今天帶大家寫一款AI出牌器!從此贏取海量“財富”,走上人生巔峰!
一、效果展示
?出牌器效果——
二、代碼步驟
第三方庫配置👇
torch==1.9.0 GitPython==3.0.5 gitdb2==2.0.6 PyAutoGUI==0.9.50 PyQt5==5.13.0 PyQt5-sip==12.8.1 Pillow>=5.2.0 opencv-python rlcard1)思路解析
UI設計排版布局——
顯示三張底牌 顯示AI角色出牌數據區域,上家出牌數據區域,下家出牌數據區域,本局勝率區域 AI玩家手牌區域 AI出牌器開始停止手牌和出牌數據識別——
游戲剛開始根據屏幕位置,截圖識別AI玩家手牌及三張底牌 確認三者之間的關系,識別地主和農民角色,確認隊友及對手關系 識別每輪三位玩家依次出了什么牌,刷新顯示對應區域AI出牌方案輸出——
加載訓練好的AI模型,初始化游戲環境 每輪出牌判斷,根據上家出牌數據給出最優出牌決策 自動刷新玩家剩余手牌和本局勝率預測2)代碼解析
使用的是pyqt5,進行簡單的UI布局設計,核心代碼如下:
def retranslateUi(self, Form):_translate = QtCore.QCoreApplication.translateForm.setWindowTitle(_translate("Form", "AI歡樂斗地主"))self.WinRate.setText(_translate("Form", "勝率:--%"))self.InitCard.setText(_translate("Form", "開始"))self.UserHandCards.setText(_translate("Form", "手牌"))self.LPlayedCard.setText(_translate("Form", "上家出牌區域"))self.RPlayedCard.setText(_translate("Form", "下家出牌區域"))self.PredictedCard.setText(_translate("Form", "AI出牌區域"))self.ThreeLandlordCards.setText(_translate("Form", "三張底牌"))self.Stop.setText(_translate("Form", "停止"))實現效果如下:
?識別AI玩家手牌及三張底牌。
我們可以截取游戲屏幕的固定位置,送入訓練好的YOLOv5網絡,來識別當前AI玩家的手牌和三張
底牌。核心代碼如下:
def find_three_landlord_cards(self, pos):three_landlord_cards_real = ""img = pyautogui.screenshot(region=pos)three_landlord_cards_real=detect_cards(img)return three_landlord_cards_realdef find_my_cards(self, pos):user_hand_cards_real = ""img = pyautogui.screenshot(region=pos) # img2 = color.rgb2gray(img)user_hand_cards_real=detect_cards(img)return user_hand_cards_real def detect_cards(img):path="datas\cards.png"img.save(path)raw_cards=detect(source=path)replace_cards=[replace_num[i] if i in replace_num else i for i in raw_cards]list_cards = sorted(replace_cards, key=lambda x: ranks_value[x])cards=("".join(list_cards))return cardsdef detect()# Initializeset_logging()# device = select_device(device)device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#若有gpu可用則用gpu# half &= device.type != 'cpu' # half precision only supported on CUDAw = weights[0] if isinstance(weights, list) else weightsclassify, pt, onnx = False, w.endswith('.pt'), w.endswith('.onnx') # inference typestride, names = 64, [f'class{i}' for i in range(1000)] # assign defaultsif pt:model = attempt_load(weights, map_location=device) # load FP32 modelstride = int(model.stride.max()) # model stridenames = model.module.names if hasattr(model, 'module') else model.names # get class namesif half:model.half() # to FP16if classify: # second-stage classifiermodelc = load_classifier(name='resnet50', n=2) # initializemodelc.load_state_dict(torch.load('resnet50.pt', map_location=device)['model']).to(device).eval()elif onnx:check_requirements(('onnx', 'onnxruntime'))import onnxruntimesession = onnxruntime.InferenceSession(w, None)dataset = LoadImages(source, img_size=imgsz, stride=stride)bs = 1 # batch_sizevid_path, vid_writer = [None] * bs, [None] * bst0 = time.time()imgsz = check_img_size(imgsz, s=stride) # check image sizefor path, img, im0s, vid_cap in dataset:if pt:img = torch.from_numpy(img).to(device)img = img.half() if half else img.float() # uint8 to fp16/32elif onnx:img = img.astype('float32')img /= 255.0 # 0 - 255 to 0.0 - 1.0if len(img.shape) == 3:img = img[None] # expand for batch dim# Inferencet1 = time_sync()if pt:pred = model(img, augment=augment, visualize=visualize)[0]elif onnx:pred = torch.tensor(session.run([session.get_outputs()[0].name], {session.get_inputs()[0].name: img}))# NMSpred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)t2 = time_sync()# Second-stage classifier (optional)if classify:pred = apply_classifier(pred, modelc, img, im0s)# Process predictionsfor i, det in enumerate(pred): # detections per imagep, s, im0, frame = path, '', im0s.copy(), getattr(dataset, 'frame', 0)p = Path(p) # to Pathgn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwhimc = im0.copy() if save_crop else im0 # for save_cropif len(det):# Rescale boxes from img_size to im0 sizedet[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()lists=[]# Print resultsfor c in det[:, -1].unique():n = (det[:, -1] == c).sum() # detections per classfor i in range(n):lists.append(names[int(c)])return lists效果展示:
?
地主、地主上家、地主下家:
同理我們可以根據游戲屏幕截圖,識別地主的圖標,確認地主角色。核心代碼如下:
# 查找地主角色 def find_landlord(self, landlord_flag_pos):for pos in landlord_flag_pos:result = pyautogui.locateOnScreen('pics/landlord_words.png', region=pos, confidence=self.LandlordFlagConfidence)if result is not None:return landlord_flag_pos.index(pos)return None效果展示:
這樣我們就可以得到玩家AI手牌,其他玩家手牌(預測),地主三張底牌,三者角色關系,出牌順
序。
出牌、不出、等待狀態:
同理我們可以根據游戲屏幕截圖,識別其他人出牌區域,判斷其出牌狀態 。核心代碼如下:
labels=['等待','出牌','不出'] device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#若有gpu可用則用gpu model = models.resnet50(pretrained=False) fc_inputs = model.fc.in_features model.fc = nn.Sequential(nn.Linear(fc_inputs, 256),nn.ReLU(),nn.Dropout(0.4),nn.Linear(256, config.NUM_CLASSES),nn.LogSoftmax(dim=1) ) pthfile=config.TRAINED_BEST_MODEL checkpoint = torch.load(pthfile) model.load_state_dict(checkpoint['model']) # optimizer.load_state_dict(checkpoint['optimizer']) start_epoch = checkpoint['epoch'] # test(model, test_load) model.to(device).eval() def detect_pass(pos):img = pyautogui.screenshot(region=pos) # path="datas\state.png"time =datetime.datetime.now().strftime(TIMESTAMP)path="datas\states\state"+'_'+time+'.png'img.save(path)# path="datas/states/state_20210807160852.png"src = cv2.imread(path) # aeroplane.jpgimage = cv2.resize(src, (224, 224))image = np.float32(image) / 255.0image[:,:,] -= (np.float32(0.485), np.float32(0.456), np.float32(0.406))image[:,:,] /= (np.float32(0.229), np.float32(0.224), np.float32(0.225))image = image.transpose((2, 0, 1))input_x = torch.from_numpy(image).unsqueeze(0).to(device)pred = model(input_x)pred_index = torch.argmax(pred, 1).cpu().detach().numpy()pred_index=int(pred_index)print(pred_index)return pred_index?效果展示:
?到這里,整個AI斗地主出牌流程基本已經完成了。
總結
當所有環境配置完成,各區域坐標位置確認無誤之后,下面我們就可以直接運行程序,測試效果啦
~首先我們運行AI出牌器程序,打開歡樂斗地主游戲界面,進入游戲。當玩家就位,手牌分發完
、畢,地主身份確認之后,我們就可以點擊畫面中開始按鈕,讓AI來幫助我們斗地主了。
喜歡的記得找我拿源碼拉!
關注小編獲取更多精彩內容!記得點擊傳送門哈👇
記得三連哦! 如需打包好的源碼+素材免費分享滴!!傳送門
總結
以上是生活随笔為你收集整理的【AI出牌器】第一次见这么“刺激”的斗地主,胜率高的关键因素竟是......的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Pygame小游戏】首月破亿下载 一款
- 下一篇: 【Python小程序】这竟是2月14号情