继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

斗地主AI算法——第十四章の主动出牌(3)

九日王朝
关注TA
已关注
手记 180
粉丝 42
获赞 185

上一章已经排除了飞机、三带等牌型,那么除去炸弹王炸以外,我们只剩下单牌、对牌、三牌以及单顺、双顺、三顺了。


首先说单牌、对牌、三牌。其逻辑基本一样,只是出牌的个数有差别,即:如果该i牌数量满足这种牌型要求,即先打出,计算其剩余价值。


			//出单牌			if (clsHandCardData.value_aHandCardList[i] > 0)			{				clsHandCardData.value_aHandCardList[i]--;				clsHandCardData.nHandCardCount--;				HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);				clsHandCardData.value_aHandCardList[i]++;				clsHandCardData.nHandCardCount++;				if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))				{					BestHandCardValue = tmpHandCardValue;					BestCardGroup= get_GroupData(cgSINGLE, i, 1);				}			}			//出对牌			if (clsHandCardData.value_aHandCardList[i] > 1)			{				//尝试打出一对牌,估算剩余手牌价值				clsHandCardData.value_aHandCardList[i] -= 2;				clsHandCardData.nHandCardCount -= 2;				HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);				clsHandCardData.value_aHandCardList[i] += 2;				clsHandCardData.nHandCardCount += 2;				//选取总权值-轮次*7值最高的策略  因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正				if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))				{					BestHandCardValue = tmpHandCardValue;					BestCardGroup = get_GroupData(cgDOUBLE, i, 2);				}			}			//出三牌			if (clsHandCardData.value_aHandCardList[i] > 2)			{				clsHandCardData.value_aHandCardList[i] -= 3;				clsHandCardData.nHandCardCount -= 3;				HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);				clsHandCardData.value_aHandCardList[i] += 3;				clsHandCardData.nHandCardCount += 3;				//选取总权值-轮次*7值最高的策略  因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正				if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))				{					BestHandCardValue = tmpHandCardValue;					BestCardGroup = get_GroupData(cgTHREE, i, 3);				}			}


至于顺子的算法,和被动出牌的有一点点差别,就是因为没有了数量限制,所以需要遍历以i牌为起点可以组成的所有顺子。



//出单顺			if (clsHandCardData.value_aHandCardList[i] > 0)			{				int prov = 0;				for (int j = i; j < 15; j++)				{					if(clsHandCardData.value_aHandCardList[j]>0)					{						prov++;					}					else					{						break;					}					if (prov >= 5)					{						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] --;						}						clsHandCardData.nHandCardCount -= prov;						HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] ++;						}						clsHandCardData.nHandCardCount += prov;						//选取总权值-轮次*7值最高的策略  因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正						if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))						{							BestHandCardValue = tmpHandCardValue;							BestCardGroup = get_GroupData(cgSINGLE_LINE, j, prov);						}					}				}							}			//出双顺			if (clsHandCardData.value_aHandCardList[i] > 1)			{				int prov = 0;				for (int j = i; j < 15; j++)				{					if (clsHandCardData.value_aHandCardList[j]>1)					{						prov++;					}					else					{						break;					}					if (prov >= 3)					{						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] -=2;						}						clsHandCardData.nHandCardCount -= prov*2;						HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] +=2;						}						clsHandCardData.nHandCardCount += prov*2;						//选取总权值-轮次*7值最高的策略  因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正						if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))						{							BestHandCardValue = tmpHandCardValue;							BestCardGroup = get_GroupData(cgDOUBLE_LINE, j, prov*2);						}					}				}			}			//出三顺			if(clsHandCardData.value_aHandCardList[i] > 2)			{				int prov = 0;				for (int j = i; j < 15; j++)				{					if (clsHandCardData.value_aHandCardList[j]>2)					{						prov++;					}					else					{						break;					}					if (prov >= 2)					{						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] -= 3;						}						clsHandCardData.nHandCardCount -= prov * 3;						HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);						for (int k = i; k <= j; k++)						{							clsHandCardData.value_aHandCardList[k] += 3;						}						clsHandCardData.nHandCardCount += prov * 3;						//选取总权值-轮次*7值最高的策略  因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正						if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7)))						{							BestHandCardValue = tmpHandCardValue;							BestCardGroup = get_GroupData(cgTHREE_LINE, j, prov * 3);						}					}				}			}


因为本策略是必须解决掉至少一个i牌的,所以出牌操作放在循环内进行,也就是说,只要你不是炸3,若你手牌有3,在处理3时一定会return  就绝对不会再走到4。




if (BestCardGroup.cgType == cgERROR)			{			}			else if (BestCardGroup.cgType == cgSINGLE)			{				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgDOUBLE)			{				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE)			{				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgSINGLE_LINE)			{				for (int j = BestCardGroup.nMaxCard- BestCardGroup.nCount+1; j <= BestCardGroup.nMaxCard; j++)				{					clsHandCardData.value_nPutCardList.push_back(j);				}				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgDOUBLE_LINE)			{				for (int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount/2) + 1; j <= BestCardGroup.nMaxCard; j++)				{					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);				}				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE_LINE)			{				for (int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount / 3) + 1; j <= BestCardGroup.nMaxCard; j++)				{					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);				}				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE_TAKE_ONE)			{				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(tmp_1);				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO)			{				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(BestCardGroup.nMaxCard);				clsHandCardData.value_nPutCardList.push_back(tmp_1);				clsHandCardData.value_nPutCardList.push_back(tmp_1);				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE_TAKE_ONE_LINE)			{				for (int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount / 4) + 1; j <= BestCardGroup.nMaxCard; j++)				{					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);				}				if (BestCardGroup.nCount / 4 == 2)				{					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_2);				}				if (BestCardGroup.nCount / 4 == 3)				{					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_2);					clsHandCardData.value_nPutCardList.push_back(tmp_3);				}				if (BestCardGroup.nCount / 4 == 4)				{					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_2);					clsHandCardData.value_nPutCardList.push_back(tmp_3);					clsHandCardData.value_nPutCardList.push_back(tmp_4);				}				clsHandCardData.uctPutCardType = BestCardGroup;			}			else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO_LINE)			{				for (int j = BestCardGroup.nMaxCard - (BestCardGroup.nCount / 5) + 1; j <= BestCardGroup.nMaxCard; j++)				{					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);					clsHandCardData.value_nPutCardList.push_back(j);				}				if (BestCardGroup.nCount / 5 == 2)				{					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_2);					clsHandCardData.value_nPutCardList.push_back(tmp_2);				}				if (BestCardGroup.nCount / 5 == 3)				{					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_1);					clsHandCardData.value_nPutCardList.push_back(tmp_2);					clsHandCardData.value_nPutCardList.push_back(tmp_2);					clsHandCardData.value_nPutCardList.push_back(tmp_3);					clsHandCardData.value_nPutCardList.push_back(tmp_3);				}				clsHandCardData.uctPutCardType = BestCardGroup;			}			return;



至此,主动出牌的所有逻辑均已实现,同时整个斗地主算法也基本完成了。接下来我们便可写一些测试模块来进行整合联调。


敬请关注下一章:斗地主AI算法——第十五章の测试模块

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP