前言
最近刷抖音,老是会碰到那种斗地主残局的直播或者视频,今天刚好礼拜六,又不忙,那反正闲来无事,不如写点东西玩一下。于是我就看到了在斗地主的同事,他每天就只能领低保,反正打不过别人就去破解残局!但是他连一些网友都打不过。怎么可能破解残局呢,所以我就写了个AI自动出牌的脚本,大家可以拿去赚豆子了,再也不用靠低保才能玩两把了
下面,我们开始介绍这个AI出牌器的制作过程。
一、核心功能设计
首先我们这款出牌器是基于DouZero开发的,核心是需要利用训练好的AI模型来帮住我们,给出最优出牌方案。
其次关于出牌器,先要需要确认一个AI出牌角色,代表我们玩家自己。我们只要给这个AI输入玩家手牌和三张底牌。确认好地主和农民的各个角色,告诉它三个人对应的关系,这样就可以确定队友和对手。我们还要将每一轮其他两人的出牌输入,这样出牌器就可以根据出牌数据,及时提供给我们最优出牌决策,带领我们取得胜利!
那么如何获取三者之间的关系呢?谁是地主?谁是农民?是自己一人作战还是农民合作?自己玩家的手牌是什么?三张底牌是什么?这些也都需要在开局后确认好。
拆解需求,大致可以整理出核心功能如下:
UI设计排版布局
-
显示三张底牌
-
显示AI角色出牌数据区域,上家出牌数据区域,下家出牌数据区域,本局胜率区域
-
AI玩家手牌区域
-
AI出牌器开始停止
手牌和出牌数据识别
-
游戏刚开始根据屏幕位置,截图识别AI玩家手牌及三张底牌
-
确认三者之间的关系,识别地主和农民角色,确认队友及对手关系
-
识别每轮三位玩家依次出了什么牌,刷新显示对应区域
AI出牌方案输出
-
加载训练好的AI模型,初始化游戏环境
-
每轮出牌判断,根据上家出牌数据给出最优出牌决策
-
自动刷新玩家剩余手牌和本局胜率预测
二、实现步骤
-
UI设计排版布局
根据上述功能,我们首先考虑进行简单的UI布局设计,这里我们使用的是pyqt5。核心设计代码如下:
def setupUi(self, Form): Form.setObjectName("Form") Form.resize(440, 395) font = QtGui.QFont() font.setFamily("Arial") font.setPointSize(9) font.setBold(True) font.setItalic(False) font.setWeight(75) Form.setFont(font) self.WinRate = QtWidgets.QLabel(Form) self.WinRate.setGeometry(QtCore.QRect(240, 180, 171, 61)) font = QtGui.QFont() font.setPointSize(14) self.WinRate.setFont(font) self.WinRate.setAlignment(QtCore.Qt.AlignCenter) self.WinRate.setObjectName("WinRate") self.InitCard = QtWidgets.QPushButton(Form) self.InitCard.setGeometry(QtCore.QRect(60, 330, 121, 41)) font = QtGui.QFont() font.setFamily("Arial") font.setPointSize(14) font.setBold(True) font.setWeight(75) self.InitCard.setFont(font) self.InitCard.setStyleSheet("") self.InitCard.setObjectName("InitCard") self.UserHandCards = QtWidgets.QLabel(Form) self.UserHandCards.setGeometry(QtCore.QRect(10, 260, 421, 41)) font = QtGui.QFont() font.setPointSize(14) self.UserHandCards.setFont(font) self.UserHandCards.setAlignment(QtCore.Qt.AlignCenter) self.UserHandCards.setObjectName("UserHandCards") self.LPlayer = QtWidgets.QFrame(Form) self.LPlayer.setGeometry(QtCore.QRect(10, 80, 201, 61)) self.LPlayer.setFrameShape(QtWidgets.QFrame.StyledPanel) self.LPlayer.setFrameShadow(QtWidgets.QFrame.Raised) self.LPlayer.setObjectName("LPlayer") self.LPlayedCard = QtWidgets.QLabel(self.LPlayer) self.LPlayedCard.setGeometry(QtCore.QRect(0, 0, 201, 61)) font = QtGui.QFont() font.setPointSize(14) self.LPlayedCard.setFont(font) self.LPlayedCard.setAlignment(QtCore.Qt.AlignCenter) self.LPlayedCard.setObjectName("LPlayedCard") self.RPlayer = QtWidgets.QFrame(Form) self.RPlayer.setGeometry(QtCore.QRect(230, 80, 201, 61)) font = QtGui.QFont() font.setPointSize(16) self.RPlayer.setFont(font) self.RPlayer.setFrameShape(QtWidgets.QFrame.StyledPanel) self.RPlayer.setFrameShadow(QtWidgets.QFrame.Raised) self.RPlayer.setObjectName("RPlayer") self.RPlayedCard = QtWidgets.QLabel(self.RPlayer) self.RPlayedCard.setGeometry(QtCore.QRect(0, 0, 201, 61)) font = QtGui.QFont() font.setPointSize(14) self.RPlayedCard.setFont(font) self.RPlayedCard.setAlignment(QtCore.Qt.AlignCenter) self.RPlayedCard.setObjectName("RPlayedCard") self.Player = QtWidgets.QFrame(Form) self.Player.setGeom