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

核心功能
- 手牌和位置识别
- 游戏刚开始根据屏幕位置,截图识别AI玩家手牌及三张底牌
- 根据玩家手牌判断是否抢地主和加倍
- 确认三者之间的关系,识别地主和农民角色,确认队友及对手关系
- 识别每轮三位玩家出牌
- 根据提示按钮,判断当前的操作
- 识别三位玩家此轮出的牌,并记录下来
- AI出牌方案输出
- 将出牌记录按格式要求发送给斗地主AI
- 获取斗地主AI出牌方案,选取最高胜率方案
- 根据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 后端地址
- 快手的 DouZero
https://douzero.org:5000/predict - 网易的 PerfectDou
https://outer-perfectdou-demo-gzailab.nie.netease.com:10074/predict - 也可根据 RLCard-Showdown 自行搭建本地运行的后端服务
免责声明
本程序仅供娱乐和学习使用,不得用于任何非法用途
参考项目
- DouZero:https://github.com/kwai/DouZero
- PerfectDou:https://github.com/Netease-Games-AI-Lab-Guangzhou/PerfectDou
- rlcard-showdown:https://github.com/datamllab/rlcard-showdown
- DouZero_For_HLDDZ_FullAuto: https://github.com/Vincentzyx/DouZero_For_HLDDZ_FullAuto
斗地主AI出牌助手--在线调用斗地主AI,实现自动斗地主的更多相关文章
- Unity3D手机斗地主游戏开发实战(04)_出牌判断大小(已完结)
之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...
- Unity3D手机斗地主游戏开发实战(04)_出牌判断大小
之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...
- Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)
Hi,之前有同学说要我把源码发出来,那我就把半成品源码的链接放在每篇文件的最后,有兴趣的话可以查阅参考,有问题可以跟我私信,也可以关注我的个人公众号,互相交流嘛.当然,代码也是在不断的持续改进中~ 上 ...
- Android斗地主棋牌游戏牌桌实现源码下载
本次给大家分享下Android斗地主棋牌游戏牌桌实现源码下载如下: 为了节约内存资源,每张扑克牌都是剪切形成的,当然这也是当前编程的主流方法. 1.主Activity package com.biso ...
- Java学习笔记34(集合框架八:综合案例:模拟斗地主的洗牌发牌)
规则: 1.54张扑克牌,有花色 2.顺序打乱,一人一张依次发牌,一人17张,留三张作为底牌 3.看牌:按大小王2A....43的序排列打印 示例: package demo; import java ...
- 使用javascript随机生成斗地主玩家手牌
学习javascript估摸着有半个多月了,好歹自己有过编程基础,学的还算轻松,不过js里的面向对象是真的打脑壳,但都但不懂,和我以前学过的c#简直相差太远 今天写了个随机生成斗地主玩家手牌的代码,自 ...
- java 模拟斗地主发牌洗牌
一 模拟斗地主洗牌发牌 1.案例需求 按照斗地主的规则,完成洗牌发牌的动作. 具体规则: 1. 组装54张扑克牌 2. 将54张牌顺序打乱 3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张 ...
- 百度AI开放平台- API实战调用
百度AI开放平台- API实战调用 一. 前言 首先说一下项目需求. 两个用户,分别上传了两段不同的文字,要计算两段文字相似度有多少,匹配数据库中的符合条件的数据,初步估计列出来会有60-1 ...
- AI智能问答助手 AI智能批量文章生成器 网站优化SEO批量内容生成工具 原创文章生成软件
<AI智能问答助手> 软件基于当下热门的OpenAI的ChatGPT技术,导入问题列表就可以批量生成对应的内容,内容质量高.原创度高.适合对内容生成需求量大的场景,如网站优化.广告文案 ...
- 百度大脑发布“AI开发者‘战疫’守护计划”,AI支援抗疫再升级
面对新冠肺炎疫情,AI开发者们正在积极运用算法.算力.软件等“武器”助力抗疫.针对开发者们在疫情防控期间的开发与学习需求,2月6日,百度大脑推出“AI开发者‘战疫’守护计划”, 正在进行疫情防控相关应 ...
随机推荐
- 小白终于解决了在学习Go中不知道Makefile是什么的难题
如何在Go中使用Makefile 1.Makefile是什么 Makefile是一种构建工具,用于在项目中定义和执行一系列命令.它通常包含了一些规则和目标,用于编译.测试.运行和清理项目. 2.Mak ...
- 从MybatisPlus回归Mybatis
从MybatisPlus回归Mybatis 之前写项目一直习惯使用MyBatisPlus,单表查询很方便:两张表也很方便,直接业务层处理两张表的逻辑.但什么都图方便只会害了你. 但连接的表比较复杂的时 ...
- 部署安装zookeeper集群
版本:3.7.0 节点IP: 172.50.13.103 172.50.13.104 172.50.13.105 获取安装包: wget http://mirrors.ustc.edu.cn/apac ...
- Mybatis框架的搭建和基本使用
本文总结最原始Mybatis框架的搭建和最基本使用(不涉及Spring框架体系). 1 依赖 首先,我们要引入Mybatis依赖: <dependency> <groupId> ...
- MyBatis Mapper映射处理CLOB和BLOB类型
Mybatis的MapperXML映射文件应该处理数据库字段类型为CLOB和BLOB类型的数据呢?首先我们先看下CLOB和BLOB这两种数据类型的介绍. 介绍 使用Mybatis时涉及到两种特殊类型 ...
- Avalonia 实现聊天消息渲染、图文混排(支持Windows、Linux、信创国产OS)
在实现即时通讯软件或聊天软件时,渲染文字表情.图文混排是一项非常繁琐的工作,再加上还要支持GIF动图.引用消息.撤回消息.名片等不同样式的消息渲染时,就更加麻烦了. 好在我们可以使用 ESFra ...
- 从头到尾说一次 Spring 事务管理(器)
事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一. 本文会从设计角度,一步步的剖析 Spring 事务管理的设计思路(都会设计事务管理器了,还能玩不转?) 为什么需要事务管理? 先看看 ...
- 领域驱动设计(DDD):三层架构到DDD架构演化
三层架构的问题 在前文中,我从基础代码的角度探讨了如何运用领域驱动设计(DDD)来实现高内聚低耦合的代码.本篇文章将从项目架构的角度,继续探讨三层架构与DDD之间的演化过程,以及DDD如何优化架构的问 ...
- 使用阿里云ECS和RDS搭建个人博客
一.ECS实例配置 1.重置云服务器ECS密码 前往ECS控制台,点击实例,找到刚才开通的ECS实例(找不到的话就看一下上方的地区是否是你的服务器的地域),点击右侧操作栏中的三个点,找到重置实例密码, ...
- 入门篇-其之一-第一个Java程序
️注意: 本文中包含实际操作,需要安装JDK.如果需要安装JDK,请按照这篇文章的步骤进行安装:点我查看JDK安装教程 小白可以多看几遍这篇文章,多敲几次代码 前面我们已经安装了JDK,接下来就是写一 ...