简介

程序基于Python3.7开发的斗地主AI出牌助手,目前支持欢乐斗地主桌面版,微信版,也可以自己制作相应其他版本。

此出牌助手核心是识别出三位玩家出牌内容,调用基于DouZero封装的API接口,输入出牌内容,根据AI出牌方案,打出相应的牌。

运行效果

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

核心功能

  • 手牌和位置识别

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

素材准备

  • 区域定位,获取坐标值

  • 按钮及牌面

核心代码

  • 根据指定窗口句柄截图

    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":''#三张底牌
    }

可用的 DouZero 后端地址

免责声明

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

参考项目

斗地主AI出牌助手--在线调用斗地主AI,实现自动斗地主的更多相关文章

  1. Unity3D手机斗地主游戏开发实战(04)_出牌判断大小(已完结)

    之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...

  2. Unity3D手机斗地主游戏开发实战(04)_出牌判断大小

    之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...

  3. Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)

    Hi,之前有同学说要我把源码发出来,那我就把半成品源码的链接放在每篇文件的最后,有兴趣的话可以查阅参考,有问题可以跟我私信,也可以关注我的个人公众号,互相交流嘛.当然,代码也是在不断的持续改进中~ 上 ...

  4. Android斗地主棋牌游戏牌桌实现源码下载

    本次给大家分享下Android斗地主棋牌游戏牌桌实现源码下载如下: 为了节约内存资源,每张扑克牌都是剪切形成的,当然这也是当前编程的主流方法. 1.主Activity package com.biso ...

  5. Java学习笔记34(集合框架八:综合案例:模拟斗地主的洗牌发牌)

    规则: 1.54张扑克牌,有花色 2.顺序打乱,一人一张依次发牌,一人17张,留三张作为底牌 3.看牌:按大小王2A....43的序排列打印 示例: package demo; import java ...

  6. 使用javascript随机生成斗地主玩家手牌

    学习javascript估摸着有半个多月了,好歹自己有过编程基础,学的还算轻松,不过js里的面向对象是真的打脑壳,但都但不懂,和我以前学过的c#简直相差太远 今天写了个随机生成斗地主玩家手牌的代码,自 ...

  7. java 模拟斗地主发牌洗牌

    一 模拟斗地主洗牌发牌 1.案例需求 按照斗地主的规则,完成洗牌发牌的动作. 具体规则: 1. 组装54张扑克牌 2. 将54张牌顺序打乱 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张 ...

  8. 百度AI开放平台- API实战调用

    百度AI开放平台- API实战调用 一.      前言 首先说一下项目需求. 两个用户,分别上传了两段不同的文字,要计算两段文字相似度有多少,匹配数据库中的符合条件的数据,初步估计列出来会有60-1 ...

  9. AI智能问答助手 AI智能批量文章生成器 网站优化SEO批量内容生成工具 原创文章生成软件

    <AI智能问答助手>   软件基于当下热门的OpenAI的ChatGPT技术,导入问题列表就可以批量生成对应的内容,内容质量高.原创度高.适合对内容生成需求量大的场景,如网站优化.广告文案 ...

  10. 百度大脑发布“AI开发者‘战疫’守护计划”,AI支援抗疫再升级

    面对新冠肺炎疫情,AI开发者们正在积极运用算法.算力.软件等“武器”助力抗疫.针对开发者们在疫情防控期间的开发与学习需求,2月6日,百度大脑推出“AI开发者‘战疫’守护计划”, 正在进行疫情防控相关应 ...

随机推荐

  1. redis的一些简单操作(针对key)

    redis默认16个数据,默认使用0号 select为切换数据库的关键字 select 1  切换数据库 设置值 set k1 lucy       key为 k1  value 为 lucy 查看全 ...

  2. mysql创建可以让Django链接的用户名

    输入以下命令: 1 grant all privileges on 库名.* to 账户名@'%' identified by 'password'; 2 flush privileges;

  3. 人工智能如何应对 DevOps 监控和可观测性挑战

    自 ChatGPT 横空出世之后,AIGC 已成为不可逆转的时代浪潮.在之前的文章中,我们介绍了DevOps 领域中AI的用例,需要回顾可以点击下方链接.在本篇文章中,我将简单聊聊人工智能(AI)如何 ...

  4. Python3入门基础教程

    引:此文是自己学习python过程中的笔记和总结,适合有语言基础的人快速了解python3和没基础的作为学习的大纲,了解学习的方向.知识点:笔记是从多本书和视频上学习后的整合版. (一)初识pytho ...

  5. 青少年CTF平台 Web签到

    题目说明 Web一星简单题,Web签到. 直接启动环境,等待30秒左右访问题目链接. 做题过程 进入后,题目好像没有告诉我们什么有用的信息, F12,看遍了题目源码,也没有发现flag,正当我怀疑这个 ...

  6. 基于consul实现docker跨主机网络通信

    前言 IP: 192.168.0.10 192.168.0.11 系统版本:ubuntu 20.04 consul版本:1.11.1 官网下载地址: https://www.consul.io/dow ...

  7. [go笔记]websocket入门

    简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket让客户端和服务端之间的数据交换变得非常简单,且允许服务器主动向客户端推送数据,并且之后客户端和服务端所有的通信都 ...

  8. Web通用漏洞--文件上传

    Web通用漏洞--文件上传 概述 文件上传安全指的是攻击者通过利用上传实现后门的写入连接后门进行权限控制的安全问题,对于如何确保这类安全问题,一般会从原生态功能中的文件内容,文件后缀,文件类型等方面判 ...

  9. Web通用漏洞--RCE

    Web通用漏洞--RCE 漏洞简介 RCE远程代码/命令执行漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统. RCE漏洞也分为代码执行漏洞和命令执行漏洞,所谓代码执行 ...

  10. React Router 6 快速上手

    1.概述 React Router 以三个不同的包发布到 npm 上,它们分别为: react-router: 路由的核心库,提供了很多的:组件.钩子. react-router-dom: 包含rea ...