为了账号安全,请及时绑定邮箱和手机立即绑定

斗地主AI算法——第七章の被动出牌(1)

标签:
算法

哎,之前扯了那么多蛋,终于讲出牌了!

https://img1.sycdn.imooc.com//5b4eff520001eab000650067.jpg

本章开始讲被动出牌的逻辑算法。首先我们先把架子搭起来,被动出牌我们肯定是要知道场上目前打出的是什么牌型。

在第二章数据结构里我们定义过,游戏全局类里面有一个存放当前牌型结构的成员,即


	//当前打出牌的类型数据,被动出牌时玩家根据这里做出筛选	CardGroupData uctNowCardGroup;


我们即将通过他进行类型的筛选,所以肯定是要枚举各类牌型的,也就是这个样子的。


https://img1.sycdn.imooc.com//5b4eff650001fe1205270492.jpg



是的不要质疑!就是这个样子的~~

https://img1.sycdn.imooc.com//5b4eff740001eab000650067.jpg


当然了,虽然是2.0初级版,我们还是要给予一定的灵性的,比如说当最后只剩两手牌且存在王炸的话,王炸优先出。


	/*王炸——当前策略只处理王炸作为倒数第二手的优先出牌逻辑,后续版本会在此基础上优化*/	if (clsHandCardData.value_aHandCardList[17] > 0 && clsHandCardData.value_aHandCardList[16] > 0)	{		clsHandCardData.value_aHandCardList[17] --;		clsHandCardData.value_aHandCardList[16] --;		clsHandCardData.nHandCardCount -= 2;		HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);		clsHandCardData.value_aHandCardList[16] ++;		clsHandCardData.value_aHandCardList[17] ++;		clsHandCardData.nHandCardCount += 2;		if (tmpHandCardValue.NeedRound == 1)		{			clsHandCardData.value_nPutCardList.push_back(17);			clsHandCardData.value_nPutCardList.push_back(16);			clsHandCardData.uctPutCardType = clsGameSituation.uctNowCardGroup = get_GroupData(cgKING_CARD, 17, 2);			return;		}	}


算法思路:若存在手牌17(大王)和16(小王),那么先去除这两张牌


然后通过get_HandCardValue获取剩余轮次。

再回溯到原有状态。若只剩一手,则打出王炸。

出牌的操作也很简单,将需要打出的牌进入clsHandCardData.value_nPutCardList数组,且通过第四章提到的get_GroupData函数获取类型结构再赋值给手牌类以及游戏全局类相应的成员变量。当确定好出牌策略后,直接return。因为被动出牌的分支只会走一个,为了节约时间,所以每个分支里都有return,若没有走入任何分支则视为错误数据。


我们先把最简单的类型写出来,就是别人出王炸时的策略。

	//王炸类型 人都王炸了你还出个毛	else if (clsGameSituation.uctNowCardGroup.cgType == cgKING_CARD)	{		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}



怎么样,是不是很简单?

https://img1.sycdn.imooc.com//5b4eff810001eab000650067.jpg


若不出牌,我们只更新自己手牌类型就好了。若出牌时,不但要更新自己手牌信息,也要更新游戏全局类里面的当前出牌信息。不过我更推荐后期嵌入的时候通过服务器来获取当前出牌的信息。比如我的测试函数里会加上:


		if (arrHandCardData[indexID].uctPutCardType.cgType != cgZERO)		{			clsGameSituation.nCardDroit = indexID;			clsGameSituation.uctNowCardGroup = arrHandCardData[indexID].uctPutCardType;		}


另外,出牌前记得清空一下出牌序列,就是在一开始加:


clsHandCardData.ClearPutCardList();



所以,整个函数的架子是这样的,假设我们啥都管不上。


/*2.0版本策略  根据场上形势决定当前预打出的手牌——被动出牌*/void get_PutCardList_2_limit(GameSituation &clsGameSituation, HandCardData &clsHandCardData){	clsHandCardData.ClearPutCardList();	/*王炸——当前策略只处理王炸作为倒数第二手的优先出牌逻辑,后续版本会在此基础上优化*/	if (clsHandCardData.value_aHandCardList[17] > 0 && clsHandCardData.value_aHandCardList[16] > 0)	{		clsHandCardData.value_aHandCardList[17] --;		clsHandCardData.value_aHandCardList[16] --;		clsHandCardData.nHandCardCount -= 2;		HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);		clsHandCardData.value_aHandCardList[16] ++;		clsHandCardData.value_aHandCardList[17] ++;		clsHandCardData.nHandCardCount += 2;		if (tmpHandCardValue.NeedRound == 1)		{			clsHandCardData.value_nPutCardList.push_back(17);			clsHandCardData.value_nPutCardList.push_back(16);			clsHandCardData.uctPutCardType = clsGameSituation.uctNowCardGroup = get_GroupData(cgKING_CARD, 17, 2);			return;		}	}	//错误牌型  不出	if (clsGameSituation.uctNowCardGroup.cgType == cgERROR)	{		clsHandCardData.uctPutCardType = get_GroupData(cgERROR, 0, 0);		return;	}	//不出牌型,在被动出牌策略里也是错误数据 不出	else if (clsGameSituation.uctNowCardGroup.cgType == cgZERO)	{		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//单牌类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgSINGLE)	{	//管不上	clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;			}	//对牌类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgDOUBLE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三牌类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//单连类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgSINGLE_LINE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//对连类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgDOUBLE_LINE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三连类型	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE_LINE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三带一单	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE_TAKE_ONE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三带一对	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE_TAKE_TWO)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三带一单连	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE_TAKE_ONE_LINE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//三带一对连	else if (clsGameSituation.uctNowCardGroup.cgType == cgTHREE_TAKE_TWO_LINE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//四带两单	else if (clsGameSituation.uctNowCardGroup.cgType == cgFOUR_TAKE_ONE)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//四带两对	else if (clsGameSituation.uctNowCardGroup.cgType == cgFOUR_TAKE_TWO)	{		//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//炸弹类型 	else if (clsGameSituation.uctNowCardGroup.cgType == cgBOMB_CARD)	{			//管不上		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;		}	//王炸类型 人都王炸了你还出个毛	else if (clsGameSituation.uctNowCardGroup.cgType == cgKING_CARD)	{		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);		return;	}	//异常处理 不出	else	{		clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);	}	return;}



当然,啥都管不上肯定是不行的,所以接下来我们会填充各种牌型的策略算法。


敬请关注下一章:斗地主AI算法——第八章の被动出牌(2)


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消