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

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

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

 

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



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

 

 

[cpp] view plain copy
 
  1. void HandCardData::ClearPutCardList()  
  2. {  
  3.     color_nPutCardList.clear();  
  4.   
  5.     value_nPutCardList.clear();  
  6.   
  7.     uctPutCardType.cgType = cgERROR;  
  8.     uctPutCardType.nCount = 0;  
  9.     uctPutCardType.nMaxCard = -1;  
  10.     uctPutCardType.nValue = 0;  
  11.   
  12.     return;  
  13. }  


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

 

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

 

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

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

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

 

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


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

 

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


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

 

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


接下来就说出牌的函数了

 

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

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

 

 

 

[cpp] view plain copy
 
  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.   
  16.     nHandCardCount -= value_nPutCardList.size();  
  17.     return true;  
  18. }  



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

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

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

 

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



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

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

 

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

 

posted on 2018-06-12 22:34  &大飞  阅读(483)  评论(0编辑  收藏  举报

导航