四川麻将胡牌

用1-9 一万到九万 10-18 一筒到九筒 19-27 一条到九条 这里就无视缺门了,缺门的问题很简单就不用我多说了。
代码:

<?php
//1-9 一万到九万 10-18 一筒到九筒 19-27 一条到九条


$paiArr = [1,1,1,1,2,2,2,2,3,3,3,3,4,4]; //123 123 123 123 44
$paiArr1 = [1,2,2,2,3,3,3,4,4,10,10,10,11,11];// 123 234 234 101010 1111
$paiArr2 = [7,7,7,8,8,8,9,9,9,10,10,11,11,11];//789 789 789 111111 1010
$paiArr3 = [1,2,3,4,5,6,7,8,9,10,11,12,13,13];//123 456 789 101112 1313
asort($paiArr);//每个都要从小到大排序的
asort($paiArr1);//每个都要从小到大排序的
asort($paiArr2);//每个都要从小到大排序的
asort($paiArr3);//每个都要从小到大排序的
echo checkHu($paiArr);
echo checkHu($paiArr1);
echo checkHu($paiArr2);
echo checkHu($paiArr3);


function checkHu($arr){//主函数
    $jiangArr = checkJiang($arr);

    foreach ($jiangArr as $key=>$index){
        $tmpArr = $arr;
        unset($tmpArr[$index]);//去除一对将
        unset($tmpArr[$index+1]);//去除一对将
        $tmpArr = array_values($tmpArr);
        for ($i =1;$i<=4;$i++){//最多4个123型的牌,四次循环
            $count1 = count($tmpArr);
            $tmpArr = check123Pai($tmpArr);
            $count2 = count($tmpArr);
            if ($count2 == $count1)break;//如果已经找不到123型的牌就结束
        }

        for ($i =1;$i<=4;$i++){//最多4个111型的牌,四次循环
            $count1 = count($tmpArr);
            $tmpArr = check111Pai($tmpArr);
            $count2 = count($tmpArr);
            if ($count2 == $count1)break;//如果已经找不到111型的牌就结束
        }
        if (count($tmpArr)==0){
            return 1;
        }
    }
    return 0;
}
function  check123Pai($arr){//找出123类型牌,并将这些牌去除(从第一个牌开始算,看看后面有没有比它大1的,然后再找有没有比它大2的,都有的话就把三张牌剔除,此时数组key变化了,需要array_values一下)
    $count = count($arr);
    for ($i=0;$i<=$count-3;$i++){
        $minPai = $arr[$i];
        $max = $minPai>18? 27 : ($minPai>9? 18:9);//这里保证9 10 11这种牌不算(九万一筒二筒不能算的)
        for ($j=$i+1;$j<=$count-2;$j++){
            if ($arr[$j]<$max&&$arr[$j]==$arr[$i]+1 ){
                for ($k=$j+1;$k<=$count-1;$k++){
                    if ($arr[$k]<=$max&&$arr[$k]==$arr[$j]+1 ){
                        unset($arr[$i]);
                        unset($arr[$j]);
                        unset($arr[$k]);
                        return array_values($arr);
                    }
                }
            }

        }
    }

    return $arr;

}
function  check111Pai($arr){//找出111类型牌并将这些牌去除(从第一个牌开始算,每次加3,保证三张一样就行,这里有人会问那要是1111这种牌怎么算。这里就涉及到算法的思想了,我先剔除了将,又剔除了123型的牌,如果还有1111型的牌,那肯定胡不了)
    $count = count($arr);
    for ($i=0;$i<=$count-3;$i=$i+3){
        if ($arr[$i]==$arr[$i+1]&&$arr[$i]==$arr[$i+2]){
            unset($arr[$i]);
            unset($arr[$i+1]);
            unset($arr[$i+2]);
            return array_values($arr);
        }
    }
    return $arr;

}





function  checkJiang($arr){//返回一对将的offset
    $count = count($arr);
    $jiangOffset = [];
    //里面会有重复的
    for ($i=0;$i<=$count-2;$i++){
        if ($arr[$i] ==$arr[$i+1]){
            $jiangOffset[] = $i;
        }
    }
    //去重
    $repeatArr = [];
    $tmpCount = count($jiangOffset)-2;
    for ($i=0;$i<=$tmpCount;$i++){
        if ($arr[$jiangOffset[$i]] ==$arr[$jiangOffset[$i+1]]){
            $repeatArr[] = $jiangOffset[$i+1];
        }
    }
    foreach ($jiangOffset as $key=>$value){
        if (in_array($value,$repeatArr)){
            unset($jiangOffset[$key]);
        }
    }
    return array_values($jiangOffset);


}
function tingPai($arr){//返回听牌的数据
    $mineArr = [];
    asort($arr);
    for ($i=0;$i<=count($arr)-4;$i+=4){
        if ($arr[$i] ==$arr[$i+3]){
            $mineArr[] = $arr[$i];
        }
    }
    $tingPaiArr = [];
    for ($i=1;$i<=27;$i++){
        if (in_array($i,$mineArr)){
            continue;
        }
        $arr1 =  $arr;
        $arr1[] = $i;
        asort($arr1);
        if (checkHu($arr1)){
            $tingPaiArr[] = $i;
        }

    }
    return $tingPaiArr;

}

思路
规则:麻将四坎牌一对将代表基本胡,坎牌比如一万二万三万,三筒三筒三筒。一对将就相同的两张牌比如一条一条,类似于斗地主里的对子。基本胡的基础上才衍生出对对胡,清一色啥的。

首先找出牌里的一对将,当然程序不知道哪对将才能胡牌,这里找出所有的将进行遍历。然后先把将去掉,剩下的判断111型的牌与123型的牌。这里问题来了,先判断哪个类型?这里必须先判断123型,再判断111型,具体原因是笔者实践得出来的。其他算法可能不一样,笔者的算法就是这个顺序。判断能胡牌了,然后再判断什么天胡地胡啥的就方便了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值