麻將胡牌算法,帶癩子


貌似去年去面試一家公司,問了麻將的算法。雖然之前做過廣東麻將,但是胡牌算法在服務端,就沒有在意。

現在在網上搜了一些算法試了試 = =!

 

麻將普通的胡牌就是刻子+順子+將。癩子可以充當任意一張牌。

 

參考:

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張麻將牌遍歷一遍加入手牌,看是否能胡,如果能胡,則表示聽此張牌。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM