炸金花
这周老师布置了一个"很困难的实验",大致的内容如下:
我大致翻译一下,就是给定的五种牌,判断这五张牌能够组成的最好的特殊组合。
但是在输入方面需要注意的是,就是输入可能是非法输入(输入的牌不存在),或者是重复输入(重复输入已经输入过的牌),我这里的想法就是预先建立一个映射:
for (int i = 0;i < 4;i++) {
//首先我们要建立映射
switch (i){
//表示牌型名
case 0:x = "c";break; case 1:x = "d";break;
case 2:x = "h";break; case 3:x = "s";break;
}
for (int j = 0;j < 13;j++) {
string xx;
switch (j) {
//牌在某个牌型里的序号
case 1:xx = "2" + x;break; case 2:xx = "3" + x;break; case 3:xx = "4" + x;break;
case 4:xx = "5" + x;break; case 5:xx = "6" + x;break; case 6:xx = "7" + x;break;
case 7:xx = "8" + x;break; case 8:xx = "9" + x;break; case 9:xx = "t" + x;break;
case 10:xx = "j" + x;break; case 11:xx = "q" + x;break;
case 12:xx = "k" + x;break; case 13:xx = "a" + x;break;
}
card_id[xx] = 1+(13*i+j)*10;//其中1表示是否已经取过这张牌了
}
}
这里的1表示是否取过,是为了后面判断是否取过这张牌做铺垫。
接下来是输入:
int i;
for (i = 0;i <5;) {
cout << "Enter a card:"; cin >> s;
//如果映射中不存在,肯定就是张坏牌
if (!card_id.count(s)) {
cout << "Bad card,ignored.\n";continue; }
//映射中存在,但是已经取过了,就是非法取牌
if (card_id[s] % 10 == 0) {
cout << "Duplicate card,ignored.\n";continue; }
card_id[s]--; a[i] = card_id[s] / 10;i++;
}
映射和输入完毕,接下来我们只需要处理判断牌型就可以了,第一种是同花顺,事实上就是顺子和同花的结合。
顺子函数:
bool is_straight(int b,int c,int d,int e,int f) {
//判断是否为顺子
//将每张牌的序号除以13的余数表示这张牌在他们牌堆里的序号,如果差值都为1就是顺子了
int bb = b % 13, cc = c % 13, dd = d % 13, ee = e % 13, ff = f % 13;
if (cc - bb == 1 && dd - cc == 1 && ee - dd == 1 && ff - ee == 1) return true;
else return false;
}
同花函数:
bool is_flush(int b, int c, int d, int e, int f){
//判断是否为同花
//将每张牌的序号除以13得到值表示处于第几个牌型,五张牌牌型相同即表示为同花顺
if (b / 13 == c / 13 && c / 13 == d / 13 && d / 13 == e / 13 && e / 13 == f / 13) return true;
else return false;
}
接下来就是四个头,三个头,对子函数的编译,这三个函数的内核算法本质是类似的。
四个头函数:
bool is_four(int b, int c, int d, int e, int f) {
//判断是否为炸弹
int num[20]; memset(num, 0, sizeof(num));//本质是桶排序
//以牌在他们的牌堆里的序号作为桶的序号,如果有一个桶里的值为4,就表示含有炸弹
num[b % 13]++; num[c % 13]++; num[d % 13]++; num[e % 13]++; num[f % 13]++;
for (int i = 0;i < 13;i++) {
if (num[i] == 4) return true;}
return false;
}
三个头函数是一样的:
bool is_three(int b, int c, int d, int e, int f) {
//判断是否有三个头
int num[20]; memset(num, 0, sizeof(num));//思想上和判断炸弹函数一样的
num[b % 13]++; num[c % 13]++; num[d % 13]++; num[e % 13]++; num[f % 13]++;
for (int i = 0;i < 13;i++) {
if (num[i] == 3) return true; }
return false;
}
需要注意的是,由于有一种牌型是two_pairs。也就是说pair函数返回的应该是这个牌型里的对子个数:
int pair_num(int b, int c, int d, int e, int f) {
//对子个数函数
int num[20],ans=0; memset(num, 0, sizeof(num));//思想本质和前面两个函数是一样的
num[b % 13]++; num[c % 13]++