斗地主AI算法——第十一章の被动出牌(5)
来源:互联网 发布:义乌样品淘宝拍摄 编辑:程序博客网 时间:2024/05/26 15:55
本章是被动出牌的最后一章,截止目前,我们已经解决了大部分牌型。只剩下飞机和炸弹了。
飞机无疑是最复杂的类型,他等于顺子和三带的结合体,但又增加了很多难度。
根据上一章的算法,我们可以大概想到,若是带出去一张我就加一个循环,若是带出去两张我就加俩循环,但是这个飞机长度不一致,带出去的牌个数也就不一致,这TM怎么加啊!!我一开始的想法是外置一个全排列函数,给定count个数,然后列举所有的方案去改变value_aHandCardList数组再筛选出最优解。但这样做有坏处,第一,这个外置函数非常的麻烦,因为他全排列的全集和子集个数都不确定。第二,影响了程序分支一致性,别的模块都差不多,就飞机这里搞特殊化不太好。第三,不一定安全,因为这种做法意味着我又要多了一个可以影响value_aHandCardList的模块,我并不希望这样。
所以思考了很久,我觉得宁愿多做几个分支,毕竟飞机的个数还是可控的,就2-4。虽然这种代码写起来跟看起来都很傻逼,但是也没有办法。。。
飞机带单:
//暂存最佳的价值HandCardValue BestHandCardValue = get_HandCardValue(clsHandCardData);//我们认为不出牌的话会让对手一个轮次,即加一轮(权值减少7)便于后续的对比参考。BestHandCardValue.NeedRound += 1;//暂存最佳的牌号int BestMaxCard = 0;//是否出牌的标志bool PutCards = false;//验证顺子的标志int prov = 0;//顺子起点int start_i = 0;//顺子终点int end_i = 0;//顺子长度int length = clsGameSituation.uctNowCardGroup.nCount / 4;int tmp_1 = 0;int tmp_2 = 0;int tmp_3 = 0;int tmp_4 = 0;//2与王不参与顺子,从当前已打出的顺子最小牌值+1开始遍历for (int i = clsGameSituation.uctNowCardGroup.nMaxCard - length + 2; i < 15; i++){if (clsHandCardData.value_aHandCardList[i] > 2){prov++;}else{prov = 0;}if (prov >= length){end_i = i;start_i = i - length + 1;for (int j = start_i; j <= end_i; j++){clsHandCardData.value_aHandCardList[j] -= 3;}clsHandCardData.nHandCardCount -= clsGameSituation.uctNowCardGroup.nCount;/*本来想做全排列选取带出的牌然后枚举出最高价值的,但考虑到当飞机长度也就是在2-4之间所以干脆做三个分支处理算了*///为两连飞机if (length == 2){for (int j = 3; j < 18; j++){if (clsHandCardData.value_aHandCardList[j] > 0){clsHandCardData.value_aHandCardList[j] -= 1;for (int k = 3; k < 18; k++){if (clsHandCardData.value_aHandCardList[k] > 0){clsHandCardData.value_aHandCardList[k] -= 1;HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);clsHandCardData.value_aHandCardList[k] += 1;//选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7))){BestHandCardValue = tmpHandCardValue;BestMaxCard = end_i;tmp_1 = j;tmp_2 = k;PutCards = true;}}}clsHandCardData.value_aHandCardList[j] += 1;}}}//为三连飞机if (length == 3){for (int j = 3; j < 18; j++){if (clsHandCardData.value_aHandCardList[j] > 0){clsHandCardData.value_aHandCardList[j] -= 1;for (int k = 3; k < 18; k++){if (clsHandCardData.value_aHandCardList[k] > 0){clsHandCardData.value_aHandCardList[k] -= 1;for (int l = 3; l < 18; l++){if (clsHandCardData.value_aHandCardList[l] > 0){clsHandCardData.value_aHandCardList[l] -= 1;HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);//选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7))){BestHandCardValue = tmpHandCardValue;BestMaxCard = end_i;tmp_1 = j;tmp_2 = k;tmp_3 = l;PutCards = true;}clsHandCardData.value_aHandCardList[l] += 1;}}clsHandCardData.value_aHandCardList[k] += 1;}}clsHandCardData.value_aHandCardList[j] += 1;}}}//为四连飞机if (length == 4){for (int j = 3; j < 18; j++){if (clsHandCardData.value_aHandCardList[j] > 0){clsHandCardData.value_aHandCardList[j] -= 1;for (int k = 3; k < 18; k++){if (clsHandCardData.value_aHandCardList[k] > 0){clsHandCardData.value_aHandCardList[k] -= 1;for (int l = 3; l < 18; l++){if (clsHandCardData.value_aHandCardList[l] > 0){clsHandCardData.value_aHandCardList[l] -= 1;for (int m = 3; m < 18; m++){if (clsHandCardData.value_aHandCardList[m] > 0){clsHandCardData.value_aHandCardList[m] -= 1;HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);//选取总权值-轮次*7值最高的策略 因为我们认为剩余的手牌需要n次控手的机会才能出完,若轮次牌型很大(如炸弹) 则其-7的价值也会为正if ((BestHandCardValue.SumValue - (BestHandCardValue.NeedRound * 7)) <= (tmpHandCardValue.SumValue - (tmpHandCardValue.NeedRound * 7))){BestHandCardValue = tmpHandCardValue;BestMaxCard = end_i;tmp_1 = j;tmp_2 = k;tmp_3 = l;tmp_4 = m;PutCards = true;}clsHandCardData.value_aHandCardList[m] += 1;}}clsHandCardData.value_aHandCardList[l] += 1;}}clsHandCardData.value_aHandCardList[k] += 1;}}clsHandCardData.value_aHandCardList[j] += 1;}}}for (int j = start_i; j <= end_i; j++){clsHandCardData.value_aHandCardList[j] += 3;}clsHandCardData.nHandCardCount += clsGameSituation.uctNowCardGroup.nCount;}}if (PutCards){for (int j = start_i; j <= end_i; j++){clsHandCardData.value_nPutCardList.push_back(j);clsHandCardData.value_nPutCardList.push_back(j);clsHandCardData.value_nPutCardList.push_back(j);}if (length == 2){clsHandCardData.value_nPutCardList.push_back(tmp_1);clsHandCardData.value_nPutCardList.push_back(tmp_2); }if (length == 3){clsHandCardData.value_nPutCardList.push_back(tmp_1);clsHandCardData.value_nPutCardList.push_back(tmp_2);clsHandCardData.value_nPutCardList.push_back(tmp_3);}if (length == 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 = clsGameSituation.uctNowCardGroup = get_GroupData(cgTHREE_TAKE_ONE_LINE, BestMaxCard, clsGameSituation.uctNowCardGroup.nCount);return;}
大家可以看到我回溯的处理方式和之前的不一样了,因为飞机类型很有可能把对牌当成两个单牌带出,甚至可以拆炸弹。所以每个循环内当确定了一个点就先处理value_aHandCardList状态,这样也相对安全,上一章中在四带二环节我也有提到过这方面。
飞机带对类似,而且这里是被动出牌,所以不存在4连飞机的情况,因为4连飞机带对的话就有20张牌了。只考虑2连和3连就可以了。
最后再说一下炸弹,这个炸弹就厉害了,我给的策略就是————————————
直接炸丫的!不要怂!!
else if (clsGameSituation.uctNowCardGroup.cgType == cgBOMB_CARD){//更大的炸弹——这里直接炸,不考虑拆分后果。因为信仰。for (int i = clsGameSituation.uctNowCardGroup.nMaxCard + 1; i < 16; i++){if (clsHandCardData.value_aHandCardList[i] == 4){clsHandCardData.value_nPutCardList.push_back(i);clsHandCardData.value_nPutCardList.push_back(i);clsHandCardData.value_nPutCardList.push_back(i);clsHandCardData.value_nPutCardList.push_back(i);clsHandCardData.uctPutCardType = clsGameSituation.uctNowCardGroup = get_GroupData(cgBOMB_CARD, i, 4);return;}}//王炸if (clsHandCardData.value_aHandCardList[17] > 0 && clsHandCardData.value_aHandCardList[16] > 0){clsHandCardData.value_nPutCardList.push_back(17);clsHandCardData.value_nPutCardList.push_back(16);clsHandCardData.uctPutCardType = clsGameSituation.uctNowCardGroup = get_GroupData(cgKING_CARD, 17, 2);return;}//管不上clsHandCardData.uctPutCardType = get_GroupData(cgZERO, 0, 0);return;}
当然也可以改成考虑拆分后果什么的,或者如果你手上有多个炸弹是否对比一下出那个接下来更好 等等逻辑。
不过对于我来说,你都有俩炸弹了,还怕什么,肯定都是要炸的!宁输不拆!就是这么浪!
好了至此被动出牌模块就全部写完了,从下一章开始,我们讲主动出牌。
敬请关注下一章:斗地主AI算法——第十二章の主动出牌(1)
1 0
- 斗地主AI算法——第十一章の被动出牌(5)
- 斗地主AI算法——第七章の被动出牌(1)
- 斗地主AI算法——第八章の被动出牌(2)
- 斗地主AI算法——第九章の被动出牌(3)
- 斗地主AI算法——第十章の被动出牌(4)
- 斗地主AI算法——第十二章の主动出牌(1)
- 斗地主AI算法——第十三章の主动出牌(2)
- 斗地主AI算法——第十四章の主动出牌(3)
- 斗地主AI算法——第二章の数据结构
- 斗地主AI算法——第三章の数据处理
- unity开发 斗地主算法—提示AI(提示出牌)
- 斗地主AI算法——第六章の牌型判断
- 斗地主智能(AI)出牌算法
- 斗地主智能(AI)出牌算法
- 斗地主智能(AI)出牌算法
- 斗地主智能(AI)出牌算法
- 斗地主AI算法——第一章の业务逻辑
- 斗地主游戏AI出牌
- 完整学习笔记之Android基础(详版)
- 由前序遍历和中序遍历推出后序遍历
- Java进阶(六)Java反射机制可恶问题NoSuchFieldException
- UGUI之修改Text字间距
- 数据挖掘领域的十大经典算法
- 斗地主AI算法——第十一章の被动出牌(5)
- ubntu 开发服务进程
- 一劳永逸的搞定 flex 布局
- 关于图与图算法
- 解决jquery操作checkbox全选全不选无法勾选问题
- Zombie's Treasure Chest UVA
- sqlSession深入源码 resource
- 需求
- Oracle RMAN Recover中使用BBED 跳过缺失的归档 继续 Recover 的测试