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

举报
九日王朝 发表于 2019/01/22 12:01:50 2019/01/22
【摘要】 上一章已经排除了飞机、三带等牌型,那么除去炸弹王炸以外,我们只剩下单牌、对牌、三牌以及单顺、双顺、三顺了。首先说单牌、对牌、三牌。其逻辑基本一样,只是出牌的个数有差别,即:如果该i牌数量满足这种牌型要求,即先打出,计算其剩余价值。 //出单牌 if (clsHandCardData.value_aHandCardList[i] > 0) { clsHandCardData....

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




首先说单牌、对牌、三牌。其逻辑基本一样,只是出牌的个数有差别,即:如果该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算法——第十五章の测试模块



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。