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


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

其实一开始写的时候我也是觉得很脑残,不过后续开发证明了这样的结构还是可以的,因为只要我封装了一层数据转换,接下来所有的算法策略都只用到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算法——第四章の权值定义




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值