经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 大数据/云/AI » 人工智能基础 » 查看文章
斗地主AI出牌助手--在线调用斗地主AI,实现自动斗地主
来源:cnblogs  作者:liongis  时间:2023/11/15 9:22:24  对本文有异议

简介

程序基于Python3.7开发的斗地主AI出牌助手,目前支持欢乐斗地主桌面版,微信版,也可以自己制作相应其他版本。
此出牌助手核心是识别出三位玩家出牌内容,调用基于DouZero封装的API接口,输入出牌内容,根据AI出牌方案,打出相应的牌。

运行效果

  1. ![](https://img2023.cnblogs.com/blog/129408/202311/129408-20231114235431212-40412513.gif)

核心功能

  • 手牌和位置识别
    1. 游戏刚开始根据屏幕位置,截图识别AI玩家手牌及三张底牌
    2. 根据玩家手牌判断是否抢地主和加倍
    3. 确认三者之间的关系,识别地主和农民角色,确认队友及对手关系
  • 识别每轮三位玩家出牌
    1. 根据提示按钮,判断当前的操作
    2. 识别三位玩家此轮出的牌,并记录下来
  • AI出牌方案输出
    1. 将出牌记录按格式要求发送给斗地主AI
    2. 获取斗地主AI出牌方案,选取最高胜率方案
    3. 根据AI出牌方案,选择对相应的牌,并出牌

素材准备

  • 区域定位,获取坐标值

  • 按钮及牌面

核心代码

  • 根据指定窗口句柄截图

    1. def WindowShot(self):
    2. """
    3. 根据窗口句柄截图
    4. 返回: 图片对象
    5. """
    6. windll.user32.SetProcessDPIAware()
    7. hwnd = self.Handle
    8. left, top, right, bottom = win32gui.GetClientRect(hwnd)
    9. w = right - left
    10. h = bottom - top
    11. hwnd_dc = win32gui.GetWindowDC(hwnd)
    12. mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
    13. save_dc = mfc_dc.CreateCompatibleDC()
    14. bitmap = win32ui.CreateBitmap()
    15. bitmap.CreateCompatibleBitmap(mfc_dc, w, h)
    16. save_dc.SelectObject(bitmap)
    17. # If Special K is running, this number is 3. If not, 1
    18. result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 3)
    19. bmpinfo = bitmap.GetInfo()
    20. bmpstr = bitmap.GetBitmapBits(True)
    21. img = np.frombuffer(bmpstr, dtype=np.uint8).reshape((bmpinfo["bmHeight"], bmpinfo["bmWidth"], 4))
    22. img = np.ascontiguousarray(img)[..., :-1] # make image C_CONTIGUOUS and drop alpha channel
    23. #img = Image.frombuffer("RGB",(bmpinfo['bmWidth'], bmpinfo['bmHeight']),bmpstr, 'raw', 'BGRX', 0, 1)
    24. if not result: # result should be 1
    25. win32gui.DeleteObject(bitmap.GetHandle())
    26. save_dc.DeleteDC()
    27. mfc_dc.DeleteDC()
    28. win32gui.ReleaseDC(hwnd, hwnd_dc)
    29. raise RuntimeError(f"Unable to acquire screenshot! Result: {result}")
    30. #cv2.imwrite('./imgs/print.png', img)
    31. #return img
    32. return cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
  • 在图片中查找第一个相似的图片

    1. def LocateOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):
    2. """
    3. 在image中寻找template,返回第一个查找到的范围
    4. 参数:
    5. template: 需要查找的图片,文件名或图片对象
    6. image: 被查找的图片,文件名或图片对象
    7. region: 查找范围
    8. confidence: 置信度
    9. grayscale: 是否为灰度图
    10. 返回值:
    11. 查找到的图片范围
    12. """
    13. if image is None:
    14. image = self.WindowShot()
    15. return pyautogui.locate(template, image, region=region, confidence=confidence, grayscale=grayscale)
  • 在图片中查找所有相似的图片

    1. def LocateAllOnImage(self, template, image=None, region=None, confidence=0.9, grayscale=True):
    2. """
    3. 在image中寻找template,返回第一个查找到的范围
    4. 参数:
    5. template: 需要查找的图片,文件名或图片对象
    6. image: 被查找的图片,文件名或图片对象
    7. region: 查找范围
    8. confidence: 置信度
    9. grayscale: 是否为灰度图
    10. 返回值:
    11. 查找到的图片范围
    12. """
    13. if image is None:
    14. image = self.WindowShot()
    15. return pyautogui.locateAll(template, image, region=region, confidence=confidence, grayscale=grayscale)
  • 识别手牌

    1. def GetCards(self, image, player):
    2. hand_cards = []
    3. cards = ""
    4. start_x = 0
    5. width = player["width"]
    6. for card in self.AllCardsNC:
    7. confidence = player["confidence"] or 0.85
    8. grayscale = True
    9. if(card in ('D', 'X')):
    10. confidence = 0.85
    11. grayscale = False
    12. card_key = player["prefix"] + card
    13. matches = self.LocateAllOnImageName(card_key, image, player["region"], confidence, grayscale)
    14. if len(matches) > 0:
    15. sorted_matches = sorted(matches, key=lambda match: match[0])
    16. #print(target_position)
    17. #print(mark)
    18. if(card != 'X'):
    19. start_x = 0
    20. for match in sorted_matches:
    21. if(start_x == 0 or start_x + player["width"] < match[0]):
    22. #大小王容易判断错误,需要再判断一下颜色值
    23. if(card == 'D'):
    24. #match = sorted_matches[0]
    25. y,x,h,w = match
    26. cropped_image = image[x:x+w, y:y+h]
    27. #colors = cv2.mean(cropped_image)
    28. mean, stddev = cv2.meanStdDev(cropped_image)
    29. #print("均值:", mean)
    30. #print("差值:", stddev)
    31. if(stddev[2][0] > 30):
    32. continue
    33. start_x = match[0]
    34. width = match[2]
    35. hand_cards.append({card:match})
    36. cards += card
    37. return cards, hand_cards
  • 将出牌记录发送给AI,进行预测

    1. def GetCardsForPredict(self):
    2. #将出牌记录发送给AI,进行预测
    3. resultStr = self.PostPredict()
    4. #获取最高胜率的出牌
    5. last_move_cards = self.GetPredictWinRates(resultStr)
    6. return last_move_cards
  • 出牌

    1. def PlayedCards(self, cards, image=None):
    2. if image is not None:
    3. window_shot_image = image
    4. else:
    5. window_shot_image = self.WindowShot()
    6. player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])
    7. select_index = []
    8. select_cards = []
    9. #将cards中的字符顺序反转
    10. play_cards = cards[::-1]
    11. cards = play_cards
    12. for c in cards:
    13. index = -1
    14. for card in player_self_cards:
    15. index += 1
    16. if c == card and index not in select_index:
    17. select_index.append(index)
    18. select_cards.append(c)
    19. #print(range[index])
    20. cards = cards.replace(c, '', 1)
    21. card_range = range[index][c]
    22. break
    23. cards = play_cards
    24. index = -1
    25. #window_shot_image = self.WindowShot()
    26. for n in select_index:
    27. window_shot_image = self.WindowShot()
    28. player_self_cards, range = self.GetCards(window_shot_image, self.Players["PlayerSelf"])
    29. if(len(player_self_cards) > n):
    30. #player_self_cards = player_self_cards
    31. index += 1
    32. card_range = range[n][cards[index]]
    33. #如果要出的牌还未选择完毕,则点击
    34. if(card_range[1] > self.CardTop):
    35. self.LeftClick(card_range)
    36. time.sleep(0.2)
    37. return self.GetSelectCards(play_cards)
  • DouZero 的请求结构体

    1. Predict = {
    2. "bomb_num":0,#炸弹数量
    3. "card_play_action_seq":'',#历史出牌动作序列,用逗号分隔
    4. "last_move_landlord":'',#地主最后出的牌
    5. "last_move_landlord_down":'',#地主下家最后出的牌
    6. "last_move_landlord_up":'',#地主上家最后出的牌
    7. "num_cards_left_landlord":20,#地主手牌剩余数量
    8. "num_cards_left_landlord_down":17,#地主下家手牌剩余数量
    9. "num_cards_left_landlord_up":17,#地主上家手牌剩余数量
    10. "other_hand_cards":'',#还剩余的牌
    11. "played_cards_landlord":'',#地主所有出的牌
    12. "played_cards_landlord_down":'',#地主下家所有出的牌
    13. "played_cards_landlord_up":'',#地主上家所有出的牌
    14. "player_hand_cards":'',#玩家手中的牌
    15. "player_position":0, #-当前玩家的位置序号 0 地主,1 地主下家,2 地主上家
    16. "three_landlord_cards":''#三张底牌
    17. }

可用的 DouZero 后端地址

免责声明

  1. 本程序仅供娱乐和学习使用,不得用于任何非法用途

参考项目

原文链接:https://www.cnblogs.com/liongis/p/17832900.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号