用数字代替麻将中的所有牌:
一万~九万 1~9
一筒~九筒 11~19
一条~九条 21~29
东、南、西、北、中、发、白 31~37
胡牌的种类:对对胡、十三幺和33332
判断胡牌的过程(以下所说的规则,都是针对手牌已经按从小到大的顺序排序):
1、首先判断手牌的总数是否为3n+2,如果不是肯定不是胡牌。
2、先从特殊的下手,如果手牌为14张的时候,就有可能是“对对胡”或者“十三幺”,先判断是否为这两种特殊胡牌,如果不是,再继续下面的判断。排除特殊情况,那么要胡,就只能是“33332”。
3、遍历所有的手牌,找到一种牌的数量>=2的,那么“33332”中的“2”就有可能从这种牌中抽取2张作为这个“2”,然后把这2张去掉,剩下的手牌就是3n张,再判断剩下的3n张牌是否能组成顺子或者是暗刻,如果可以全部组成,那么说明这牌就胡了。否则需要找下一种牌当成“2”,再重复上面的判断,直到找到为止,找不到就是不胡啦。
判断剩下的3n张牌是否能组成顺子或者是暗刻,是通过判断第一种牌的数量:
①如果是1张或2张,要胡牌的话,它必须和后面的牌组成顺子,否自不能胡。如果可以,将组成顺子的牌移除,接着处理剩下的牌。
②如果是3张,要胡牌有两种可能,一种是把3张当做是暗刻,另一种是这3张都与后面的牌组成顺子。如果只是判断胡不胡牌,这两种任意一种都是一样的,如果要计算分数,就要自己分开算了。
③如果是4张,要胡牌的话,有1张要和后面的牌组成顺子,剩下的3张牌又可以继续②操作。
整个过程可以通过函数的递归调用,每次处理一张,如果不能凑成顺子或者暗刻就不能胡,直接返回错误,如果可以则继续判断,直到牌数为0,则就是胡了,返回成功即可。
下面是我用OC写的胡牌算法,初步验证可以,可能有漏洞,以后遇到再修改,如果你们发现问题,也可以留言,我再修复更新。
// 检查手牌是否符合胡牌规则
- (BOOL)checkHuWithHandCards:(NSArray *)handCards
{
// 只有手牌是14张,才有可能是“对对胡”或者“十三幺”
if (handCards.count == 14)
{
// 对对胡
BOOL isDuiDuiHu = true;
NSMutableArray *ArrM1 = [NSMutableArray arrayWithArray:handCards];
while (ArrM1.count && isDuiDuiHu)
{
if (ArrM1[0] == ArrM1[1])
{
[ArrM1 removeObjectAtIndex:0];
[ArrM1 removeObjectAtIndex:0];
}
else
{
isDuiDuiHu = false;
break;
}
}
if (isDuiDuiHu)
{
return true;
}
// 十三幺
BOOL isShiSanYao = false;
NSArray *shiSanYaoArr = @[@1, @9, @11, @19, @21, @29, @31, @32, @33, @34, @35, @36, @37];
NSMutableArray *arrM2 = [NSMutableArray arrayWithArray:handCards];
for (int j = 0; j < handCards.count - 1; ++j)
{
if (handCards[j] == handCards[j + 1])
{
[arrM2 removeObjectAtIndex:j];
break;
}
}
for (int i = 0; i < shiSanYaoArr.count; ++i)
{
isShiSanYao = false;
if ([arrM2[i] intValue] == [shiSanYaoArr[i] intValue])
{
isShiSanYao = true;
}
else
{
break;
}
}
if (isShiSanYao)
{
return true;
}
}
// 其他胡牌(3、3、3、3、2)
return [self checkHu33332WithCards:[self changeHandCards:handCards]];
}
// 其他胡牌(3、3、3、3、2)
- (BOOL)checkHu33332WithCards:(NSArray *)cards
{
for (int i = 0; i < cards.count; ++i)
{
if ([cards[i][1] intValue] >= 2)
{
NSMutableArray *arrM = [NSMutableArray arrayWithArray:cards];
// 先把一对牌找出来,排除掉之后继续下面的判断
if ([cards[i][1] intValue] == 2)
{
[arrM removeObjectAtIndex:i];
}
else
{
[arrM replaceObjectAtIndex:i withObject:@[cards[i][0], [NSNumber numberWithInt:[cards[i][1] intValue] - 2]]];
}
if ((arrM.count && [self checkForCards:arrM]) || !arrM.count)
return true;
}
}
return false;
}
// 按照第一张牌的数量,分类检查
- (BOOL)checkForCards:(NSArray *)cards
{
switch ([cards[0][1] intValue])
{
case 1:
case 2:
if (![self checkFirstCard1Or2:cards])
return false;
break;
case 3:
if (![self checkFirstCard3:cards])
return false;
break;
case 4:
if (![self checkFirstCard4:cards])
return false;
break;
default:
break;
}
return true;
}
// 第一张牌的数量是1或2
- (BOOL)checkFirstCard1Or2:(NSArray *)cards
{
// 只能与后面的牌组成顺子,不然就胡不了了
if (cards.count >= 3 && [cards[0][0] intValue] == [cards[1][0] intValue] - 1 && [cards[0][0] intValue] == [cards[2][0] intValue] - 2)
{
NSMutableArray *arrM = [NSMutableArray arrayWithArray:cards];
for (int i = 2; i >= 0; --i)
{
if ([cards[i][1] intValue] > 1)
{
[arrM replaceObjectAtIndex:i withObject:@[cards[i][0], [NSNumber numberWithInt:[cards[i][1] intValue] - 1]]];
}
else
{
[arrM removeObjectAtIndex:i];
}
}
if ((arrM.count && [self checkForCards:arrM]) || !arrM.count)
return true;
}
return false;
}
// 第一张牌的数量是3
- (BOOL)checkFirstCard3:(NSArray *)cards
{
// 可以与后面的牌组成顺子,这里为了方便,只是统一成暗刻
NSMutableArray *arrM = [NSMutableArray arrayWithArray:cards];
[arrM removeObjectAtIndex:0];
if ((arrM.count && [self checkForCards:arrM]) || !arrM.count)
return true;
return false;
}
// 第一张牌的数量是4
- (BOOL)checkFirstCard4:(NSArray *)cards
{
// 先把3张当成暗刻,再继续下一步判断
NSMutableArray *arrM = [NSMutableArray arrayWithArray:cards];
[arrM replaceObjectAtIndex:0 withObject:@[cards[0][0], [NSNumber numberWithInt:1]]];
return [self checkForCards:arrM];
}
// 将手牌数组转化为二维数组,0、值 1、数量
- (NSArray *)changeHandCards:(NSArray *)handCards
{
NSMutableArray *cardsArrM = [NSMutableArray array];
int count = 1;
for (int i = 0; i < handCards.count; ++i)
{
if (i == handCards.count - 1)
{
[cardsArrM addObject:@[handCards[i], [NSNumber numberWithInt:count]]];
break;
}
if (handCards[i] == handCards[i + 1])
{
count++;
}
else
{
[cardsArrM addObject:@[handCards[i], [NSNumber numberWithInt:count]]];
count = 1;
}
}
return cardsArrM;
}
// 计算数组中有多少张牌
- (int)cardsCount:(NSArray *)cards
{
int count = 0;
for (int i = 0; i < cards.count; ++i)
{
count = count + [cards[i][1] intValue];
}
return count;
}
检查的牌:
NSArray *arr1 = @[@1, @9, @11, @19, @21, @21, @29, @31, @32, @33, @34, @35, @36, @37];
NSArray *arr2 = @[@1, @1, @11, @11, @21, @21, @31, @31, @33, @33, @35, @35, @37, @37];
NSArray *arr3 = @[@1, @1, @21,@22,@23,@24,@25,@26,@27,@28,@29,@13,@14,@15];
NSArray *arr4 = @[@7, @8, @9, @21, @22, @23, @23, @23, @24, @25, @26, @13, @14, @15];
NSLog(@"----%@", [self checkHuWithHandCards:arr1]?@"胡":@"不胡");
NSLog(@"----%@", [self checkHuWithHandCards:arr2]?@"胡":@"不胡");
NSLog(@"----%@", [self checkHuWithHandCards:arr3]?@"胡":@"不胡");
NSLog(@"----%@", [self checkHuWithHandCards:arr4]?@"胡":@"不胡");