該算法通過(guò)計(jì)算需要的萬(wàn)能牌個(gè)數(shù)延欠,和已經(jīng)擁有的萬(wàn)能牌個(gè)數(shù)對(duì)比來(lái)判斷是否胡牌陌兑,算法通用,且效率高由捎,計(jì)算胡牌算法每秒鐘可以運(yùn)行三百萬(wàn)次以上话肖。以下是算法的具體內(nèi)容。
1. 所有合法牌:
0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 萬(wàn)
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. 核心算法
將萬(wàn)遇汞、條卵洗、筒、風(fēng)各種花色分開(kāi)心肪,然后分別計(jì)算每種花色構(gòu)成整撲(整撲即三張相同牌或者順子)還需要多少?gòu)埲f(wàn)能牌锭亏。如:0x01、0x01硬鞍、0x02慧瘤、0x03戴已、0x04 構(gòu)成整撲需要一張萬(wàn)能牌, 0x01锅减、0x03糖儡、0x05、0x07構(gòu)成整撲需要兩張萬(wàn)能牌上煤。
計(jì)算整撲按照從小到大的順序一次計(jì)算休玩。
- 首先檢查是否是刻子(三張相同的牌)。
- 然后檢測(cè)檢查是否是對(duì)子劫狠。
如果是對(duì)子拴疤,檢測(cè)它是否符合A2BxCy,xyz為張數(shù)独泞,
如果x>0,y>1或者x>1,y>0呐矾,則分別檢測(cè)A成對(duì)子和A成順子需要的萬(wàn)能牌張數(shù)。否則懦砂,則A組合成對(duì)子來(lái)計(jì)算蜒犯。 - 如果是單張牌,則檢測(cè)其是否可以與后面的牌組合成順子荞膘,如果不能則檢測(cè)是否能組合成吃牌罚随,例如一萬(wàn)二萬(wàn),一萬(wàn)三萬(wàn)這種組合羽资,如果還是不能淘菩,就是一張單獨(dú)的牌。
- 風(fēng)牌判斷比較簡(jiǎn)單屠升,這里就不贅述了潮改。
計(jì)算完成后,依次遍歷將牌在萬(wàn)腹暖,條汇在,筒,風(fēng)的情況下脏答,它們構(gòu)成整撲加將需要的萬(wàn)能牌個(gè)數(shù)糕殉,然后對(duì)比擁有的萬(wàn)能牌個(gè)數(shù),便可以得出是否可以胡牌以蕴。
3. 邏輯代碼
判斷字牌(萬(wàn)糙麦,條,筒)組合成整撲需要的萬(wàn)能牌個(gè)數(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
}
判斷(萬(wàn),條魄缚,筒)組合成整撲需要的萬(wàn)能牌個(gè)數(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
}
檢測(cè)是否可以胡牌
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)
//分析萬(wàn),條焚廊,筒
//ziPaiType := []string{"萬(wàn)", "條", "筒"}
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{"萬(wàn)", "條", "筒"}
totalNeedMagick := ziPaiNeedMagicNums[0] + ziPaiNeedMagicNums[1] + ziPaiNeedMagicNums[2] + fengPaiNeedMagicNum
//所有牌都可以成整樸,將必定在財(cái)神牌上
if int(magickNum) - totalNeedMagick >= 0 {
//fmt.Println("將在------",jiangType[ziPaiType])
return true
}
//將在萬(wàn),條习劫,筒中
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. 測(cè)試代碼
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)
}