转载请标明出处:https://blog.youkuaiyun.com/sm9sun/article/details/70859367 文章出自:九日王朝
上一章我们已经搭好了出牌算法的基本框架,本章主要实现优先处理的三带、飞机等牌型。
首先定义一些基本变量:
-
//暂存最佳的价值
-
HandCardValue BestHandCardValue;
-
BestHandCardValue.NeedRound =
20;
-
BestHandCardValue.SumValue = MinCardsValue;
-
//我们认为不出牌的话会让对手一个轮次,即加一轮(权值减少7)便于后续的对比参考。
-
BestHandCardValue.NeedRound +=
1;
-
-
//暂存最佳的组合
-
CardGroupData BestCardGroup;
-
-
//带出去的牌
-
int tmp_1 =
0;
-
int tmp_2 =
0;
-
int tmp_3 =
0;
-
int tmp_4 =
0;
因为枚举了牌型,所以实际和被动出牌逻辑都差不多,且没有nMaxCard的限制,所以我们要从3开始遍历。且上一章我们提到,不考虑炸弹拆分的情况。故value_aHandCardList[i]不能等于4。
-
for (
int i =
3; i <
16; i++)
-
{
-
//2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
-
if (clsHandCardData.value_aHandCardList[i] !=
4)
-
{
-
//出三带一
-
if (clsHandCardData.value_aHandCardList[i] >
2)
-
{
-
clsHandCardData.value_aHandCardList[i] -=
3;
-
for (
int j =
3; j <
18; j++)
-
{
-
if (clsHandCardData.value_aHandCardList[j] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[j] -=
1;
-
clsHandCardData.nHandCardCount -=
4;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
clsHandCardData.value_aHandCardList[j] +=
1;
-
clsHandCardData.nHandCardCount +=
4;
-
//选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE, i,
4);
-
tmp_1 = j;
-
}
-
}
-
}
-
clsHandCardData.value_aHandCardList[i] +=
3;
-
}
-
//出三带二
-
if (clsHandCardData.value_aHandCardList[i] >
2)
-
{
-
for (
int j =
3; j <
16; j++)
-
{
-
clsHandCardData.value_aHandCardList[i] -=
3;
-
if (clsHandCardData.value_aHandCardList[j] >
1)
-
{
-
clsHandCardData.value_aHandCardList[j] -=
2;
-
clsHandCardData.nHandCardCount -=
5;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
clsHandCardData.value_aHandCardList[j] +=
2;
-
clsHandCardData.nHandCardCount +=
5;
-
//选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO, i,
5);
-
tmp_1 = j;
-
}
-
}
-
clsHandCardData.value_aHandCardList[i] +=
3;
-
}
-
}
-
//出四带二单
-
if (clsHandCardData.value_aHandCardList[i] >
3)
-
{
-
//2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
-
}
-
//出四带二对
-
if (clsHandCardData.value_aHandCardList[i] >
3)
-
{
-
//2.0版本策略主动出牌不拆分炸弹,朕自己从来就不打四带二,因为浪
-
}
-
//出三带一单连
-
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;
-
}
-
/*本来想做全排列选取带出的牌然后枚举出最高价值的,但考虑到当飞机长度也就是在2-4之间
-
所以干脆做三个分支处理算了*/
-
//为两连飞机
-
if (prov ==
2)
-
{
-
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] -=
3;
-
}
-
clsHandCardData.nHandCardCount -= prov *
4;
-
for (
int tmp1 =
3; tmp1 <
18; tmp1++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp1] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp1] -=
1;
-
for (
int tmp2 = tmp1; tmp2 <
18; tmp2++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp2] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp2] -=
1;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov *
4);
-
tmp_1 = tmp1;
-
tmp_2 = tmp2;
-
-
}
-
clsHandCardData.value_aHandCardList[tmp2] +=
1;
-
}
-
}
-
clsHandCardData.value_aHandCardList[tmp1] +=
1;
-
}
-
}
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] +=
3;
-
}
-
clsHandCardData.nHandCardCount += prov *
4;
-
}
-
//为三连飞机
-
if (prov ==
3)
-
{
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] -=
3;
-
}
-
clsHandCardData.nHandCardCount -= prov *
4;
-
for (
int tmp1 =
3; tmp1 <
18; tmp1++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp1] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp1] -=
1;
-
for (
int tmp2 = tmp1; tmp2 <
18; tmp2++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp2] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp2] -=
1;
-
for (
int tmp3 = tmp2; tmp3 <
18; tmp3++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp3] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp3] -=
1;
-
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov *
4);
-
tmp_1 = tmp1;
-
tmp_2 = tmp2;
-
tmp_3 = tmp3;
-
-
}
-
clsHandCardData.value_aHandCardList[tmp3] +=
1;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp2] +=
1;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp1] +=
1;
-
}
-
}
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] +=
3;
-
}
-
clsHandCardData.nHandCardCount += prov *
4;
-
}
-
//为四连飞机
-
if (prov ==
4)
-
{
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] -=
3;
-
}
-
clsHandCardData.nHandCardCount -= prov *
4;
-
for (
int tmp1 =
3; tmp1 <
18; tmp1++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp1] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp1] -=
1;
-
for (
int tmp2 = tmp1; tmp2 <
18; tmp2++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp2] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp2] -=
1;
-
for (
int tmp3 = tmp2; tmp3 <
18; tmp3++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp3] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp3] -=
1;
-
for (
int tmp4 = tmp3; tmp4 <
18; tmp4++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp4] >
0 )
-
{
-
clsHandCardData.value_aHandCardList[tmp4] -=
1;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, j, prov *
4);
-
tmp_1 = tmp1;
-
tmp_2 = tmp2;
-
tmp_3 = tmp3;
-
tmp_4 = tmp4;
-
}
-
clsHandCardData.value_aHandCardList[tmp4] +=
1;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp3] +=
1;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp2] +=
1;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp1] +=
1;
-
}
-
}
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] +=
3;
-
}
-
clsHandCardData.nHandCardCount += prov *
4;
-
}
-
//若prov==5,则是地主可以直接出去,在剪枝部分已经处理
-
}
-
-
}
-
//出三带一双连
-
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;
-
}
-
/*本来想做全排列选取带出的牌然后枚举出最高价值的,但考虑到当飞机长度也就是在2-4之间
-
所以干脆做三个分支处理算了*/
-
//为两连飞机
-
if (prov ==
2)
-
{
-
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] -=
3;
-
}
-
clsHandCardData.nHandCardCount -= prov *
5;
-
for (
int tmp1 =
3; tmp1 <
16; tmp1++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp1] >
1 )
-
{
-
clsHandCardData.value_aHandCardList[tmp1] -=
2;
-
for (
int tmp2 = tmp1; tmp2 <
16; tmp2++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp2] >
1 )
-
{
-
clsHandCardData.value_aHandCardList[tmp2] -=
2;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO_LINE, j, prov *
5);
-
tmp_1 = tmp1;
-
tmp_2 = tmp2;
-
}
-
clsHandCardData.value_aHandCardList[tmp2] +=
2;
-
}
-
}
-
clsHandCardData.value_aHandCardList[tmp1] +=
2;
-
}
-
}
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] +=
3;
-
}
-
clsHandCardData.nHandCardCount += prov *
5;
-
}
-
//为三连飞机
-
if (prov ==
3)
-
{
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] -=
3;
-
}
-
clsHandCardData.nHandCardCount -= prov *
5;
-
for (
int tmp1 =
3; tmp1 <
16; tmp1++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp1] >
1 )
-
{
-
clsHandCardData.value_aHandCardList[tmp1] -=
2;
-
for (
int tmp2 = tmp1; tmp2 <
16; tmp2++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp2] >
1 )
-
{
-
clsHandCardData.value_aHandCardList[tmp2] -=
2;
-
for (
int tmp3 = tmp2; tmp3 <
16; tmp3++)
-
{
-
if (clsHandCardData.value_aHandCardList[tmp3] >
1 )
-
{
-
clsHandCardData.value_aHandCardList[tmp3] -=
2;
-
HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
-
if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound *
7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound *
7)))
-
{
-
BestHandCardValue = tmpHandCardValue;
-
BestCardGroup = get_GroupData(cgTHREE_TAKE_TWO_LINE, j, prov *
5);
-
tmp_1 = tmp1;
-
tmp_2 = tmp2;
-
tmp_3 = tmp3;
-
}
-
clsHandCardData.value_aHandCardList[tmp3] +=
2;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp2] +=
2;
-
}
-
-
}
-
clsHandCardData.value_aHandCardList[tmp1] +=
2;
-
}
-
}
-
for (
int k = i; k <= j; k++)
-
{
-
clsHandCardData.value_aHandCardList[k] +=
3;
-
}
-
clsHandCardData.nHandCardCount += prov *
5;
-
}
-
//若prov==4,则是地主可以直接出去,在剪枝部分已经处理
-
}
-
}
-
}
-
-
}
这个循环结束后,若有好的选择,则BestCardGroup会保留出牌的类型,在循环外进行出牌处理。
-
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;
-
return;
-
}
-
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;
-
return;
-
}
-
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;
-
return;
-
}
-
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算法——第十四章の主动出牌(3)