麻將胡牌演算法

LG_227發表於2018-04-05

本文實現了一個胡牌演算法,目前支援視訊中講解的三種番型,更多番型或者其它番型大家可以結合當地的麻將進行二次開發,專案中不僅有後臺胡牌演算法,而且還配備了前臺頁面,開發人員可以在前臺中直接輸入麻將對應的資料,操作十分方便。具體細節請觀看視訊講解

視訊和demo下載地址:wisdomdd.cn

視訊中的原始碼可以點選【下載例項】進行下載, 環境配置: Eclipse+Maven+JDK1.7

環境下載地址: http://www.wisdomdd.cn/Wisdom/category/getAllCategoryFile.htm


 胡牌前提:  共14張牌,可以湊成4個三張,1個對子

            三張牌: 3個一樣的牌(3個1萬)叫刻子,或者 3個順序牌(1萬,2萬,3萬)叫順子

            對子:   二張一樣的牌(2個1萬)

            

 番型計算:   14張牌首先要滿足胡牌的前提條件,然後再根據各個地方的胡牌規則進行番型計算,如果沒有番型,則不能胡牌



 下面以下圖對應的番型規則進行演算法介紹

blob.png



胡牌前提對應的演算法:

    類: MahjongStaticTool

     引數: MahjongTile[] mahjongTiles 麻將對應的14張牌

     引數: twoNum 對子的個數

     引數: threeNum  殼子+順子的  數目

  我們以 threeNum=4, twoNum=1 即4個三張牌,1個二張牌為例

   tryCombination以遞迴方法來獲取牌型資料, 最後將牌型資料存放在MahjongTile[][]二維陣列中

   MahjongTile[][]共5組資料, 例: 第一組有3張牌, 第二組有3張牌,第三組有3張牌,第四組有2張牌,第五組有3張牌

public static MahjongTile[][] tryCombination(MahjongTile[] mahjongTiles, int twoNum, int threeNum)  
    {  
        return MahjongStaticTool.tryCombination(mahjongTiles, twoNum, threeNum, null);  
    }  
   
    private static MahjongTile[][] tryCombination(MahjongTile[] mahjongTiles, int twoNum, int threeNum, MahjongTile[][] saveMahjongTileses)  
    {  
        if (mahjongTiles == null)  
        {  
            if (twoNum == 0 && threeNum == 0)  
            {  
                return saveMahjongTileses;  
            }  
            else  
            {  
                return null;  
            }  
        }  
        if (mahjongTiles.length == ((twoNum * 2) + (threeNum * 3)))  
        {  
            if (threeNum > 0)  
            {  
                //int[][] indexs = siphonThreeIndexs(mahjongTiles.length);  
                int[][] indexs = getThreeSiphonByLength(mahjongTiles.length);
                if (indexs == null)  
                {  
                    return null;  
                }  
                   
                for (int[] index : indexs)  
                {  
                    if (mahjongTiles[index[0]].isCanThree(mahjongTiles[index[1]], mahjongTiles[index[2]]))  
                    {  
                        MahjongTile[][] saveMahjongTilesesCache = appendSomeMahjongTiles(saveMahjongTileses, new MahjongTile[]{mahjongTiles[index[0]], mahjongTiles[index[1]], mahjongTiles[index[2]]});  
                        MahjongTile[][] mahjongTilesesReturn = MahjongStaticTool.tryCombination(removeSomeMahjongTiles(mahjongTiles, new int[]{index[0], index[1], index[2]}), twoNum, threeNum - 1, saveMahjongTilesesCache);  
                        if (mahjongTilesesReturn != null)  
                        {  
                            return mahjongTilesesReturn;  
                        }  
                    }  
                }  
            }  
            else if (twoNum > 0)  
            {  
                //int[][] indexs = siphonTwoIndexs(mahjongTiles.length);
                if(mahjongTiles.length != 2){
                    System.out.println("aaaaaaaaaaaaaaaa");
                }
                int[][] indexs = twoSiphon;
                if (indexs == null)  
                {  
   
                    return null;  
                }  
                for (int[] index : indexs)  
                {  
                    if (mahjongTiles[index[0]].isCanTwo(mahjongTiles[index[1]]))  
                    {  
                        MahjongTile[][] saveMahjongTilesesCache = appendSomeMahjongTiles(saveMahjongTileses, new MahjongTile[]{mahjongTiles[index[0]], mahjongTiles[index[1]]});  
                        MahjongTile[][] mahjongTilesesReturn = MahjongStaticTool.tryCombination(removeSomeMahjongTiles(mahjongTiles, new int[]{index[0], index[1]}), twoNum - 1, threeNum, saveMahjongTilesesCache);  
                        if (mahjongTilesesReturn != null)  
                        {  
                            return mahjongTilesesReturn;  
                        }  
                    }  
                }  
            }  
            else  
            {  
                return saveMahjongTileses;  
            }  
        }  
        return null;  
    }

番型對應的演算法:

    滿足基本胡牌要求後,就可以根據番型來計算, 下在舉例本人的番型計算規則

     由於番型可以疊加,所以需要核對每一種番型演算法,滿足一種則加一番

1. 麻將手牌13張, 最後一張為自摸牌,進行標記,表明為最後一張
2. 將麻將牌進行分組, 萬牌放一組, 桶牌放一組, 條牌一組, 東風牌一組,南風牌一組, 西風牌一組, 北風牌一組, 紅中一組, 發財一組, 白皮一組,  賴子一組
   賴子牌只有一組,其它牌10
3.1. 賴子牌組沒有牌,如果沒牌,則將其它牌組進行組合,看14能否組成 4個三張牌, 1個二張牌, 如果能組成則存在胡的可能性,記錄下4個三張和對子
3.2  賴子牌組有牌,則將賴子牌分別投入到其它牌組,每張牌投放牌組的可能是10(10個牌組), 每張牌在每個組按照牌組的種類進行迴圈遍歷,如賴子在萬牌組,
    則進行1-9的迴圈遍歷, 若賴子在北牌組,只能變成相應的風, 賴子變成相應的牌時,如果賴子是最後一張,則變成的牌也要標記為最後一張
     賴子牌型確定後,看14張牌能否組成 4個三張牌, 1個二張牌, 如果能組成則存在胡的可能性, 記錄下4個三張和對子
 
4. 如果上述存在胡牌的可能性,則進行番型比對
   由於斷一門,斷么九比較簡單,省略不討論, 由於平胡複雜度比較高,實現起來難度大, 下面重點討論平胡
    
 
    4.1 14張牌型確定後, 迴圈遍歷14張牌,如果有風將牌,則肯定不是平胡, 迴圈過程中,找出最後一張牌
    4.2 判斷4個三張牌中是否有坎子的情況,如果是,則找出有幾個坎子,如果有三個坎子, 則判斷這三個坎子能否組成三個順子(如果能則執行規則4.3), 如果不能,則肯定不是平胡,不用繼續下面的規則;
        如果有1,2,4個坎子,則肯定不是平胡,不用走下面的規則,    如果沒有一個坎子,則執行規則4.3
    4.3 判斷四組順子牌中含有最後一張牌的組(記錄A組), 如果最後一張牌在中間,則可能是卡單張的可能
        如果其它牌組跟A組牌不相同,但包含跟最後一張牌一樣的牌則繼續看規則4.4
    4.4 判斷四組順子牌中含有最後一張牌的組(記錄A組), 如果最後一張牌是3或者7, 則可能是邊三或者邊七
        如果其它牌組跟A組牌不相同,但包含跟最後一張牌一樣的牌並且此組牌的平均值不為最後一張的值,則執行規則4.5
    4.5 找出對子牌,判斷對子牌中是否有最後一張,如果有最後一張,則判斷其它四個牌組是否有跟最後一張牌一樣的牌,
        如果有,則繼續執行; 否則贊頭
          
    如果能滿足4.1並且4.2並且4.3並且4.4並且4.5  則為平胡

斷一門

/**
     * 斷一門
     * @param mahjongTiles
     * @return
     */
    public static boolean duanYiMen(MahjongTile[] mahjongTiles, MahjongTile[][] mahjongTileses){
         
        boolean hasWan   = false;
        boolean hasPie   = false;
        boolean hasStrip = false;
        boolean hasWind  = false;
        boolean hasMess  = false;
         
        for(MahjongTile tile : mahjongTiles){
            if(tile.isWan()){
                hasWan = true;
            }else if(tile.isPie()){
                hasPie = true;
            }else if(tile.isStrip()){
                hasStrip = true;
            }else if(tile.isWind()){
                hasWind = true;
                return false;
            }else if(tile.isMess()){
                hasMess = true;
                return false;
            }
        }
         
        if(hasWind == false && hasMess == false){
            int n = 0;
            if(hasWan == true){
                n++;
            }
            if(hasPie == true){
                n++;
            }
            if(hasStrip == true){
                n++;
            }
             
            if(n == 2){
                return true;
            }
        }
        return false;
    }



相關文章