简易麻将平胡算法

本文介绍了麻将平胡的计算方法,包括检查手牌数量、识别三牌和对子、组合三牌并验证胡牌条件,以及测试和分析胡牌牌型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、平胡简介

麻将平胡牌(无财神):N(0、1、2、3、4)个三牌和1个对子,手牌总数为 N * 3 + 2。


二、平胡计算

1、先检测手牌数量是否符合要求。

2、获得可能的三牌集(三连[1, 2, 3]、三同[1, 1, 1])和对子集(对子[1, 1])。

3、使用组合函数,获得所有可能的三牌组合集,每个组合包括N个三牌。

4、若无三牌组合,则是单调平胡,则直接遍历对子集,若有对子在手牌中数量足够,则可胡牌。

5、若有三牌组合,遍历三牌组合集,若三牌组合集中所有的三牌都在手牌中数量足够,再遍历对子集,若有对子在手牌中数量足够,则可胡牌。


三、测试函数

测试函数中的arr的下标为麻将牌唯一标志,值为该麻将牌数量。

#define LEN 34		// 万(0 - 8)、条(9 - 17)、筒(18 - 26)、东南西北中发白(27 - 33) 

enum GROUP_TYPE
{
	GROUP_GANG,
	GROUP_LIAN,
	GROUP_PENG,
	GROUP_PAIR
};

struct CardGroup
{
	int card;
	GROUP_TYPE type;
};

int main(int argc, char *argv[])
{
	int arr[LEN] = {0};
	arr[0] = 2;
	finishCard(arr, 0);

	arr[0] = 2;
	arr[1] = 3;
	finishCard(arr, 1);

	arr[0] = 2;
	arr[1] = 3;
	arr[9] = 1;
	arr[10] = 1;
	arr[11] = 1;
	finishCard(arr, 2);

	arr[0] = 2;
	arr[1] = 3;
	arr[8] = 3;

	arr[9] = 1;
	arr[10] = 1;
	arr[11] = 1;
	finishCard(arr, 3);

	arr[0] = 2;
	arr[1] = 3;
	arr[8] = 3;

	arr[9] = 1;
	arr[10] = 1;
	arr[11] = 1;

	arr[30] = 3;
	finishCard(arr, 4);

	return 0;
}

四、胡牌牌数检测

bool checkCardCount(int cardData[LEN], int groupSize)
{
	// 三牌组合最多只有4种
	if (groupSize < 0 || groupSize > 4) return false;

	int cardCount = 0;
	for (int i = 0; i < LEN; i++)
	{
		// 每一种牌最多只能有4张
		if (cardData[i] < 0 || cardData[i] > 4) return false;
		cardCount += cardData[i];
	}

	// 牌总数检测
	if (cardCount != (groupSize * 3) + 2) return false;

	return true;
}

五、获得可能的三牌集和对子集

void getCardGroupsAndPairs(int cardData[LEN], vector<CardGroup> &cardGroups, vector<CardGroup> &cardPairs)
{
	for (int i = 0; i < LEN; i++)
	{
		if (cardData[i] <= 0) continue;

		CardGroup cardGroup;
		cardGroup.card = i;

		// 三连
		if ((i >= 0 && i <= 6) ||		// 一万 - 七万
			(i >= 9 && i <= 15) ||		// 一条 - 七条
			(i >= 18 && i <= 24))		// 一筒 - 七筒
		{
			if (cardData[i] > 0 && cardData[i + 1] > 0 && cardData[i + 2] > 0)
			{
				cardGroup.type = GROUP_LIAN;
				cardGroups.push_back(cardGroup);
			}
		}

		// 三同
		if (cardData[i] >= 3)
		{
			cardGroup.type = GROUP_PENG;
			cardGroups.push_back(cardGroup);
		}

		// 对子
		if (cardData[i] >= 2)
		{
			cardGroup.type = GROUP_PAIR;
			cardPairs.push_back(cardGroup);
		}
	}
}

六、组合函数

点击打开链接


七、胡牌分析

最后打印出所有胡牌的牌型

void finishCard(int cardData[LEN], int groupSize)
{
	// 胡牌牌数检测
	if (!checkCardCount(cardData, groupSize)) return;

	// 获取所有的三牌、对子
	vector<CardGroup> cardGroups;			// 三牌(三连、三同)
	vector<CardGroup> cardPairs;			// 对子
	getCardGroupsAndPairs(cardData, cardGroups, cardPairs);

	// 获得组合集 groups (使用组合函数),每个组合元素个数为 groupSize
	vector<vector<int>> groups;
	combination(cardGroups.size(), groupSize, groups);

	// 获得可以胡牌的组合集 groupsOk(三牌和对子都符合要求)
	vector<vector<int>> groupsOk;
	int t[LEN] = {0};

	// 若无三牌,对子是否符合要求
	if (groups.size() <= 0)
	{
		vector<int> group;
		memcpy(t, cardData, sizeof(t));

		for (int i = 0; i < cardPairs.size(); i++)
		{
			CardGroup &cg = cardPairs[i];
			if (t[cg.card] >= 2)
			{
				group.push_back(i);
				groupsOk.push_back(group);
				group.pop_back();
			}
		}
	}

	// 若有三牌,三牌和对子是否符合要求
	for (int i = 0; i < groups.size(); i++)
	{
		bool isOk = true;
		vector<int> &group = groups[i];
		memcpy(t, cardData, sizeof(t));

		// 三牌是否符合要求
		for (int j = 0; j < group.size(); j++)
		{
			int cardGroupIndex = group[j];
			CardGroup &cg = cardGroups[cardGroupIndex];
			if (cg.type == GROUP_PENG)			// 三同		
			{
				t[cg.card] -= 3;
				if (t[cg.card] < 0) isOk = false;
			}
			else if (cg.type == GROUP_LIAN)		// 三连
			{
				if (--t[cg.card] < 0 || --t[cg.card + 1] < 0 || --t[cg.card + 2] < 0) isOk = false;
			}
			else
			{
				isOk = false;
			}
			if (!isOk) break;
		}

		// 对子是否符合要求
		if (isOk)
		{
			for (int i = 0; i < cardPairs.size(); i++)
			{
				CardGroup &cg = cardPairs[i];
				if (t[cg.card] >= 2)
				{
					group.push_back(i);
					groupsOk.push_back(group);
					group.pop_back();
				}
			}
		}
	}

	// 打印胡牌结果
	cout << "success size: " << groupsOk.size() << endl;
	for (int i = 0; i < groupsOk.size(); i++)
	{
		vector<int> &groupOk = groupsOk[i];
		for (int j = 0; j < groupOk.size(); j++)
		{
			CardGroup &cg = (j == groupOk.size() - 1) ? cardPairs[groupOk[j]] : cardGroups[groupOk[j]];
			if (cg.type == GROUP_LIAN)
			{
				cout << "(" << cg.card << ", " << cg.card + 1 << ", " << cg.card + 2 << ") ";
			}
			else if (cg.type == GROUP_PENG)
			{
				cout << "(" << cg.card << ", " << cg.card << ", " << cg.card << ") ";
			}
			else if (cg.type == GROUP_PAIR)
			{
				cout << "(" << cg.card << ", " << cg.card << ") ";
			}
		}
		cout << "\n-----------------------------" << endl;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值