斗地主AI出牌助手--在线调用斗地主AI,实现自动斗地主

admin2025-11-04 10:09:18901

根据指定窗口句柄截图

def WindowShot(self):

"""

根据窗口句柄截图

返回: 图片对象

"""

windll.user32.SetProcessDPIAware()

hwnd = self.Handle

left, top, right, bottom = win32gui.GetClientRect(hwnd)

w = right - left

h = bottom - top

hwnd_dc = win32gui.GetWindowDC(hwnd)

mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)

save_dc = mfc_dc.CreateCompatibleDC()

bitmap = win32ui.CreateBitmap()

bitmap.CreateCompatibleBitmap(mfc_dc, w, h)

save_dc.SelectObject(bitmap)

# If Special K is running, this number is 3. If not, 1

result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)

bmpinfo = bitmap.GetInfo()

bmpstr = bitmap.GetBitmapBits(True)

img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))

img = np.ascontiguousarray(img)[..., :-1] # make image C_CONTIGUOUS and drop alpha channel

#img = Image.frombuffer("RGB",(bmpinfo['bmWidth'], bmpinfo['bmHeight']),bmpstr, 'raw', 'BGRX', 0, 1)

if not result: # result should be 1

win32gui.DeleteObject(bitmap.GetHandle())

save_dc.DeleteDC()

mfc_dc.DeleteDC()

win32gui.ReleaseDC(hwnd, hwnd_dc)

raise RuntimeError(f"Unable to acquire screenshot! Result: {result}")

#cv2.imwrite('./imgs/print.png', img)

#return img

return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)

在图片中查找第一个相似的图片

def LocateOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):

"""

在image中寻找template,返回第一个查找到的范围

参数:

template: 需要查找的图片,文件名或图片对象

image: 被查找的图片,文件名或图片对象

region: 查找范围

confidence: 置信度

grayscale: 是否为灰度图

返回值:

查找到的图片范围

"""

if image is None:

image = self.WindowShot()

return pyautogui.locate(template, image, region=region, confidence=confidence, grayscale=grayscale)

在图片中查找所有相似的图片

def LocateAllOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):

"""

在image中寻找template,返回第一个查找到的范围

参数:

template: 需要查找的图片,文件名或图片对象

image: 被查找的图片,文件名或图片对象

region: 查找范围

confidence: 置信度

grayscale: 是否为灰度图

返回值:

查找到的图片范围

"""

if image is None:

image = self.WindowShot()

return pyautogui.locateAll(template, image, region=region, confidence=confidence, grayscale=grayscale)

识别手牌

def GetCards(self, image, player):

hand_cards = []

cards = ""

start_x = 0

width = player["width"]

for card in self.AllCardsNC:

confidence = player["confidence"] or 0.85

grayscale = True

if(card in ('D', 'X')):

confidence = 0.85

grayscale = False

card_key = player["prefix"] + card

matches = self.LocateAllOnImageName(card_key, image, player["region"], confidence, grayscale)

if len(matches) > 0:

sorted_matches = sorted(matches, key=lambda match: match[0])

#print(target_position)

#print(mark)

if(card != 'X'):

start_x = 0

for match in sorted_matches:

if(start_x == 0 or start_x + player["width"] < match[0]):

#大小王容易判断错误,需要再判断一下颜色值

if(card == 'D'):

#match = sorted_matches[0]

y,x,h,w = match

cropped_image = image[x:x+w, y:y+h]

#colors = cv2.mean(cropped_image)

mean, stddev = cv2.meanStdDev(cropped_image)

#print("均值:", mean)

#print("差值:", stddev)

if(stddev[2][0] > 30):

continue

start_x = match[0]

width = match[2]

hand_cards.append({card:match})

cards += card

return cards, hand_cards

将出牌记录发送给AI,进行预测

def GetCardsForPredict(self):

#将出牌记录发送给AI,进行预测

resultStr = self.PostPredict()

#获取最高胜率的出牌

last_move_cards = self.GetPredictWinRates(resultStr)

return last_move_cards

出牌

def PlayedCards(self, cards, image=None):

if image is not None:

window_shot_image = image

else:

window_shot_image = self.WindowShot()

player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])

select_index = []

select_cards = []

#将cards中的字符顺序反转

play_cards = cards[::-1]

cards = play_cards

for c in cards:

index = -1

for card in player_self_cards:

index += 1

if c == card and index not in select_index:

select_index.append(index)

select_cards.append(c)

#print(range[index])

cards = cards.replace(c, '', 1)

card_range = range[index][c]

break

cards = play_cards

index = -1

#window_shot_image = self.WindowShot()

for n in select_index:

window_shot_image = self.WindowShot()

player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])

if(len(player_self_cards) > n):

#player_self_cards = player_self_cards

index += 1

card_range = range[n][cards[index]]

#如果要出的牌还未选择完毕,则点击

if(card_range[1] > self.CardTop):

self.LeftClick(card_range)

time.sleep(0.2)

return self.GetSelectCards(play_cards)

DouZero 的请求结构体

Predict = {

"bomb_num":0,#炸弹数量

"card_play_action_seq":'',#历史出牌动作序列,用逗号分隔

"last_move_landlord":'',#地主最后出的牌

"last_move_landlord_down":'',#地主下家最后出的牌

"last_move_landlord_up":'',#地主上家最后出的牌

"num_cards_left_landlord":20,#地主手牌剩余数量

"num_cards_left_landlord_down":17,#地主下家手牌剩余数量

"num_cards_left_landlord_up":17,#地主上家手牌剩余数量

"other_hand_cards":'',#还剩余的牌

"played_cards_landlord":'',#地主所有出的牌

"played_cards_landlord_down":'',#地主下家所有出的牌

"played_cards_landlord_up":'',#地主上家所有出的牌

"player_hand_cards":'',#玩家手中的牌

"player_position":0, #-当前玩家的位置序号 0 地主,1 地主下家,2 地主上家

"three_landlord_cards":''#三张底牌

}