賴子胡牌檢測演算法

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

先簡單的說明一下,基於上一篇部落格麻將胡牌演算法使用的是Lua語言,有一些同學私信我,之後部落格能不能使用福士一點的後端語言,所以這篇部落格將使用Google強力推薦的後端語言Golang。不過在這裡值得一提的是,編程特別是演算法更應該注重的是思想,程式設計語言本身並不會流露出你的演算法能力和設計思想,語言只是表達你思想的一個工具而已。裝逼到此結束,進入本文我們來討論一下賴子胡牌應該怎麼檢測

當然一些麻將中使用到的基本名詞和胡牌規則,在這裡就不在重複解釋了。如果不瞭解的可以參考上一篇部落格麻將胡牌演算法

賴子胡牌

胡牌規則和普通胡牌一樣,不過出現了一個賴子牌。這張牌可以是任意牌,如果我們依然按照普通胡牌演算法那樣檢測去遍曆的話,即使只算,,我們簡單的計算一下麻將共有27種牌。如果有四個賴子,那麼賴子檢測演算法的時間複雜度將是普通胡牌演算法的27 * 27 * 27 * 27倍,最壞的情況將是最後一種情況能胡牌,那麼就比普通胡牌演算法多檢測19683次,按照目前的PC效能來看其實還是可以接受的,不過我們通過演算法可以去最佳化那何樂而不為呢。

遍曆檢測

在最佳化之前我們還是先說說如何遍曆去檢測賴子胡牌,因為這不是這篇部落格討論的重點,所以只是簡單的介紹一下便利的思想。

去除手牌賴子

// 去除賴子牌func getAndRmoveLaiZiCard(cardList []int) []int {    laiZiCardList := make([]int, 0, len(allLaiZiCardList))    for i := 0; i < len(cardList); i++ {        for _, laiZiValue := range allLaiZiCardList {            if laiZiValue == cardList[i] {                laiZiCardList = append(laiZiCardList, cardList[i])                cardList[i] = 0                break            }        }    }    return laiZiCardList}
  • 這一步主要目的有兩個
    • 擷取手上的賴子牌,便於之後將賴子作為任意一張牌放入手牌
    • 去除手中的賴子牌,便於加入一種賴子牌組成新的手牌

組合手牌(遍曆賴子胡牌檢測演算法的關鍵)

// 賴子胡牌檢測(遍曆)func checkLaiZiHu(cardList []int, laiZiCount int) bool {    for _, mahjongValue := range mahjongValueList {        tempCardList := append(cardList, mahjongValue)        if laiZiCount == 1 {            checkCount++            mahjongMatrix := getMahjongMatrixWithCardList(tempCardList)            printCardsInfoByMahjongMatrix(mahjongMatrix)            isHu := checkHu(mahjongMatrix)            if isHu {                return isHu            }        } else if laiZiCount > 1 {            isHu := checkLaiZiHu(tempCardList, laiZiCount-1)            if isHu {                return isHu            }        }    }    return false}

上面我們提到了,胡牌檢測的時候一張賴子牌可以作為任意牌出現在手牌中。一個賴子的時候毫無疑問,賴子組合有27種(只涉及 三種花色)。那麼兩個賴子的時候就是27*27種組合了。因此上面使用遞迴的演算法去建立每一種組合。

胡牌檢測

因為在上一步已經構造好賴子組合并且加入到手牌中,因此只需要將手牌按照普通胡牌檢測方法檢測即可。

  • 胡牌檢測

    // 檢測胡牌func checkHu(mahjongMatrix MahjongMatrix) bool {    mahjongMatrixList := getMahjongMatrixListByRemoveTwoCards(mahjongMatrix)    for i := 0; i < len(mahjongMatrixList); i++ {        removeThreeLinkCards(&mahjongMatrixList[i])        removeTheSameThreeCards(&mahjongMatrixList[i])        isHu := checkMatrixAllElemEqualZero(mahjongMatrixList[i])        if isHu {            return isHu        }    }    return false}
  • 去除麻將矩陣中一個將之後的麻將矩陣列表

    // 通過去除麻將矩陣中一個將之後的麻將矩陣列表func getMahjongMatrixListByRemoveTwoCards(mahjongMatrix MahjongMatrix) []MahjongMatrix {    var mahjongMatrixList []MahjongMatrix    for i := 0; i < 3; i++ {        for j := 0; j < 12; j++ {            if mahjongMatrix[i][j] >= 2 {                temp := mahjongMatrix                temp[i][j] -= 2                mahjongMatrixList = append(mahjongMatrixList, temp)            }        }    }    return mahjongMatrixList}
  • 去除句子

    // 去除句子func removeThreeLinkCards(mahjongMatrix *MahjongMatrix) {    for i := 0; i < len(mahjongMatrix); i++ {        for j := 0; j < len(mahjongMatrix[i])-2; j++ {            if mahjongMatrix[i][j] > 0 && mahjongMatrix[i][j+1] > 0 && mahjongMatrix[i][j+2] > 0 {                mahjongMatrix[i][j] -= 1                mahjongMatrix[i][j+1] -= 1                mahjongMatrix[i][j+2] -= 1                j--            }        }    }}

注意:可能存在0x0101, 0x0102, 0x0201, 0x0202, 0x0301, 0x0302這個樣的牌,因此檢測到一個句子之後,需要執行j--避免漏掉一個句子的檢測

  • 去除克子

    // 去除克子func removeTheSameThreeCards(mahjongMatrix *MahjongMatrix) {    for i := 0; i < len(mahjongMatrix); i++ {        for j := 0; j < len(mahjongMatrix[i]); j++ {            if mahjongMatrix[i][j] >= 3 {                mahjongMatrix[i][j] -= 3            }        }    }}
  • 檢測矩陣中元素是否全為零

    // 檢測矩陣中元素是否全為0func checkMatrixAllElemEqualZero(mahjongMatrix MahjongMatrix) bool {    for i := 0; i < len(mahjongMatrix); i++ {        for j := 0; j < len(mahjongMatrix[i]); j++ {            if mahjongMatrix[i][j] != 0 {                return false            }        }    }    return true}

計數檢測

計數檢測,就是對遍曆檢測的一種最佳化。計數的思想就除先去除賴子牌之後剩餘的牌進行胡牌檢測,然後檢測還沒有組成 刻字 順子 的牌需要多少個賴子牌才能組成 賴子 克子。如果需要的個數大於已有賴子個數則不能胡牌,否則可以胡牌。

計數賴子

首先將賴子牌從手牌中移除並且記錄賴子的個數,這個演算法與上面的去除賴子演算法一致,可以參考上面去除賴子演算法。

去除克子和句子

將除去賴子牌後剩餘牌放入麻將矩陣中進行胡牌檢測,演算法與上面的胡牌檢測演算法一致,可以參考上面胡牌檢測演算法。

檢測麻將矩陣中剩餘牌

  • 計算將麻將矩陣中剩餘牌湊出一個 所需要的賴子個數
  • 計算剩餘的牌組成 克子 順子 所需要的賴子個數
  • 總共需要賴子個數如果小於等於手中所持有賴子個數則胡牌
func checkLaiZiHu(cardList []int, laiZiCount int) bool {    mahjongMatrix := getMahjongMatrixWithCardList(cardList)    removeThreeLinkCards(&mahjongMatrix)    removeTheSameThreeCards(&mahjongMatrix)    for i := 0; i < len(mahjongMatrix); i++ {        for j := 0; j < len(mahjongMatrix[i]); j++ {            if mahjongMatrix[i][j] > 0 {                tempMahjong := mahjongMatrix                needLaiZiCount := tempMahjong[i][j] % 2                tempMahjong[i][j] = 0                needLaiZiCount = getNeedLaiZiCountByMahjongMatrix(tempMahjong, needLaiZiCount)                if needLaiZiCount <= laiZiCount {                    return true                }            }        }        needLaiZiCount := getNeedLaiZiCountByMahjongMatrix(mahjongMatrix, 2)        if needLaiZiCount <= laiZiCount {            return true        }    }    return false}// 計算需要賴子的數量func getNeedLaiZiCountByMahjongMatrix(mahjongMatrix MahjongMatrix, needLaiZiCount int) int {    minLaiZiCount := needLaiZiCount    if !checkMatrixAllElemEqualZero(mahjongMatrix) {        for i := 0; i < len(mahjongMatrix); i++ {            for j := 0; j < len(mahjongMatrix[i]); j++ {                if mahjongMatrix[i][j] <= 0 {                    continue                }                if mahjongMatrix[i][j+1] > 0 {                    mahjongMatrix[i][j]--                    mahjongMatrix[i][j+1]--                    j--                    minLaiZiCount++                    continue                }                if mahjongMatrix[i][j+2] > 0 {                    mahjongMatrix[i][j]--                    mahjongMatrix[i][j+2]--                    j--                    minLaiZiCount++                    continue                }                if mahjongMatrix[i][j] == 1 {                    mahjongMatrix[i][j]--                    minLaiZiCount += 2                    continue                }                if mahjongMatrix[i][j] == 2 {                    mahjongMatrix[i][j] -= 2                    minLaiZiCount++                }            }        }    }    return minLaiZiCount}

注意:在組成 的過程中可能一個花色裡面都沒有剩餘牌,此時應該使用兩個賴子組成一個

歡迎討論

Email huliuworld@yahoo.com
Github https://github.com/LHCoder2016/MahjongArithmetic.git

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.