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


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

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


  
  
  1. //手牌数据类
  2. class HandCardData
  3. {
  4. public:
  5. //构造函数
  6. HandCardData::HandCardData()
  7. {
  8. }
  9. //析构函数
  10. virtual HandCardData::~HandCardData()
  11. {
  12. }
  13. public:
  14. //手牌序列——无花色,值域3~17
  15. vector < int> value_nHandCardList;
  16. //手牌序列——状态记录,便于一些计算,值域为该index牌对应的数量0~4
  17. int value_aHandCardList[ 18] = { 0 };
  18. //手牌序列——有花色,按照从大到小的排列 56,52:大王小王……4~0:红3黑3方3花3
  19. vector < int> color_nHandCardList;
  20. //手牌个数
  21. int nHandCardCount = 17 ;
  22. //玩家角色地位 0:地主 1:农民——地主下家 2:农民——地主上家
  23. int nGameRole = -1;
  24. //玩家座位ID
  25. int nOwnIndex = -1;
  26. //玩家要打出去的牌类型
  27. CardGroupData uctPutCardType;
  28. //要打出去的牌——无花色
  29. vector < int> value_nPutCardList;
  30. //要打出去的牌——有花色
  31. vector < int> color_nPutCardList;
  32. HandCardValue uctHandCardValue;
  33. public:
  34. //要打出的牌序列清空
  35. void ClearPutCardList();
  36. //手牌排序,大牌靠前
  37. void SortAsList(vector <int> &arr);
  38. //出一张牌,返回操作是否合法
  39. bool PutOneCard(int value_nCard, int &clear_nCard);
  40. //出一组牌,返回操作是否合法
  41. bool PutCards();
  42. //通过有花色手牌获取无花色手牌(包含两种结构)
  43. void get_valueHandCardList();
  44. //初始化
  45. void Init();
  46. //输出所有成员变量,用于测试
  47. void PrintAll();
  48. };


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



  
  
  1. void HandCardData::ClearPutCardList()
  2. {
  3. color_nPutCardList.clear();
  4. value_nPutCardList.clear();
  5. uctPutCardType.cgType = cgERROR;
  6. uctPutCardType.nCount = 0;
  7. uctPutCardType.nMaxCard = -1;
  8. uctPutCardType.nValue = 0;
  9. return;
  10. }

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


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


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

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

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


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

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


  
  
  1. void HandCardData::Init()
  2. {
  3. //根据花色手牌获取权值手牌
  4. get_valueHandCardList();
  5. //手牌 排序
  6. SortAsList(color_nHandCardList);
  7. SortAsList(value_nHandCardList);
  8. //当前手牌个数
  9. nHandCardCount = value_nHandCardList.size();
  10. }

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


  
  
  1. void HandCardData::PrintAll()
  2. {
  3. cout << "color_nHandCardList:" << endl;
  4. for ( vector< int>::iterator iter = color_nHandCardList.begin(); iter != color_nHandCardList.end(); iter++)
  5. cout << get_CardsName(*iter) << (iter == color_nHandCardList.end() - 1 ? '\n' : ',');
  6. cout << endl;
  7. /*
  8. cout << "value_nHandCardList:" << endl;
  9. for (vector<int>::iterator iter = value_nHandCardList.begin(); iter != value_nHandCardList.end(); iter++)
  10. cout << *iter << (iter == value_nHandCardList.end() - 1 ? '\n' : ',');
  11. cout << endl;
  12. cout << "value_aHandCardList:" << endl;
  13. for (int i = 0; i < 18; i++)
  14. {
  15. cout << value_aHandCardList[i] << (i == 17 ? '\n' : ',');
  16. }
  17. cout << endl;
  18. cout << "nHandCardCount:" << nHandCardCount << endl;
  19. cout << endl;
  20. cout << "nGameRole:" << nGameRole << endl;
  21. cout << endl;
  22. */
  23. }

接下来就说出牌的函数了


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

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





  
  
  1. bool HandCardData::PutCards()
  2. {
  3. for ( vector< int>::iterator iter = value_nPutCardList.begin(); iter != value_nPutCardList.end(); iter++)
  4. {
  5. int color_nCard = -1;
  6. if (PutOneCard(*iter, color_nCard))
  7. {
  8. color_nPutCardList.push_back(color_nCard);
  9. }
  10. else
  11. {
  12. return false;
  13. }
  14. }
  15. nHandCardCount -= value_nPutCardList.size();
  16. return true;
  17. }


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

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

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


  
  
  1. bool HandCardData::PutOneCard( int value_nCard, int &color_nCard)
  2. {
  3. bool ret = false;
  4. //value状态数组处理
  5. value_aHandCardList[value_nCard]--;
  6. if (value_aHandCardList[value_nCard] < 0)
  7. {
  8. return false;
  9. }
  10. //value列表数组处理
  11. for ( vector< int>::iterator iter = value_nHandCardList.begin(); iter != value_nHandCardList.end(); iter++)
  12. {
  13. if (*iter == value_nCard)
  14. {
  15. value_nHandCardList.erase(iter);
  16. ret = true;
  17. break;
  18. }
  19. }
  20. // color列表数组处理
  21. int k = (value_nCard - 3) * 4; //数值转换
  22. for ( vector< int>::iterator iter = color_nHandCardList.begin(); iter != color_nHandCardList.end(); iter++)
  23. {
  24. for ( int i = k; i < k + 4; i++)
  25. {
  26. if (*iter == i)
  27. {
  28. color_nCard = i;
  29. color_nHandCardList.erase(iter);
  30. return ret;
  31. }
  32. }
  33. }
  34. return false;
  35. }


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

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


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




猜你喜欢

转载自blog.csdn.net/King_fengzi/article/details/89326203