帶萬能牌的麻將和牌算法

該算法通過計算需要的萬能牌個數(shù),和已經(jīng)擁有的萬能牌個數(shù)對比來判斷是否胡牌,算法通用,且效率高,計算胡牌算法每秒鐘可以運(yùn)行三百萬次以上。以下是算法的具體內(nèi)容。

1. 所有合法牌:

0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09  萬
0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19  條
0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29  筒
0x31 0x32 0x33 0x34 0x35 0x36 0x37            東西南北中發(fā)白

2. 核心算法

將萬、條、筒、風(fēng)各種花色分開,然后分別計算每種花色構(gòu)成整撲(整撲即三張相同牌或者順子)還需要多少張萬能牌。如:0x01、0x01、0x02、0x03、0x04 構(gòu)成整撲需要一張萬能牌, 0x01、0x03、0x05、0x07構(gòu)成整撲需要兩張萬能牌。
計算整撲按照從小到大的順序一次計算。

  1. 首先檢查是否是刻子(三張相同的牌)。
  2. 然后檢測檢查是否是對子。
    如果是對子,檢測它是否符合A2BxCy,xyz為張數(shù),
    如果x>0,y>1或者x>1,y>0,則分別檢測A成對子和A成順子需要的萬能牌張數(shù)。否則,則A組合成對子來計算。
  3. 如果是單張牌,則檢測其是否可以與后面的牌組合成順子,如果不能則檢測是否能組合成吃牌,例如一萬二萬,一萬三萬這種組合,如果還是不能,就是一張單獨(dú)的牌。
  4. 風(fēng)牌判斷比較簡單,這里就不贅述了。

計算完成后,依次遍歷將牌在萬,條,筒,風(fēng)的情況下,它們構(gòu)成整撲加將需要的萬能牌個數(shù),然后對比擁有的萬能牌個數(shù),便可以得出是否可以胡牌。

3. 邏輯代碼

判斷字牌(萬,條,筒)組合成整撲需要的萬能牌個數(shù)。

func SwitchCardToIndex(card uint8) uint8 {
    return 9 * (card / 16) + card % 16 - 1
}

func SwitchCardsToIndexList(cards []uint8) []uint8 {
    indexList := make([]uint8, 34)
    for _, card := range cards {
        index := SwitchCardToIndex(card)
        indexList[index] ++
    }
    return indexList
}

func CheckZiPaiZhengPu(cardsIndex []uint8) int {
    tmpCardsIndex := cardsIndex
    needMagicNum := 0
    curPos := 0
    for curPos < len(tmpCardsIndex){
        if tmpCardsIndex[curPos] >= 3 {
            tmpCardsIndex[curPos] -= 3
        } else if tmpCardsIndex[curPos] == 2 {
            if tmpCardsIndex[curPos+1] > 0 && tmpCardsIndex[curPos+2] > 0 && (tmpCardsIndex[curPos+1]>1 || tmpCardsIndex[curPos+2]>1){
                shunCardsIndex := make([]uint8, len(tmpCardsIndex))
                copy(shunCardsIndex, tmpCardsIndex)
                shunCardsIndex[curPos] --
                shunCardsIndex[curPos+1] --
                shunCardsIndex[curPos+2] --
                shunNeedNum := CheckZiPaiZhengPu(shunCardsIndex)
                duiCardsIndex := tmpCardsIndex
                duiCardsIndex[curPos] -= 2
                duiNeedNum := CheckZiPaiZhengPu(duiCardsIndex) + 1
                if duiNeedNum > shunNeedNum {
                    return shunNeedNum + needMagicNum
                }
                return duiNeedNum + needMagicNum
            } else {
                needMagicNum ++
                tmpCardsIndex[curPos] -= 2
            }
        } else if tmpCardsIndex[curPos] == 1{
            if tmpCardsIndex[curPos+1] >= 1 && tmpCardsIndex[curPos+2] >= 1 {
                tmpCardsIndex[curPos] --
                tmpCardsIndex[curPos+1] --
                tmpCardsIndex[curPos+2] --
            } else if tmpCardsIndex[curPos+1] >= 1 {
                needMagicNum ++
                tmpCardsIndex[curPos] --
                tmpCardsIndex[curPos+1] --
            } else if tmpCardsIndex[curPos+2] >= 1 {
                needMagicNum ++
                tmpCardsIndex[curPos] --
                tmpCardsIndex[curPos+2] --
            } else {
                needMagicNum += 2
                tmpCardsIndex[curPos] --
            }
        } else {
            curPos ++
        }
    }
    return needMagicNum
}

判斷(萬,條,筒)組合成整撲需要的萬能牌個數(shù)。

func CheckFengPaiZhengPu(cardsIndex []uint8) int {
    tmpCardsIndex := cardsIndex
    needMagicNum := 0
    curPos := 0
    for curPos < 7{
        if tmpCardsIndex[curPos] >= 3 {
            tmpCardsIndex[curPos] -= 3
        } else if tmpCardsIndex[curPos] == 2 {
            needMagicNum ++
            tmpCardsIndex[curPos] -= 2
        } else if tmpCardsIndex[curPos] == 1{
            needMagicNum += 2
            tmpCardsIndex[curPos] --
        } else {
            curPos ++
        }
    }
    return needMagicNum
}

檢測是否可以胡牌

func CanHuPai(handCardIndex []uint8, magicCard uint8) bool {
    magicIndex := SwitchCardToIndex(magicCard)
    tmpCardIndex := make([]uint8, len(handCardIndex))
    copy(tmpCardIndex, handCardIndex)
    magickNum := tmpCardIndex[magicIndex]

    if magickNum >= 3 {
        return true
    }

    tmpCardIndex[magicIndex] = 0
    tmpIndexList := make([]uint8, 11)

    //分析萬,條,筒
    //ziPaiType := []string{"萬", "條", "筒"}
    ziPaiNeedMagicNums := make([]int, 3)
    for i:=0; i<3; i++ {
        copy(tmpIndexList, tmpCardIndex[i*9:(i+1)*9])
        tmpResult := CheckZiPaiZhengPu(tmpIndexList)
        ziPaiNeedMagicNums[i] = tmpResult
    }

    //分析風(fēng)
    copy(tmpIndexList, tmpCardIndex[27:34])
    fengPaiNeedMagicNum := CheckFengPaiZhengPu(tmpIndexList)

    //jiangType := []string{"萬", "條", "筒"}
    totalNeedMagick := ziPaiNeedMagicNums[0] + ziPaiNeedMagicNums[1] + ziPaiNeedMagicNums[2] + fengPaiNeedMagicNum

    //所有牌都可以成整樸,將必定在財神牌上
    if int(magickNum) - totalNeedMagick >= 0 {
        //fmt.Println("將在------",jiangType[ziPaiType])
        return true
    }

    //將在萬,條,筒中
    for ziPaiType:=0; ziPaiType<3; ziPaiType++{
        leftMagicNum := int(magickNum) + ziPaiNeedMagicNums[ziPaiType] - totalNeedMagick
        if leftMagicNum >= 0 {
            for eyeIndex:=0; eyeIndex<9; eyeIndex ++ {
                copy(tmpIndexList, tmpCardIndex[ziPaiType * 9:(ziPaiType+1) * 9])
                if tmpIndexList[eyeIndex] >= 2 {
                    tmpIndexList[eyeIndex] -= 2
                    tmpNeedMagic := CheckZiPaiZhengPu(tmpIndexList)
                    if leftMagicNum >= tmpNeedMagic {
                        return true
                    }
                } else if tmpIndexList[eyeIndex] == 1 && leftMagicNum > 0{
                    tmpNeedMagic := 1
                    tmpIndexList[eyeIndex] --
                    tmpNeedMagic += CheckFengPaiZhengPu(tmpIndexList)
                    if leftMagicNum >= tmpNeedMagic {
                        return true
                    }
                }
            }
        }
    }

    //將在風(fēng)中
    leftMagicNum := int(magickNum) + fengPaiNeedMagicNum - totalNeedMagick
    if leftMagicNum >= 0 {
        for eyeIndex:=0; eyeIndex<7; eyeIndex ++ {
            copy(tmpIndexList, tmpCardIndex[27:34])
            if tmpIndexList[eyeIndex] >= 2 {
                tmpIndexList[eyeIndex] -= 2
                tmpNeedMagic := CheckFengPaiZhengPu(tmpIndexList)
                if leftMagicNum >= tmpNeedMagic {
                    return true
                }
            } else if tmpIndexList[eyeIndex] == 1 && leftMagicNum > 0{
                tmpNeedMagic := 1
                tmpIndexList[eyeIndex] --
                tmpNeedMagic += CheckFengPaiZhengPu(tmpIndexList)
                if leftMagicNum >= tmpNeedMagic {
                    return true
                }
            }
        }
    }
    return false
}

4. 測試代碼

func main() {
    if err:=recover(); err != nil {
        fmt.Println(err)
    }
    //cardsIndex := SwitchCardsToIndexList([]uint8{0x11,0x17,0x12,0x11,0x17,0x12,0x13,0x13,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x26,0x26})
    //cardsIndex := SwitchCardsToIndexList([]uint8{0x12,0x12,0x13,0x13,0x13,0x14,0x15,0x16,0x02,0x02,0x03,0x03,0x03,0x04,0x05,0x06,0x26,0x26})
    cardsIndex := SwitchCardsToIndexList([]uint8{0x11,0x11,0x12,0x13,0x13,0x22,0x22,0x23,0x24,0x26,0x26})
    isHu := CanHuPai(cardsIndex, 0x26)
    fmt.Println(isHu)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容