斗地主老输?叫你赢欢乐豆

sw

最近在网上看到一个有意思的开源项目,快手团队开发的开源AI斗地主——DouZero。今天我们就一起来学习制作一个基于DouZero的欢乐斗地主出牌器,看看AI是如何来帮助我们斗地主,赢欢乐豆,实现财富自由的吧!

首先一起来看看AI斗地主出牌器的效果:

下面,我们开始介绍这个AI出牌器的制作过程。

一、核心功能设计

首先我们这款出牌器是基于DouZero开发的,核心是需要利用训练好的AI模型来帮住我们,给出最优出牌方案。

其次关于出牌器,先要需要确认一个AI出牌角色,代表我们玩家自己。我们只要给这个AI输入玩家手牌和三张底牌。确认好地主和农民的各个角色,告诉它三个人对应的关系,这样就可以确定队友和对手。我们还要将每一轮其他两人的出牌输入,这样出牌器就可以根据出牌数据,及时提供给我们最优出牌决策,带领我们取得胜利!

那么如何获取三者之间的关系呢?谁是地主?谁是农民?是自己一人作战还是农民合作?自己玩家的手牌是什么?三张底牌是什么?这些也都需要在开局后确认好。

拆解需求,大致可以整理出核心功能如下:

UI设计排版布局显示三张底牌显示AI角色出牌数据区域,上家出牌数据区域,下家出牌数据区域,本局胜率区域AI玩家手牌区域AI出牌器开始停止

手牌和出牌数据识别游戏刚开始根据屏幕位置,截图识别AI玩家手牌及三张底牌确认三者之间的关系,识别地主和农民角色,确认队友及对手关系识别每轮三位玩家依次出了什么牌,刷新显示对应区域

AI出牌方案输出加载训练好的AI模型,初始化游戏环境每轮出牌判断,根据上家出牌数据给出最优出牌决策自动刷新玩家剩余手牌和本局胜率预测

二、实现步骤

1.UI设计排版布局

根据上述功能,我们首先考虑进行简单的UI布局设计,这里我们使用的是pyqt5。核心设计代码如下:

defsetupUi(self,Form):("Form")(440,395)font=()("Arial")(9)(True)(False)(75)(font)=(Form)((240,180,171,61))font=()(14)(font)()("WinRate")=(Form)((60,330,121,41))font=()("Arial")(14)(True)(75)(font)("")("InitCard")=(Form)((10,260,421,41))font=()(14)(font)()("UserHandCards")=(Form)((10,80,201,61))()()("LPlayer")=()((0,0,201,61))font=()(14)(font)()("LPlayedCard")=(Form)((230,80,201,61))font=()(16)(font)()()("RPlayer")=()((0,0,201,61))font=()(14)(font)()("RPlayedCard")=(Form)((40,180,171,61))()()("Player")=()((0,0,171,61))font=()(14)(font)()("PredictedCard")=(Form)((140,10,161,41))font=()(16)(font)()("ThreeLandlordCards")=(Form)((260,330,111,41))font=()("Arial")(14)(True)(75)(font)("")("Stop")(Form)(_cards)()(Form)defretranslateUi(self,Form):_translate=(_translate("Form","AI欢乐斗地主--Dragon少年"))(_translate("Form","胜率:--%"))(_translate("Form","开始"))(_translate("Form","手牌"))(_translate("Form","上家出牌区域"))(_translate("Form","下家出牌区域"))(_translate("Form","AI出牌区域"))(_translate("Form","三张底牌"))(_translate("Form","停止"))123456789101112819202122232425262728293033738394044748495055758596061626364656667686970777787980887888990919293949596979899100101102103104105106107

实现效果如下:

2.手牌和出牌数据识别

下面我们需要所有扑克牌的模板图片与游戏屏幕特定区域的截图进行对比,这样才能获取AI玩家手牌、底牌、每一轮出牌、三者关系(地主、地主上家、地主下家)。

识别AI玩家手牌及三张底牌:

我们可以截取游戏屏幕,根据固定位置来识别当前AI玩家的手牌和三张底牌。核心代码如下:

“是新的”标志forhaveinlocList:ifabs(e[0]-have)=distance:flag=0breakifflag:count+=1(e[0])returncount获取地主三张底牌deffind_three_landlord_cards(self,pos):three_landlord_cards_real=""img=(region=pos)img=((349,168))forcardinAllCards:result=(needleImage='pics/o'+card+'.png',haystackImage=img,confidence=)three_landlord_cards_real+=card[1]*_filter(list(result),)returnthree_landlord_cards_real1234567891011128192021222324252627282930337

效果如下所示:

地主、地主上家、地主下家:

同理我们可以根据游戏屏幕截图,识别地主的图标,确认地主角色。核心代码如下:

坐标=(414,804,1041,59)左侧玩家截图区域=(1010,470,380,160)地主标志截图区域(右-我-左)=(817,36,287,136)玩家手牌_hand_cards_real=""_hand_cards_env=[]其他玩家手牌(整副牌减去玩家手牌,后续再减掉历史出牌)_hand_cards=[]玩家角色代码:0-地主上家,1-地主,2-地主下家_position_code=_position=""出牌顺序:0-玩家出牌,1-玩家下家出牌,2-玩家上家出牌_order=0=None识别三张底牌_landlord_cards_real=_three_landlord_cards()("底牌:"+_landlord_cards_real)_landlord_cards_env=[RealCard2EnvCard[c]forcinlist(_landlord_cards_real)]整副牌减去玩家手上的牌,就是其他人的手牌,再分配给另外两个角色(如何分配对AI判断没有影响)foriinset(AllEnvCard):_hand_([i]*((i)-_hand_cards_(i)))_play_data_({'three_landlord_cards':_landlord_cards_env,['landlord_up','landlord','landlord_down'][(_position_code+0)%3]:_hand_cards_env,['landlord_up','landlord','landlord_down'][(_position_code+1)%3]:_hand_cards[0:17]if(_position_code+1)%3!=1_hand_cards[17:],['landlord_up','landlord','landlord_down'][(_position_code+2)%3]:_hand_cards[0:17]if(_position_code+1)%3==1_hand_cards[17:]})print(_play_data_list)得到出牌顺序_order=0_position=="landlord"_position=="landlord_up"else21234567891011128192021222324252627282930337383940447484950557585960616263646566676869707172737475

效果如下:

3.AI出牌方案输出

下面我们就需要用到DouZero开源的AI斗地主了。DouZero项目地址:。我们需要将该开源项目下载并导入项目中。

创建一个AI玩家角色,初始化游戏环境,加载模型,进行每轮的出牌判断,控制一局游戏流程的进行和结束。核心代码如下:

初始化游戏环境=GameEnv(ai_players)玩家出牌时就通过智能体获取action,否则通过识别获取其他玩家出牌_order==0:("")action_message=(_position)不出pass_flag=('pics/',region=,confidence=)识别下家出牌_played_cards_real=_other_cards()更新界面(_played_cards__played_cards_realelse"不出")_order=2_order==2:("")_white()==0and\('pics/',region=,confidence=):print("等待上家出牌")()()500:(,50)()()500:(,50)未找到"不出"ifpass_flagisNone:找到"不出"else:_played_cards_real=""print("\n上家出牌:",_played_cards_real)_played_cards_env=[RealCard2EnvCard[c]forcinlist(_played_cards_real)](_position,_played_cards_env)_order=0#更新界面(_played_cards__played_cards_realelse"不出")else:()()100:(,50)print("{}胜,本局结束!\n".format("农民"=="farmer"else"地主"))(self,"本局结束","{}胜!".format("农民"=="farmer"else"地主"),,)()_display()123456789101112819202122232425262728293033738394044748495055758596061626364656667686970777787980887888990919293949596979899100101102103104105106107108109

到这里,整个AI斗地主出牌流程基本已经完成了。

文章版权声明:除非注明,否则均为虚境探索者原创文章,转载或复制请以超链接形式并注明出处。

上一个 回合制RPG游戏推荐 不容错过的经典大作

下一个 两只企鹅在游戏里秀恩爱的下场是什么?