麻将胡牌算法

用数字代替麻将中的所有牌:

一万~九万    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]?@"胡":@"不胡");












  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值