清一色麻将人和率计算器

玩清一色麻将天天点人和?

这个程序是拿来计算亲家第一打点人和概率用的

实现方式就是大力枚举手牌,从以下数据可以看出枚举是很容易的

  • 本质不同的 1313 张配牌 9360093600
  • 本质不同的 1414 张配牌 118800118800
  • 本质不同的 13+1413+14 张配牌 352013490352013490

实际上限制了一家配牌枚举另一家通常只有几千种

(顺便这个样例可以产生最大的输出 286422497420\frac{286422}{497420}

// 清一色麻人和率计算器 by Zhengfourth
// 命令格式:14个字符描述亲家手牌,例如:renhe 11115588889999
// 或者9个字符描述每种牌的数量,例如:renhe 400020044
// 输出表示如果你切出每一张牌对应的铳率

#include <cstdio>
#include <cstring>
#include <cstdlib>
[[noreturn]] void __ILLEGAL(int line) {
	printf("%d:不合法的输入", line);
	exit(-1);
}
#define ILLEGAL() __ILLEGAL(__LINE__)
const int c[5][5] = {{1},{1,1},{1,2,1},{1,3,3,1},{1,4,6,4,1}};
int a[9], b[9], ans[9];
bool dfsH(int n, int i, bool sh) {
	if (!n) return true;
	if (i == 9) return false;
	if (!b[i]) return dfsH(n, i+1, false);
	if (!sh && b[i] >= 3) {
		b[i] -= 3;
		bool ret = dfsH(n-3, i, true);
		b[i] += 3;
		if (ret) return true;
	}
	if (!sh && b[i] >= 2 && n % 3 == 2) {
		b[i] -= 2;
		bool ret = dfsH(n-2, i, true);
		b[i] += 2;
		if (ret) return true;
	}
	if (i < 7 && b[i+1] >= 1 && b[i+2] >= 1) {
		b[i]--; b[i+1]--; b[i+2]--;
		bool ret = dfsH(n-3, i, true);
		b[i]++; b[i+1]++; b[i+2]++;
		if (ret) return true;
	}
	return false;
}
bool check() {
	bool qit = true;
	for (int j = 0; j < 9; j++)
		if (b[j] != 2 && b[j] != 0) qit = false;
	if (qit) return true;
	return dfsH(14, 0, false);
}
void test(int nc) {
	for (int i = 0; i < 9; i++) if (a[i]) {
		b[i]++;
		if (check()) ans[i] += nc;
		b[i]--;
	}
}
void dfsP(int i, int x, int nc) {
	if (i == 9) {
		if (x == 13) test(nc);
		return;
	}
	for (b[i] = 0; b[i]+a[i] <= 4 && x+b[i] <= 13; b[i]++) {
		dfsP(i+1, x+b[i], nc*c[4-a[i]][b[i]]);
	}
}
int main(int argc, char** argv) {
	if (argc != 2) ILLEGAL();
	char *in = argv[1];
	int len = strlen(in);
	if (len == 14) {
		for (int i = 0; i < 14; i++) {
			if (in[i] < '1' && in[i] > '9') ILLEGAL();
			a[in[i]-'1']++;
		}
	} else if (len == 9) {
		int all = 0;
		for (int i = 0; i < 9; i++) {
			if (in[i] < '0' && in[i] > '4') ILLEGAL();
			a[i] = in[i] - '0';
			all += a[i];
		}
		if (all != 14) ILLEGAL();
	} else ILLEGAL();
	dfsP(0, 0, 1);
	int q = 497420;
	for (int i = 0; i < 9; i++) if (a[i]) {
		printf("%d: %6d/497420 = %lf\n", i+1, ans[i], 1.0d*ans[i]/q);
	}
}