本章是被动出牌的最后一章,截止目前,我们已经解决了大部分牌型。只剩下飞机和炸弹了。

飞机无疑是最复杂的类型,他等于顺子和三带的结合体,但又增加了很多难度。

根据上一章的算法,我们可以大概想到,若是带出去一张我就加一个循环,若是带出去两张我就加俩循环,但是这个飞机长度不一致,带出去的牌个数也就不一致,这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)

斗地主AI算法——第十一章の被动出牌(5)相关推荐

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

    哎,之前扯了那么多蛋,终于讲出牌了! 本章开始讲被动出牌的逻辑算法.首先我们先把架子搭起来,被动出牌我们肯定是要知道场上目前打出的是什么牌型. 在第二章数据结构里我们定义过,游戏全局类里面有一个存放当 ...

  2. 斗地主AI算法——第十三章の主动出牌(2)

    上一章我们已经搭好了出牌算法的基本框架,本章主要实现优先处理的三带.飞机等牌型. 首先定义一些基本变量: //暂存最佳的价值HandCardValue BestHandCardValue;BestHa ...

  3. 斗地主AI算法——第六章の牌型判断

    本章实现了上一章提到的检查当前是否只是一手牌函数ins_SurCardsType /* 检查剩余的牌是否只是一手牌是: 返回手牌类型数据 不是:返回错误类型(cgERROR) */ CardGroup ...

  4. 斗地主AI算法——第四章の权值定义

    第一章业务逻辑结尾部分我提到了权值的计算方法: ①每个单牌都有一个基础价值②组合牌型的整体价值与这个基础价值有关,但显然计算规则不完全一样.③整手牌可以分成若干个组合牌,但分法不唯一. 当时,我说了① ...

  5. 斗地主AI算法——第三章の数据处理

    上一章我们定义了基本的数据结构,相信大家看到手牌类里面那么多出牌序列时一定会比较愤慨... 其实一开始写的时候我也是觉得很脑残,不过后续开发证明了这样的结构还是可以的,因为只要我封装了一层数据转换,接 ...

  6. 斗地主AI算法——第九章の被动出牌(3)

    上一章已经说明了被动出牌算法基本的出牌思路,且以单牌为例给出了具体的代码. 对牌.三不带牌型实现方法与单牌基本类似.改动的地方主要是枚举牌类型,出牌时value_nPutCardList的处理,回溯时 ...

  7. 斗地主AI算法——第十七章の总结整理

    转载请标明出处:https://blog.csdn.net/sm9sun/article/details/70878001  文章出自:九日王朝 查看全文 http://www.taodudu.cc/ ...

  8. 斗地主AI算法——第十章の被动出牌(4)

    上一章已经说明了单顺的实现方法,双顺.三不带顺牌型实现方法与单牌基本类似.改动的地方除了上一章说的枚举牌类型,出牌时value_nPutCardList的处理,回溯时value_aHandCardLi ...

  9. 斗地主AI算法——第十二章の主动出牌(1)

    本章开始,我们介绍主动出牌的算法,和被动出牌类似,我们第一步把主要架子搭起来. 首先清空出牌序列 clsHandCardData.ClearPutCardList(); 主动出牌的策略按照优先级大体可 ...

最新文章

  1. 《OpenCV3编程入门》学习笔记2 启程前的认知准备
  2. ecshop商城首页怎样设置广告ALT标签
  3. 自然语言处理中的自注意力机制(Self-Attention Mechanism)
  4. SK-Learn使用NMF(非负矩阵分解)和LDA(隐含狄利克雷分布)进行话题抽取
  5. 如何解决secureCRT里面的The remote system refused the connection.
  6. error while loading shared libraries: libgconf-2.so.4
  7. CVPR 2021 |针对强时序依赖,即插即用、混合注意力机制的 ACTION 模块
  8. python的命名空间_python命名空间(namespace)
  9. 微软新版 Edge 浏览器叫板 Chrome!
  10. [转]android MapView 定位与Overlay onTap事件处理
  11. Java并发编程实战读书笔记(1)
  12. Oracle_用户管理
  13. java开发环境有哪些_Java学习开发环境配置大全
  14. 数据挖掘期末论文要求
  15. html如何将汉字转换成英文,中文字体转化为英文或转码
  16. 金盘系统无法连接服务器,西数金盘Gold系列主要面向企业级服务器及存储系统...
  17. Java中停止线程的3种方式
  18. centos6.5安装openoffice和swftools 错误信息
  19. 实体门店一定要做私域运营吗?哪些行业适合做私域流量运营?
  20. 项目笔记——简易RPC框架(待升级)

热门文章

  1. 18 PP配置-生产计划-检查 MRP 元素的文本
  2. 47 CO配置-控制-利润中心会计-设置实际数据的控制参数
  3. python gui button回调函数运行完成后弹出窗口_嵌入式设备GUI开发之GTK+入门(一)...
  4. python 中time和datetime_python中time模块与datetime模块的详解
  5. python调用函数_Python 函数中的 4 种参数类型
  6. ftp 速度_如何评价我的骑行功率(FTP)?
  7. 解决/usr/local/lib/libglog.so.0: error adding symbols: DSO missing from command line
  8. 结构重参数化技术【为了模型压缩】:进可暴力提性能,退可无损做压缩
  9. 回调破前高意味着什么_4连阳后是回调还是突破呢?
  10. mybatis sql标签_【1039期】Mybatis面试18问,你想知道的都在这里了!