前面几章已经把整个斗地主AI算法工程完成的差不多了,接下来进入整合联调以及模拟测试模块。

测试模块主要任务就是代替服务器给出我们需要的数据。因为我们本来的计划是封装成类库通过服务器调用获取,其调用的接口无非就是叫分、被动出牌、主动出牌。

被动出牌和主动出牌我们已经完成,叫分我们已经实现了权值的获取,只需要在外面加一个区间划分即可:

/*
获取叫分函数
*/int LandScore(GameSituation &clsGameSituation, HandCardData &clsHandCardData)
{int SumValue = 0;clsHandCardData.uctHandCardValue=get_HandCardValue(clsHandCardData);SumValue = clsHandCardData.uctHandCardValue.SumValue;cout << "SumValue is :" << SumValue << ",";cout << "NeedRound is :" << clsHandCardData.uctHandCardValue.NeedRound << endl;if (SumValue<10) {return 0;}else if (SumValue < 15){return 1;}else if (SumValue < 20){return 2;}else {return 3;}
}

接下来就是模拟数据了,首先完成洗牌,即初始化牌值与随机打乱。

//洗牌
void InitCards(vector <int> &Cards)
{//先清空CardsCards.clear();vector <int> tmpCards;int i;//大王56,小王52,没有53,54,55号牌for (i = 0; i < 53; i++) {tmpCards.push_back(i);}tmpCards.push_back(56);//顺序随机打乱for (i = tmpCards.size(); i>0; i--) {srand(unsigned(time(NULL)));// 选中的随机下标int index = rand() % i;Cards.push_back(tmpCards[index]);tmpCards.erase(tmpCards.begin() + index);}}

同时为了方便测试,我也做了一个指定牌型的函数。

//洗牌(指定牌型,用于测试)
void InitCards_Appoint(vector <int> &Cards)
{//先清空CardsCards.clear();/***********飞机与炸弹连续拆分逻辑测试**********/Cards.push_back(48); Cards.push_back(50); Cards.push_back(49);Cards.push_back(44); Cards.push_back(47); Cards.push_back(35);Cards.push_back(40); Cards.push_back(46); Cards.push_back(34);Cards.push_back(36); Cards.push_back(45); Cards.push_back(33);Cards.push_back(23); Cards.push_back(43); Cards.push_back(31);Cards.push_back(22); Cards.push_back(42);    Cards.push_back(30);Cards.push_back(21); Cards.push_back(41); Cards.push_back(29);Cards.push_back(19); Cards.push_back(39); Cards.push_back(27);Cards.push_back(18); Cards.push_back(38); Cards.push_back(26);Cards.push_back(17); Cards.push_back(37); Cards.push_back(25);Cards.push_back(15); Cards.push_back(32);   Cards.push_back(20);Cards.push_back(14); Cards.push_back(28); Cards.push_back(16);Cards.push_back(13); Cards.push_back(24); Cards.push_back(12);Cards.push_back(11); Cards.push_back(3); Cards.push_back(7);Cards.push_back(10); Cards.push_back(2); Cards.push_back(6);Cards.push_back(9); Cards.push_back(1); Cards.push_back(5);Cards.push_back(8); Cards.push_back(0); Cards.push_back(4);Cards.push_back(51); Cards.push_back(52); Cards.push_back(56);}

洗完牌就是发牌了,发牌这里我们需要定义一个包含三个人手牌的结构,因为作为正常调用来说我们是不应该有这样的数据的。

//下发到三名玩家的手牌序列,此数据只用于测试,作为AI时不会获取struct ALLCardsList
{vector <int>  arrCardsList[3];
};

然后依次发送到玩家对应的手牌数组里,最后三张为底牌。

//发牌
void SendCards(GameSituation & clsGameSituation, ALLCardsList &uctALLCardsList)
{//洗牌vector <int> Cards;InitCards(Cards);//InitCards_Appoint(Cards);int i, j, k;j = 0;for (k = 0; k < 17; k++) {for (i = 0; i < 3; i++,j++){uctALLCardsList.arrCardsList[i].push_back(Cards[j]);}}//三张底牌clsGameSituation.DiPai[0] = Cards[j];clsGameSituation.DiPai[1] = Cards[j+1];clsGameSituation.DiPai[2] = Cards[j+2];return;
}

再然后就是模拟游戏过程,首先定义游戏全局类,与三名玩家的手牌信息类。调用发牌函数完成发牌环节,可以用手牌信息类里面的PrintAll输出你想要的数据信息。

 GameSituation clsGameSituation;ALLCardsList  uctALLCardsList;//发牌SendCards(clsGameSituation, uctALLCardsList);HandCardData arrHandCardData[3];arrHandCardData[0].color_nHandCardList = uctALLCardsList.arrCardsList[0];arrHandCardData[1].color_nHandCardList = uctALLCardsList.arrCardsList[1];arrHandCardData[2].color_nHandCardList = uctALLCardsList.arrCardsList[2];for (int i = 0; i < 3; i++){arrHandCardData[i].Init();arrHandCardData[i].nOwnIndex = i;}cout << "0号玩家牌为:" << endl;arrHandCardData[0].PrintAll();cout << "1号玩家牌为:" << endl;arrHandCardData[1].PrintAll();cout << "2号玩家牌为:" << endl;arrHandCardData[2].PrintAll();cout << "底牌为:" << endl;cout << get_CardsName(clsGameSituation.DiPai[0]) << ','<< get_CardsName(clsGameSituation.DiPai[1]) << ','<< get_CardsName(clsGameSituation.DiPai[2]) << endl;cout << endl;

发完牌后开始叫地主,调用LandScore函数返回其叫的分值,只有比当前已叫的分值更高才可以刷新叫地主记录。若无人叫地主重新开一局,否则将三张底牌给地主,同时刷新地主手牌,且将地主设置成将要出牌的玩家

 for (int i = 0; i < 3; i++){int  tmpLandScore = LandScore(clsGameSituation, arrHandCardData[i]);if (tmpLandScore > clsGameSituation.nNowLandScore){clsGameSituation.nNowLandScore = tmpLandScore;clsGameSituation.nNowDiZhuID = i;}}if (clsGameSituation.nNowDiZhuID == -1){cout << "无人叫地主" << endl;return;}cout << clsGameSituation.nNowDiZhuID << "号玩家是地主,叫分为:" << clsGameSituation.nNowLandScore << endl;clsGameSituation.nDiZhuID=clsGameSituation.nNowDiZhuID;clsGameSituation.nLandScore =clsGameSituation.nNowLandScore;//将三张底牌给地主arrHandCardData[clsGameSituation.nDiZhuID].color_nHandCardList.push_back(clsGameSituation.DiPai[0]);arrHandCardData[clsGameSituation.nDiZhuID].color_nHandCardList.push_back(clsGameSituation.DiPai[1]);arrHandCardData[clsGameSituation.nDiZhuID].color_nHandCardList.push_back(clsGameSituation.DiPai[2]);//地主手牌刷新arrHandCardData[clsGameSituation.nDiZhuID].Init();//出牌玩家IDint indexID= clsGameSituation.nDiZhuID;cout << endl;cout << "0号玩家牌为:" << endl;arrHandCardData[0].PrintAll();cout << "1号玩家牌为:" << endl;arrHandCardData[1].PrintAll();cout << "2号玩家牌为:" << endl;arrHandCardData[2].PrintAll();//当前控手玩家先为地主clsGameSituation.nCardDroit = indexID;

接下来就是循环进行出牌了。在游戏全局类里我们设置了一个标志是否结束的变量,可以用于控制循环。出牌时我们只需调用get_PutCardList出牌函数即可。若某个玩家出完牌后手牌为0,则游戏结束。若玩家出过牌,则刷新游戏全局类里面当前牌型信息。

while (!clsGameSituation.Over){get_PutCardList_2(clsGameSituation, arrHandCardData[indexID]);//获取出牌序列arrHandCardData[indexID].PutCards();cout << indexID << "号玩家出牌:" << endl;for (vector<int>::iterator iter = arrHandCardData[indexID].color_nPutCardList.begin();iter != arrHandCardData[indexID].color_nPutCardList.end(); iter++)cout << get_CardsName(*iter) << (iter == arrHandCardData[indexID].color_nPutCardList.end() - 1 ? '\n' : ',');cout << endl;if (arrHandCardData[indexID].nHandCardCount == 0){clsGameSituation.Over = true;if (indexID == clsGameSituation.nDiZhuID){cout << "地主" << indexID << "号玩家获胜" << endl;}else{for (int i = 0; i < 3; i++) {if (i != clsGameSituation.nDiZhuID){cout << "农民" << i << "号玩家获胜" << endl;}}}}if (arrHandCardData[indexID].uctPutCardType.cgType != cgZERO){clsGameSituation.nCardDroit = indexID;clsGameSituation.uctNowCardGroup = arrHandCardData[indexID].uctPutCardType;}indexID == 2 ? indexID = 0 : indexID++;}

get_PutCardList函数做了一个分支,通过nCardDroit当前控手对象判断是主动出牌还是被动出牌

/*
2.0版本策略  根据场上形势决定当前预打出的手牌——分支处理
*/
void get_PutCardList_2(GameSituation &clsGameSituation, HandCardData &clsHandCardData)
{if (clsGameSituation.nCardDroit == clsHandCardData.nOwnIndex){get_PutCardList_2_unlimit(clsGameSituation, clsHandCardData);}else{get_PutCardList_2_limit(clsGameSituation, clsHandCardData);}return;
}

完成测试模块后,我们就可以调试程序了。

那么现在我们就可以愉快的玩耍了,下一章我们将观察几次对局情况进行样例的分析。

敬请关注下一章:斗地主AI算法——第十六章の样例分析

斗地主AI算法——第十五章の测试模块相关推荐

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

    上一章已经排除了飞机.三带等牌型,那么除去炸弹王炸以外,我们只剩下单牌.对牌.三牌以及单顺.双顺.三顺了. 首先说单牌.对牌.三牌.其逻辑基本一样,只是出牌的个数有差别,即:如果该i牌数量满足这种牌型 ...

  2. 斗地主AI算法——第十六章の样例分析

    上一章,我们已经完成了测试模块的开发.至此我们已经可以进行整体测试了.本章主要内容就是对随机生成的对局情况进行简单的分析. 实际上整个开发过程绝大部分时间都是用在样例分析上,通过样例给出的返回操作分析 ...

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

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

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

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

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

    本章是被动出牌的最后一章,截止目前,我们已经解决了大部分牌型.只剩下飞机和炸弹了. 飞机无疑是最复杂的类型,他等于顺子和三带的结合体,但又增加了很多难度. 根据上一章的算法,我们可以大概想到,若是带出 ...

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

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

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

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

  8. 第十五章 - 垃圾回收相关算法

    第十五章 - 垃圾回收相关算法 文章目录 第十五章 - 垃圾回收相关算法 1.标记阶段:引用计数算法 1.1 垃圾标记阶段:对象存活判断 1.2 引用计数算法 1.3 小结 2.标记阶段:可达性分析算 ...

  9. 《算法导论3rd第十五章》动态规划

    前言 和分治法一样, 动态规划 (dynamic programming)是通过组合子问题的解而解决整个问题的.分治法是将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原问题 ...

最新文章

  1. Android:ListView、ListActivity、 setListAdapter
  2. python怎么安装第三方库-怎样安装Python的第三方库
  3. spring-文件上传
  4. 使用模板引擎artTemplate的几个问题总结
  5. 条令考试小程序辅助器_应知应会|条令纲要学习微课堂(六)
  6. 微软 Build 2019 对开发者意味着什么?
  7. 二进制补码以及为什么要使用补码
  8. 如何通过ip访问服务器文件共享,通过ip访问云服务器文件共享
  9. 软件开发流程(Software development process)
  10. 数学建模——层次分析法(Matlab)【评价类问题】
  11. java强制删文件夹_Java 删除文件夹 和 文件 集合
  12. SpringBoot统一返回result结果集
  13. python gpl_详细介绍 GPL 协议
  14. 计算机系统中用通常所说的外存是指,全国计算机一级考试选择题练习及答案(2)...
  15. ISCC2021—ISCC客服一号冲冲冲(二)
  16. 转贴-- CISCO CPOS STM配置示例
  17. 用于图像质量评价的LIVE数据库 百度网盘地址附解压密码
  18. 10月23日,相约全球边缘计算大会·上海站
  19. 三聚氰胺,究竟是谁的错?
  20. 人工智能创业盈利点在何处

热门文章

  1. 47 SD配置-销售凭证设置-激活项目类别的定价
  2. 12 快件文档“更新终止”从作者“xxx”收到
  3. linux线程wait和sleep,java多线程 sleep()和wait()的区别
  4. ResNet网络总结
  5. C++:画数组元素直方图
  6. 【炼丹技巧】指数移动平均(EMA)【在一定程度上提高最终模型在测试数据上的表现(例如accuracy、FID、泛化能力...)】
  7. 使用Flash Pro CC 输出动画--html5-canvas
  8. phpcmsV9 邮箱注册:邮箱验证(不改代码、含演示截图) - 配置篇
  9. Mint-UI框架router-link返回上一页的方法 - 踩坑篇
  10. phpcms v9宽字节注入问题