上一章我们定义了基本的数据结构,相信大家看到手牌类里面那么多出牌序列时一定会比较愤慨。。。

其实一开始写的时候我也是觉得很脑残,不过后续开发证明了这样的结构还是可以的,因为只要我封装了一层数据转换,接下来所有的算法策略都只用到2个成员变量,状态数据及手牌数量。特别便于调试、管理。那么接下来就写出类成员函数的实现方法

//手牌数据类
class HandCardData
{public://构造函数HandCardData::HandCardData(){}//析构函数virtual HandCardData::~HandCardData(){}public://手牌序列——无花色,值域3~17vector <int> value_nHandCardList;//手牌序列——状态记录,便于一些计算,值域为该index牌对应的数量0~4int value_aHandCardList[18] = { 0 };//手牌序列——有花色,按照从大到小的排列  56,52:大王小王……4~0:红3黑3方3花3vector <int> color_nHandCardList;//手牌个数int nHandCardCount = 17 ;//玩家角色地位       0:地主    1:农民——地主下家   2:农民——地主上家int nGameRole = -1;//玩家座位ID int nOwnIndex = -1;//玩家要打出去的牌类型CardGroupData uctPutCardType;//要打出去的牌——无花色vector <int> value_nPutCardList;//要打出去的牌——有花色vector <int> color_nPutCardList;HandCardValue uctHandCardValue;
public://要打出的牌序列清空void ClearPutCardList();//手牌排序,大牌靠前void SortAsList(vector <int> &arr);//出一张牌,返回操作是否合法bool PutOneCard(int value_nCard, int &clear_nCard);//出一组牌,返回操作是否合法bool PutCards();//通过有花色手牌获取无花色手牌(包含两种结构)void get_valueHandCardList();//初始化void Init();//输出所有成员变量,用于测试void PrintAll();};

void HandCardData::ClearPutCardList() 是把要出的牌打入出牌序列前清空现列表的操作,含有花色和无花色,顺便把之前出牌类型的值初始化一下

void HandCardData::ClearPutCardList()
{color_nPutCardList.clear();value_nPutCardList.clear();uctPutCardType.cgType = cgERROR;uctPutCardType.nCount = 0;uctPutCardType.nMaxCard = -1;uctPutCardType.nValue = 0;return;
}

void HandCardData::SortAsList(vector <int> & arr )简单的排序,这个就不说了

/*降序排序对比*/
int cmp(int a, int b) { return a > b ? 1 : 0; }void HandCardData::SortAsList(vector <int> & arr )
{sort(arr.begin(), arr.end(), cmp);return;
}

void HandCardData::get_valueHandCardList()根据获取的有花色手牌序列转换成无花色手牌序列

我们的花色定义是按照从大到小的排列  56,52:大王小王……4~0:红3黑3方3花3  所以花色值/4再加上最小的牌3就是我们要的无花色权值

注:2对应的值是15 A对应的值是14

void HandCardData::get_valueHandCardList()
{//清零value_nHandCardList.clear();memset(value_aHandCardList, 0,sizeof(value_aHandCardList));for (vector<int>::iterator iter = color_nHandCardList.begin(); iter != color_nHandCardList.end(); iter++){value_nHandCardList.push_back((*iter / 4)+3);  value_aHandCardList[(*iter / 4) + 3]++;}}

void HandCardData::Init()手牌的初始化,主要用于根据获取的有花色手牌序列转换成无花色手牌序列,手牌序列排序, 计算出手牌个数。

void HandCardData::Init()
{//根据花色手牌获取权值手牌get_valueHandCardList();//手牌 排序SortAsList(color_nHandCardList);SortAsList(value_nHandCardList);//当前手牌个数nHandCardCount = value_nHandCardList.size();}

void HandCardData::PrintAll()就是输出一些类成员变量,测试时使用。

void HandCardData::PrintAll()
{cout << "color_nHandCardList:" << endl;for (vector<int>::iterator iter = color_nHandCardList.begin(); iter != color_nHandCardList.end(); iter++)cout << get_CardsName(*iter) << (iter == color_nHandCardList.end() - 1 ? '\n' : ',');cout << endl;/*cout << "value_nHandCardList:" << endl;for (vector<int>::iterator iter = value_nHandCardList.begin(); iter != value_nHandCardList.end(); iter++)cout << *iter << (iter == value_nHandCardList.end() - 1 ? '\n' : ',');cout << endl;cout << "value_aHandCardList:" << endl;for (int i = 0; i < 18; i++){cout << value_aHandCardList[i] << (i == 17 ? '\n' : ',');}cout << endl;cout << "nHandCardCount:" << nHandCardCount << endl;cout << endl;cout << "nGameRole:" << nGameRole << endl;cout << endl;*/
}

接下来就说出牌的函数了

bool  HandCardData::PutCards()出一组牌,返回操作是否合法

其函数实现为:遍历无花色手牌序列逐一映射到有花色手牌,然后将其加入有花色出牌数组里。说白了PutCards就是循环调用PutOneCard

bool  HandCardData::PutCards()
{for (vector<int>::iterator iter = value_nPutCardList.begin(); iter != value_nPutCardList.end(); iter++){int color_nCard = -1;if (PutOneCard(*iter, color_nCard)){color_nPutCardList.push_back(color_nCard);}else{return false;}}nHandCardCount -= value_nPutCardList.size();return true;
}

重点就是出一张牌的实现方法了,bool PutOneCard(int value_nCard, int &clear_nCard);

这里我们需要做的事情可以分成两部分,第一部分,返回一个有花色的手牌以供PutCards加入有花色出牌序列,也就是引用的 int &clear_nCard

第二个就是处理我们的这几个数组(value状态数组、value列表数组、color列表数组)

bool  HandCardData::PutOneCard(int value_nCard, int &color_nCard)
{bool ret = false;//value状态数组处理value_aHandCardList[value_nCard]--;if (value_aHandCardList[value_nCard] < 0){return false;}//value列表数组处理for (vector<int>::iterator iter = value_nHandCardList.begin(); iter != value_nHandCardList.end(); iter++){if (*iter == value_nCard){value_nHandCardList.erase(iter);ret = true;break;}}// color列表数组处理int k = (value_nCard - 3) * 4;      //数值转换for (vector<int>::iterator iter = color_nHandCardList.begin(); iter != color_nHandCardList.end(); iter++){for (int i = k; i < k + 4; i++) {if (*iter == i){color_nCard = i;color_nHandCardList.erase(iter);return ret;}}}return false;
}

至此,手牌类成员的数据处理函数就做完了,而全局类并没有什么需要我们处理的,因为那些都应该是我们从服务器获取的信息。

如果说这些都算是准备工作的话,那么接下来便是开始进入AI逻辑环节了,我们先从手牌权值的定义说起。

敬请关注下一章:斗地主AI算法——第四章の权值定义

斗地主AI算法——第三章の数据处理相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. 斗地主AI算法——第二章の数据结构

    上一章我们已经确立了基本的业务逻辑处理流程.从本章开始,我们便进入开发阶段. 首先就是明确我们都需要哪些数据,且它们以怎样的形式存储. 首先从上一章反复提到的手牌权值结构说起,也就是F()的返回值,他 ...

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

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

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

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

最新文章

  1. 微服务为什么一定要用docker ?
  2. python毫秒级时间戳
  3. 解决IE正常模式与兼容性模式的办法
  4. php+mysql案例含源码_【专注】Zabbix源码安装教程—步骤详解(1)安装前准备
  5. C++的六个默认函数
  6. Android文本框输入汉字,android中EditText输入类型为何不能设置为中文
  7. 禁用安全模式(2k,2k3,xp)
  8. Linux系统中DHCP的配置
  9. python人体识别_Github开源人体姿态识别项目OpenPose中文文档
  10. 机器学习--支持向量机(二)拉格朗日乘子法详解
  11. docker监听通信
  12. 基于SSM的疫情数据统计分析系统
  13. 基于bootsplash的嵌入式linux启动画面定制
  14. sql 语句 查询结果赋值变量_RationalDMIS 7.1 变量赋值 ASSIGN语句
  15. 对数换底公式及推导证明
  16. html表格打印自动换行,html 表格自动换行问题
  17. 绝对公平?破解北京机动车摇号的秘密
  18. MySQL讲义第 43 讲——select 查询之查询练习(一)
  19. 安卓虚拟摄像头_iPhone 的“第四颗摄像头”位置,为什么给了激光雷达?
  20. 2014完,2015启

热门文章

  1. 40 MM配置-采购-采购订单-STO配置-定义凭证类型和可用性检查设置
  2. php mysql 日期查找_PHP / MySQL存储和搜索日期
  3. 剖析Caffe源码之Net---Net构造函数
  4. django连接自定义mysql,Django中使用自定义Manager管理多个Mysql数据库
  5. java 指针 地址压缩_JVM优化之压缩普通对象指针(CompressedOops)
  6. word删除分节符后之前的格式乱了_分页符分节符,你知道多少
  7. 关于vue中Cannot read property 'length' of undefined 导致:数据不显示问题【自己经验参考】
  8. 轻量小巧的Knife4j v2.0.8源码
  9. php闭包查询作用,ThinkPHP5 闭包查询问题的探讨
  10. 帮管客CRM客户管理系统