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

举报
九日王朝 发表于 2019/01/22 11:46:33 2019/01/22
【摘要】 上一章我们定义了基本的数据结构,相信大家看到手牌类里面那么多出牌序列时一定会比较愤慨。。。其实一开始写的时候我也是觉得很脑残,不过后续开发证明了这样的结构还是可以的,因为只要我封装了一层数据转换,接下来所有的算法策略都只用到2个成员变量,状态数据及手牌数量。特别便于调试、管理。那么接下来就写出类成员函数的实现方法//手牌数据类class HandCardData{ public: //构造...

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


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


//手牌数据类

class HandCardData

{

 

 

public:

//构造函数

HandCardData::HandCardData()

{

}

//析构函数

virtual HandCardData::~HandCardData()

{

}

 

public:

 //手牌序列——无花色,值域3~17

    vector <int> value_nHandCardList;

 

 //手牌序列——状态记录,便于一些计算,值域为该index牌对应的数量0~4

int value_aHandCardList[18] = { 0 };

 

 //手牌序列——有花色,按照从大到小的排列  56,52:大王小王……4~0:红3黑3方3花3

vector <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算法——第四章の权值定义


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。