• 麻将胡牌算法,带癞子


    貌似去年去面试一家公司,问了麻将的算法。虽然之前做过广东麻将,但是胡牌算法在服务端,就没有在意。

    现在在网上搜了一些算法试了试 = =!

    麻将普通的胡牌就是刻子+顺子+将。癞子可以充当任意一张牌。

    参考:

    https://xingbinice.iteye.com/blog/2380673

    网上搜罗的算法,先取将牌,然后递归判断剩下的牌是否能组成刻子或顺子。

     public canHuLaizi(cards, laizi) {  
            if ((cards.length + laizi + 1) % 3 != 0) {  
                // 若牌张数不是2、5、8、11、14则不能胡  
                return false;  
            }  
            // 排序方便胡牌判断  
            cards.sort(function(a, b) {  
                return a - b;  
            })  
            // 依次删除一对牌做将,其余牌全部成扑则可胡  
            for (var i = 0; i < cards.length; i++) {  
                if (i > 0 && cards[i] == cards[i - 1]){  
                    // 和上一次是同样的牌,避免重复计算  
                    continue;   
                }  
                if ((i + 1 < cards.length && cards[i] == cards[i + 1]) || laizi > 0) {  
                    // 找到对子、或是用一张癞子拼出的对子  
                    var puCards = cards.slice();  
                    var puLaizi = laizi;  
                    puCards.splice(i, 1);  
                    if (puCards[i] == cards[i]) {  
                        puCards.splice(i, 1);  
                    }  
                    else {  
                        puLaizi--;  
                    }  
                    // 删去对子判断剩下的牌是否成扑  
                    if (this.isPu(puCards, puLaizi)) {  
                        return true;  
                    }  
                }  
            }  
            if (laizi >= 2 && this.isPu(cards, laizi - 2)) {  
                // 两个癞子做将牌  
                return true;  
            }  
            return false;  
        } 
    

     

    递归判断数组cards是否能组成顺子或刻子

       public isPu(cards, laizi) {  
            if (cards.length == 0) {  
                return true;  
            }  
            // 若第一张是顺子中的一张  
            for (var first = cards[0] - 2; first <= cards[0]; first++) {  
                if(first % 10 > 7 || (laizi == 0 && first < cards[0])) {   
                    // 剪枝:顺子第一张牌不会大于7点、无赖子情况下顺子第一张只能用手上的牌  
                    continue;  
                }  
                var shunCount = 0;  
                for (var i = 0; i < 3; i++) {  
                    if (cards.indexOf(first + i) >= 0) {  
                        shunCount++;  
                    }  
                }  
                if (shunCount == 3 || shunCount + laizi >= 3) {  
                    // 找到包含第一张牌的顺子  
                    var puCards = cards.slice();  
                    var puLaizi = laizi;  
                    for (var i = 0; i < 3; i++) {  
                        var deletePos = puCards.indexOf(first + i);  
                        if (deletePos >= 0) {  
                            puCards.splice(deletePos, 1);  
                        }  
                        else {  
                            puLaizi--;  
                        }  
                    }  
                    if (this.isPu(puCards, puLaizi)) {  
                        // 剩下的牌成扑  
                        return true;  
                    }  
                }  
            }  
            // 若第一张是刻子中的一张  
            var keziCount = 1;  
            var keziCard = cards[0];  
            if (cards[1] == keziCard) {  
                keziCount++;  
            }  
            if (cards[2] == keziCard) {  
                keziCount++;  
            }  
            if (keziCount == 3 || keziCount + laizi >= 3) {  
                var puCards = cards.slice();  
                var puLaizi = laizi;  
                for (var i = 0; i < 3; i++) {  
                    var deletePos = puCards.indexOf(keziCard);  
                    if (deletePos >= 0) {  
                        puCards.splice(deletePos, 1);  
                    }  
                    else {  
                        puLaizi--;  
                    }  
                }  
                if (this.isPu(puCards, puLaizi)) {  
                    return true;  
                }  
            }  
            return false;  
        }  
    

    测试1万次,含4癞子是否能胡牌。大概花了50ms。

            // cards:手牌数组,不超过14张牌,每张牌由整数表示如下  
            // 条:1, 2, 3, 4, 5, 6, 7, 8, 9,  
            // 万:11, 12, 13, 14, 15, 16, 17, 18, 19,  
            // 筒:21, 22, 23, 24, 25, 26, 27, 28, 29,  
            // 东南西北中发白:31, 41, 51, 61, 71, 81, 91,  
            //   
            // laizi:癞子数量,用整数表示 
            let cardList = [1,1,2,3,4,23,24,27,28,5];
            let laizi = 4;
            let bHuPai;
            let startTime = egret.getTimer();
            for(let i=0;i<10000;i++){
                bHuPai = this.canHuLaizi(cardList, laizi);
            }
            console.log(egret.getTimer() - startTime, bHuPai);  //51  true
    

      

    判断听牌

    判断听牌,就是将条,万,索,字共34张麻将牌遍历一遍加入手牌,看是否能胡,如果能胡,则表示听此张牌。

  • 相关阅读:
    一个贼基础的 编码解码方式
    SQL 中循环、for循环、游标
    sql中判断是否存在 数据库、表、存储过程、函数
    sql 同步表或同步表的时候更改部分字段
    sql存储过程的建立
    POJ
    UCloud 的安全秘钥 (计蒜客初赛第五场)(待解决)
    UCloud 机房的网络搭建(计蒜客初赛第五场)
    2017 计蒜之道 初赛 第四场
    腾讯课堂的物理实验(2017计蒜客初赛第三场)
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/11302586.html
Copyright © 2020-2023  润新知