癩子麻將胡牌以及聽牌演算法實現
最先實現的就是演算法的實現。
需求:碰槓胡 ,不能吃 ,不能聽 ,只能自摸胡,其中癩子可以做任意牌但是不能碰和槓。
寫的時候還不會玩麻將,還是老闆教的。^_^
最麻煩的是胡牌演算法。之前搜到的都是不包含癩子正常的胡牌,用的是%3餘2,其中餘數2就是餘的將的意思。
但是有癩子就不能這麼用了。只好自己寫一個了。
一個有136張牌,萬,餅,條,東西南北中發白34種牌。
有四個癩子是直接就胡牌的,最壞的情況是有3個癩子,但是如果遍歷一遍不用邏輯判斷就有34X34X34接近4萬次.
想一下如果能胡牌,最壞的情況下是在最後一次判斷能胡牌,那之前的近4萬次的判斷都是浪費的。
這裡轉變一下思維,就是有目的的按需所取成胡牌所需要的癩子個數,而不是盲目遍歷再判斷胡牌。
演算法的正確性:如果想胡牌必然是三撲一將(正常胡牌)。其中撲指的是順子或者三重牌(比如 一餅二餅三餅 或者東風東風東風)。將指的是兩個重牌。
四種情況:
1.假如將在【萬】裡面那麼【餅】【條】【風】(包含中發白)必然是整撲。
2.假如將在【餅】裡面那麼【萬】【條】【風】(包含中發白)必然是整撲。
3.假如將在【條】裡面那麼【萬】【餅】【風】(包含中發白)必然是整撲。
4.假如將在【風】裡面(包含中發白)那麼【萬】【餅】【條】必然是整撲。
假如當前癩子的數目是curHunNum。
現在先獲取【萬】【餅】【條】【風】各自成為整撲所需要癩子的個數,如果是情況一。
needHunNum= 【餅】成為整撲需要癩子的個數+【條】成為整撲需要癩子的個數+【風】成為整撲需要癩子的個數;
如果hadHunNum = needHunNum - curHunNum; 如果hadHunNum<0 需求的比擁有的多 就不做判斷。
否則就判斷【萬】中成為整撲一將需要的數目。
情況二三四依次類推。
更新
今天又寫了一下聽牌,既然寫了希望能幫助更多的人吧
聽的牌要麼是將要麼是撲,有的牌有可能同時當將和當撲都能贏
當結果有一個能聽的時候說明只要再來一個混也能贏。
程式碼:
majmap = {"101":"一萬","102":"二萬","103":"三萬","104":"四萬","105":"五萬","106":"六萬","107":"七萬","108":"八萬","109":"九萬",
"201":"一餅","202":"二餅","203":"三餅","204":"四餅","205":"五餅","206":"六餅","207":"七餅","208":"八餅","209":"九餅",
"301":"一條","302":"二條","303":"三條","304":"四條","305":"五條","306":"六條","307":"七條","308":"八條","309":"九條",
"401":"東風","402":"西風","403":"南風","404":"北風","405":"紅中","406":"發財","407":"白板"}
if __name__ == "__main__":
#####################################
#測試胡牌
# samArr = [111, 111, 111, 111, 214, 214, 214, 214, 315, 315, 315, 315, 118, 119, 119 ]
# print testHu(112, samArr, 111)
#####################################
#####################################
#測試具體能聽哪些牌
# samArr = [405,202,203,203,204,205,302,302,303,303]#執行時間:0:00:00.001100 <callTime:83> [ 一餅 , 四餅 , 二條 , 三條 , 紅中 , ]
# samArr = [405,202,203,203,204,205,301,302,303,303]#執行時間:0:00:00.000721 <callTime:72> [ 一餅 , 四餅 , 三條 , 紅中 , ]
# samArr = [405,202,203,203,204,205,301,302,302,303]#執行時間:0:00:00.000659 <callTime:72> [ 一餅 , 四餅 , 二條 , 紅中 , ]
# samArr = [405,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000887 <callTime:72> [ 三餅 , 六餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,202,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000715 <callTime:59> [ 二餅 , 五餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,202,203,203,204,301,302,302,303,303]#執行時間:0:00:00.000797 <callTime:72> [ 三餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,104,104,107,107,107,203,204,205,305,307,308,309]#執行時間:0:00:00.000791 <callTime:83> [ 四萬 , 五條 , 三條 , 四條 , 六條 , 七條 , 紅中 , ]
# samArr = [405,104,104,107,107,107,203,204,205,207,307,308,309]#執行時間:0:00:00.000844 <callTime:85> [ 四萬 , 七餅 , 二餅 , 五餅 , 六餅 , 八餅 , 九餅 , 紅中 , ]
# samArr = [405,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000799 <callTime:88> [ 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,103,104,105,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000859 <callTime:89> [ 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,103,104,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000836 <callTime:88> [ 二餅 , 三條 , 六條 , 紅中 , ]
# #測試兩個癩子的執行時間
# samArr = [405,405,103,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000955 <callTime:136> [ 四萬 , 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,103,105,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000696 <callTime:94> [ 四萬 , 三餅 , 三條 , 紅中 , ]
# samArr = [405,405,103,105,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000790 <callTime:94> [ 四萬 , 三餅 , 一條 , 四條 , 紅中 , ]
# #測試三個癩子的執行時間
# samArr = [405,405,405,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.001111 <callTime:135> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,405,105,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000926 <callTime:118> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 三餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,405,105,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000949 <callTime:116> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 三餅 , 一條 , 四條 , 六條 , 紅中 , ]
# #測試四個癩子的執行時間
# samArr = [405,405,405,405,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000607 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
# samArr = [405,405,405,405,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000390 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
# samArr = [405,405,405,405,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000758 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
#####################################
#####################################
#測試打出哪些牌能聽
# tingNumArr = [405,202,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000704 <callTime:48> [ 二餅 , 三餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,104,104,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000649 <callTime:61> [ 七餅 , 五條 , ]
# tingNumArr = [405,103,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000874 <callTime:82> [ 三萬 , 六萬 , 九萬 , ]
# #測試兩個癩子
# tingNumArr = [405,405,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000424 <callTime:35> [ 三餅 , 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,104,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000616 <callTime:63> [ 四萬 , 七餅 , 五條 , ]
# tingNumArr = [405,405,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000551 <callTime:48> [ 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
# #測試三個癩子
# tingNumArr = [405,405,405,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000493 <callTime:27> [ 三餅 , 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,405,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000518 <callTime:36> [ 七萬 , 三餅 , 四餅 , 五餅 , 七餅 , 五條 , 七條 , 八條 , 九條 , ]
# tingNumArr = [405,405,405,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000522 <callTime:53> [ 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
# #測試四個癩子
# tingNumArr = [405,405,405,405,204,205,301,302,302,303,303]#執行時間:0:00:00.000422 <callTime:24> [ 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,405,405,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000604 <callTime:35> [ 七萬 , 三餅 , 四餅 , 五餅 , 七餅 , 五條 , 七條 , 八條 , 九條 , ]
# tingNumArr = [405,405,405,405,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000678 <callTime:31> [ 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
##############################
# 測試特殊情況 單一花色重複多次
# tingNumArr = [405,201,201,201,201,202,202,202,202,205,205,205,205,209]#執行時間:0:00:00.006123 <callTime:356> [ 五餅 , 九餅 , ]
# tingNumArr = [405,405,202,204,205,205,206,206,207,208,208,208,209,306]#執行時間:0:00:00.002929 <callTime:358> [ 二餅 , 九餅 , 六條 , ]
# samArr = [405,201,201,201,201,201,202,202,202,202,204,204,205]#執行時間:0:00:00.016391 <callTime:1029> [ 三餅 , 六餅 , 紅中 , ]
samArr = [405,405,201,201,201,201,202,202,202,202,204,204,209]#執行時間:0:00:00.026671 <callTime:1527> [ 三餅 , 四餅 , 七餅 , 八餅 , 九餅 , 紅中 , ]
##############################
global callTime
callTime = 0
begin = datetime.datetime.now()
# 測試摸哪些牌能胡牌
tingArr = getTingArr(samArr,405)
#測試打哪些牌能聽牌
# tingArr = getTingNumArr(tingNumArr,405)
#測試摸到這張牌是不是能胡牌
# tingArr = {}
# print testHu(209, samArr, 405)
# tingArr = []
# for i in tingNumArr:
# tmp = []
# tmp.extend(tingNumArr)
# tmp.remove(i)
# getTingNumArr(tmp,405)
end = datetime.datetime.now()
runTime = end-begin
rstr = "執行時間:" + str(runTime) + " <callTime:" + str(callTime) + "> [ "
for i in range(0,len(tingArr)):
key = str(tingArr[i])
rstr += majmap.get(key) + " , "
rstr += "]"
print rstr
可以發現一般情況下大概1ms時間左右,我用c++測試的時候大概能快五六倍的樣子。但是當花色比較單一,並且重複的數字比較多的時候,執行速度變得很慢。
原因如下:
不用再下載了直接貼上來吧也好直接更改:
#coding:utf8
#####################
#作者:skillart
#bolg:http://blog.csdn.net/skillart/article/details/40422885
#
#####################
# 資料格式:型別=value/100, 數值=value%10
# [111-119] 萬
# [121-129]
# [131-139]
# [141-149]
# [211-219] 餅
# [221-229]
# [231-239]
# [241-249]
# [311-319] 條
# [321-329]
# [331-339]
# [341-349]
# [411-417] 東西南北中發白
# [421-427]
# [431-437]
# [441-447]
import random
g_NeedHunCount = 4
g_mjsArr = [
101, 102, 103, 104, 105, 106, 107, 108, 109, #萬
101, 102, 103, 104, 105, 106, 107, 108, 109,
101, 102, 103, 104, 105, 106, 107, 108, 109,
101, 102, 103, 104, 105, 106, 107, 108, 109,
201, 202, 203, 204, 205, 206, 207, 208, 209, #餅
201, 202, 203, 204, 205, 206, 207, 208, 209,
201, 202, 203, 204, 205, 206, 207, 208, 209,
201, 202, 203, 204, 205, 206, 207, 208, 209,
301, 302, 303, 304, 305, 306, 307, 308, 309, #條
301, 302, 303, 304, 305, 306, 307, 308, 309,
301, 302, 303, 304, 305, 306, 307, 308, 309,
301, 302, 303, 304, 305, 306, 307, 308, 309,
401, 402, 403, 404, 405, 406, 407, # 東 西 南 北 中 發 白
401, 402, 403, 404, 405, 406, 407,
401, 402, 403, 404, 405, 406, 407,
401, 402, 403, 404, 405, 406, 407
] # end
# [ 測試使用
g_testMjsArr = [
101, 101, 101, 101, 102, 102, 104, 201, 103,
103, 103, 103, 104, 104, 102, 104, 105, 105,
105, 105, 106, 106, 106, 106, 107, 107, 107,
107, 108, 108, 108, 108, 109, 109, 109, 109,
201, 202, 203, 204, 204, 202, 203, 205, 201,
202, 203, 204, 201, 202, 203, 204, 205, 206,
207, 208, 206, 102, 207, 208, 205, 206, 207,
208, 205, 206, 207, 208, 209, 209, 209, 209,
301, 302, 303, 304, 301, 302, 303, 304, 301,
302, 303, 304, 301, 302, 303, 304, 305, 306,
307, 308, 305, 306, 307, 308, 305, 306, 307,
308, 305, 306, 307, 308, 309, 309, 309, 309,
401, 402, 403, 404, 405, 406, 407, # 東 西 南 北 中 發 白
401, 402, 403, 404, 405, 406, 407,
401, 402, 403, 404, 405, 406, 407,
401, 402, 403, 404, 405, 406, 407
]
def getTestMjs():
mjArr = []
mjArr.extend(g_testMjsArr)
return mjArr
# 測試使用 ]
# 獲得一副牌並混亂牌
def randomMjs():
mjArr = []
mjArr.extend(g_mjsArr)
i = random.randint(1, 5 )
while i > 0:
random.shuffle( mjArr )
i = i - 1
return mjArr
# 判斷是否有效
def isValidMj( mj ):
itype = mj / 100
clr = mj % 100 / 10 # 忽略該欄位,僅用於判別有效
value = mj % 10
if itype == 1 or itype == 2 or itype == 3:
if value < 1 or value > 9 or clr != 0:
return False
else:
return True
elif itype == 4:
if value < 1 or value > 7 or clr != 0:
return False
else:
return True
else:
return False
# 獲得混
def getHunMj(fanMj):
t = fanMj / 100
v = fanMj % 10
if t == 4:
v = v+1
if v > 7:
v = 1
elif t>0 and t<5:
v = v+1
if v > 9:
v = 1
return t*100 + v
def sortArr(arr):
if len(arr) == 0:
return
arr.sort( None, key=lambda v:v%10 )
def seprateArr( mjArr, hunMj ):
reArr = [[],[],[],[],[]]
ht = hunMj / 100
hv = hunMj % 10
for mj in mjArr:
t = mj / 100
v = mj % 10
if ht == t and hv == v:
t = 0
reArr[t].append( mj )
sortArr( reArr[t] )
return reArr
def test3Combine( mj1, mj2, mj3 ):
t1, t2, t3 = mj1/100, mj2/100, mj3/100
# 牌型不同不能組合
if t1 != t2 or t1 != t3:
return False
v1, v2, v3 = mj1%10, mj2%10, mj3%10
# 重牌
if v1 == v2 and v1 == v3:
return True
if t3 == 4:
return False
if (v1+1) == v2 and (v1+2) == v3:
return True
return False
def getModNeedNum(arrLem,isJiang):
if arrLem <=0:
return 0
modNum = arrLem % 3
needNumArr = [0,2,1]
if isJiang:
needNumArr = [2,1,0]
return needNumArr[modNum]
def getNeedHunInSub( subArr, hNum ):
global callTime
callTime += 1
global g_NeedHunCount
if g_NeedHunCount == 0:
return
lArr = len(subArr)
if hNum + getModNeedNum(lArr,False) >= g_NeedHunCount:
return
if lArr == 0:
g_NeedHunCount = min( hNum, g_NeedHunCount )
return
elif lArr == 1:
g_NeedHunCount = min( hNum+2, g_NeedHunCount )
return
elif lArr == 2:
t = subArr[0] / 100
v0 = subArr[0] % 10
v1 = subArr[1] % 10
if t == 4: # 東南西北中發白(無順)
if v0 == v1:
g_NeedHunCount = min( hNum+1, g_NeedHunCount )
return
elif (v1-v0) < 3:
g_NeedHunCount = min( hNum+1, g_NeedHunCount )
return
elif lArr >= 3: # 大於三張牌
t = subArr[0] / 100
v0 = subArr[0] % 10
v2 = subArr[2] % 10
#第一個和另外兩個一鋪
arrLen = len(subArr)
for i in range( 1, arrLen ):
if hNum + getModNeedNum(lArr-3,False) >= g_NeedHunCount:
break
v1 = subArr[i] % 10
#13444 134不可能連一起
if v1 - v0 > 1:
break
if ( i+2 ) < arrLen:
if ( subArr[i+2]%10 ) == v1:
continue
if i+1 < arrLen:
tmp1, tmp2, tmp3 = subArr[0],subArr[i], subArr[i+1]
if test3Combine( tmp1, tmp2, tmp3 ):
subArr.remove( tmp1 )
subArr.remove( tmp2 )
subArr.remove( tmp3 )
subLen = len(subArr)
getNeedHunInSub(subArr, hNum)
subArr.append( tmp1 )
subArr.append( tmp2 )
subArr.append( tmp3 )
sortArr( subArr )
# 第一個和第二個一鋪
v1 = subArr[1] % 10
if hNum + getModNeedNum(lArr-2,False) +1 < g_NeedHunCount:
if t == 4: # 東南西北中發白(無順)
if v0 == v1:
tmp1 = subArr[0]
tmp2 = subArr[1]
subArr.remove( tmp1 )
subArr.remove( tmp2 )
getNeedHunInSub(subArr, hNum+1)
subArr.append( tmp1 )
subArr.append( tmp2 )
sortArr( subArr )
else:
arrLen= len(subArr)
for i in range( 1, arrLen ):
if hNum + getModNeedNum(lArr-2,False) +1 >= g_NeedHunCount:
break;
v1 = subArr[i] % 10
#如果當前的value不等於下一個value則和下一個結合避免重複
if (i+1) != arrLen:
v2 = subArr[i+1] % 10
if v1 == v2:
continue
mius = v1 - v0
if mius < 3:
tmp1 = subArr[0]
tmp2 = subArr[i]
subArr.remove( tmp1 )
subArr.remove( tmp2 )
getNeedHunInSub(subArr, hNum+1)
subArr.append( tmp1 )
subArr.append( tmp2 )
sortArr( subArr )
if mius >= 1:
break
else:
break
# 第一個自己一鋪
if hNum + getModNeedNum(lArr-1,False)+2 < g_NeedHunCount:
tmp = subArr[0]
subArr.remove( tmp )
getNeedHunInSub( subArr, hNum+2 )
subArr.append( tmp )
sortArr( subArr )
else:
return
def test2Combine( mj1, mj2 ):
t1, t2 = mj1 / 100, mj2 / 100
v1, v2 = mj1 % 10, mj2 % 10
if t1 == t2 and v1 == v2:
return True
return False
def canHu( hunNum, arr ):
global g_NeedHunCount
tmpArr = []
tmpArr.extend(arr)
arrLen = len( tmpArr )
if arrLen <= 0:
if hunNum >= 2:
return True
return False
if hunNum < getModNeedNum(arrLen,True):
return False
for i in range( arrLen ):
if i == (arrLen - 1 ):# 如果是最後一張牌
if hunNum > 0:
tmp = tmpArr[i]
hunNum = hunNum - 1
tmpArr.remove( tmpArr[i] )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
if g_NeedHunCount <= hunNum:
# print 'type:',tmp/100, 'value', tmp%10, 1
return True
hunNum = hunNum +1
tmpArr.append(tmp)
sortArr(tmpArr)
else:
if ( i+2 ) == arrLen or (tmpArr[i]%10) != (tmpArr[i+2]%10):
if test2Combine( tmpArr[i], tmpArr[i+1] ):
tmp1 = tmpArr[i]
tmp2 = tmpArr[i+1]
tmpArr.remove( tmp1 )
tmpArr.remove( tmp2 )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
if g_NeedHunCount <= hunNum:
# print 'type:',tmp1/100, 'value', tmp1%10, 2
return True
tmpArr.append( tmp1 )
tmpArr.append( tmp2 )
sortArr(tmpArr)
if hunNum>0 and (tmpArr[i]%10) != (tmpArr[i+1]%10):
hunNum = hunNum -1
tmp = tmpArr[i]
tmpArr.remove( tmp )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
if g_NeedHunCount <= hunNum:
# print 'type:',tmp/100, 'value', tmp%10, 3
return True
hunNum = hunNum +1
tmpArr.append( tmp )
sortArr( tmpArr )
return False
# 判斷胡牌
def testHu( mj, mjArr, hunMj ):
global g_NeedHunCount
tmpArr = []
tmpArr.extend(mjArr) # 建立一個麻將陣列的copy
if mj != 0:
tmpArr.append( mj ) # 插入一個麻將
sptArr = seprateArr( tmpArr, hunMj )
curHunNum = len( sptArr[0] )
if curHunNum > 3:
return True
ndHunArr = [] # 每個分類需要混的陣列
for i in range( 1, 5 ):
g_NeedHunCount = 4
getNeedHunInSub( sptArr[i], 0 )
ndHunArr.append(g_NeedHunCount)
isHu = False
# 將在萬中
#如果需要的混小於等於當前的則計算將在將在萬中需要的混的個數
ndHunAll = ndHunArr[1] + ndHunArr[2] + ndHunArr[3]
if ndHunAll <= curHunNum:
hasNum = curHunNum - ndHunAll
isHu = canHu( hasNum, sptArr[1] )
if isHu:
return True
# 將在餅中
ndHunAll = ndHunArr[0] + ndHunArr[2] + ndHunArr[3]
if ndHunAll <= curHunNum:
hasNum = curHunNum - ndHunAll
isHu = canHu( hasNum, sptArr[2] )
if isHu:
return True
# 將在條中
ndHunAll = ndHunArr[0] + ndHunArr[1] + ndHunArr[3]
if ndHunAll <= curHunNum:
hasNum = curHunNum - ndHunAll
isHu = canHu( hasNum, sptArr[3] )
if isHu:
return True
# 將在風中
ndHunAll = ndHunArr[0] + ndHunArr[1] + ndHunArr[2]
if ndHunAll <= curHunNum:
hasNum = curHunNum - ndHunAll
isHu = canHu( hasNum, sptArr[4] )
if isHu:
return True
return False
def testGang( mj, mjArr, hunMj ):
t = mj / 100
v = mj % 10
c = 0
tmpArr = []
tmpArr.extend(mjArr)
sptArr = seprateArr( tmpArr, hunMj )
if len( sptArr[t] ) < 2:
return False
else:
for tmj in sptArr[t]:
if ( tmj%10 ) == v:
c = c+1
if c == 3:
return True
def testPeng( mj, mjArr, hunMj ):
t = mj / 100
v = mj % 10
c = 0
tmpArr = []
tmpArr.extend(mjArr)
sptArr = seprateArr( tmpArr, hunMj )
if len( sptArr[t] ) < 2:
return False
else:
for tmj in sptArr[t]:
if ( tmj%10 ) == v:
c = c+1
if c == 2 or c == 3:
return True
def analyzeAnGang( mjArr, hunMj ):
result = []
tmpArr = []
tmpArr.extend(mjArr)
sptArr = seprateArr( tmpArr, hunMj )
for i in range(len(sptArr)):
subLen = len( sptArr[i] )
if subLen < 4:
continue
else:
for j in range(subLen):
if ( subLen - 1 - j )<3:
break
if (sptArr[i][j]%10) == (sptArr[i][j+1]%10) and \
(sptArr[i][j+1]%10) == (sptArr[i][j+2]%10) and \
(sptArr[i][j+2]%10) == (sptArr[i][j+3]%10):
result.append( sptArr[i][j] )
return result
def rmSample( mj, mjArr, cnt=0 ):
i = cnt
j = 0
while i>0:
if mjArr.count( mj ):
mjArr.remove( mj )
j += 1
i -= 1
return j
def getJiangNeedHum(arr):
global g_NeedHunCount
minNeedNum = 4
tmpArr = []
tmpArr.extend(arr)
arrLen = len( tmpArr )
if arrLen <= 0:
return 2
for i in range( arrLen ):
if i == (arrLen - 1 ):# 如果是最後一張牌
tmp = tmpArr[i]
tmpArr.remove( tmpArr[i] )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
minNeedNum = min(minNeedNum,g_NeedHunCount+1)
tmpArr.append(tmp)
sortArr(tmpArr)
else:
if ( i+2 ) == arrLen or (tmpArr[i]%10) != (tmpArr[i+2]%10):
if test2Combine( tmpArr[i], tmpArr[i+1] ):
tmp1 = tmpArr[i]
tmp2 = tmpArr[i+1]
tmpArr.remove( tmp1 )
tmpArr.remove( tmp2 )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
minNeedNum = min(minNeedNum,g_NeedHunCount)
tmpArr.append( tmp1 )
tmpArr.append( tmp2 )
sortArr(tmpArr)
if (tmpArr[i]%10) != (tmpArr[i+1]%10):
tmp = tmpArr[i]
tmpArr.remove( tmp )
g_NeedHunCount = 4
getNeedHunInSub(tmpArr, 0)
minNeedNum = min(minNeedNum,g_NeedHunCount+1)
tmpArr.append( tmp )
sortArr( tmpArr )
return minNeedNum
def getTingArr(mjArr,hunMj):
global g_NeedHunCount
global callTime
tmpArr = []
tmpArr.extend(mjArr) # 建立一個麻將陣列的copy
sptArr = seprateArr( tmpArr, hunMj )
ndHunArr = [] # 每個分類需要混的陣列
for i in range( 1, 5 ):
g_NeedHunCount = 4
getNeedHunInSub( sptArr[i], 0 )
ndHunArr.append(g_NeedHunCount)
jaNdHunArr = []#每個將分類需要混的陣列
for i in range(1,5):
jdNeedHunNum = getJiangNeedHum(sptArr[i])
jaNdHunArr.append(jdNeedHunNum)
curHunNum = len( sptArr[0])
tingArr = []
paiArr = [[101,110],[201,210],[301,310],[401,408]]
#是否單調將
isAllHu = False
needNum = 0
for i in range(0,4):
needNum += ndHunArr[i]
if curHunNum - needNum == 1:
isAllHu = True
if isAllHu:
for lis in paiArr:
for x in range(lis[0],lis[1]):
tingArr.append(x)
return tingArr
for i in range(0,4):
# if len(sptArr[i+1]) == 0:
# continue;
# 聽牌是將
needNum = 0
for j in range(0,4):
if(i != j):
needNum = needNum + ndHunArr[j]
if needNum <= curHunNum:
for k in range(paiArr[i][0],paiArr[i][1]):
t = [k]
t.extend(sptArr[i+1])
sortArr(t)
if canHu(curHunNum-needNum,t):
tingArr.append(k)
# print callTime
# 聽牌是撲
for j in range(0,4):
if(i != j):
needNum = 0
for k in range(0,4):
if(k != i):
if(k == j):
needNum += jaNdHunArr[k]
else:
needNum += ndHunArr[k]
if needNum <= curHunNum:
for k in range(paiArr[i][0],paiArr[i][1]):
if k not in tingArr:
t = [k]
t.extend(sptArr[i+1])
g_NeedHunCount = 4
sortArr(t)
getNeedHunInSub(t, 0 )
if g_NeedHunCount <= curHunNum - needNum:
tingArr.append(k)
if(len(tingArr) > 0) and hunMj not in tingArr:
tingArr.append(hunMj)
return tingArr;
def getTingNumArr(mjArr,hunMj):
global g_NeedHunCount
global callTime
tmpArr = []
tmpArr.extend(mjArr) # 建立一個麻將陣列的copy
sptArr = seprateArr( tmpArr, hunMj )
ndHunArr = [] # 每個分類需要混的陣列
for i in range( 1, 5 ):
g_NeedHunCount = 4
getNeedHunInSub( sptArr[i], 0 )
ndHunArr.append(g_NeedHunCount)
jaNdHunArr = []#每個將分類需要混的陣列
for i in range(1,5):
jdNeedHunNum = getJiangNeedHum(sptArr[i])
jaNdHunArr.append(jdNeedHunNum)
#給一個混看能不能胡
curHunNum = len( sptArr[0])+1
tingArr = []
#是否單調將
isAllHu = False
needNum = 0
for i in range(0,4):
needNum += ndHunArr[i]
if curHunNum - needNum == 1:
isAllHu = True
if isAllHu:
tingArr.extend(tmpArr)
return tingArr
for i in range(0,4):
setTmp = set(sptArr[i+1])
for x in setTmp:
t = []
t.extend(sptArr[i+1])
t.remove(x)
# 將
needNum = 0
for j in range(0,4):
if(i != j):
needNum = needNum + ndHunArr[j]
if needNum <= curHunNum and x not in tingArr:
if canHu(curHunNum-needNum,t):
tingArr.append(x)
# print callTime
# 撲
for j in range(0,4):
if len(sptArr[j+1]) == 0:
continue
if(i != j):
needNum = 0
for k in range(0,4):
if(k != i):
if(k == j):
needNum += jaNdHunArr[k]
else:
needNum += ndHunArr[k]
if needNum <= curHunNum and x not in tingArr:
g_NeedHunCount = 4
getNeedHunInSub(t, 0 )
if g_NeedHunCount <= curHunNum - needNum:
tingArr.append(x)
# print str(callTime) + 10*'-'
return tingArr
import datetime
# print 'reqOtherAction +2'
# samArr = [111, 111, 111, 111, 214, 214, 214, 214, 315, 315, 315, 315, 118, 119, 119 ]
# begin = datetime.datetime.now()
# print testHu(112, samArr, 111)
# end = datetime.datetime.now()
# print end-begin
# samArr = [405,104,104,107,107,203,204,205,207,105,107,108,109]
# getTingArr(samArr,405)
#testPengGang( 302,samArr, 403 ):
# hasGang( samArr, 115 )
#samArr = [101, 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101 ]
#print testGang(101, samArr, 102)
majmap = {"101":"一萬","102":"二萬","103":"三萬","104":"四萬","105":"五萬","106":"六萬","107":"七萬","108":"八萬","109":"九萬",
"201":"一餅","202":"二餅","203":"三餅","204":"四餅","205":"五餅","206":"六餅","207":"七餅","208":"八餅","209":"九餅",
"301":"一條","302":"二條","303":"三條","304":"四條","305":"五條","306":"六條","307":"七條","308":"八條","309":"九條",
"401":"東風","402":"西風","403":"南風","404":"北風","405":"紅中","406":"發財","407":"白板"}
if __name__ == "__main__":
#####################################
#測試胡牌
# samArr = [111, 111, 111, 111, 214, 214, 214, 214, 315, 315, 315, 315, 118, 119, 119 ]
# print testHu(112, samArr, 111)
#####################################
#####################################
#測試具體能聽哪些牌
samArr = [405,202,203,203,204,205,302,302,303,303]#執行時間:0:00:00.001100 <callTime:83> [ 一餅 , 四餅 , 二條 , 三條 , 紅中 , ]
# samArr = [405,202,203,203,204,205,301,302,303,303]#執行時間:0:00:00.000721 <callTime:72> [ 一餅 , 四餅 , 三條 , 紅中 , ]
# samArr = [405,202,203,203,204,205,301,302,302,303]#執行時間:0:00:00.000659 <callTime:72> [ 一餅 , 四餅 , 二條 , 紅中 , ]
# samArr = [405,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000887 <callTime:72> [ 三餅 , 六餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,202,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000715 <callTime:59> [ 二餅 , 五餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,202,203,203,204,301,302,302,303,303]#執行時間:0:00:00.000797 <callTime:72> [ 三餅 , 一條 , 四條 , 紅中 , ]
# samArr = [405,104,104,107,107,107,203,204,205,305,307,308,309]#執行時間:0:00:00.000791 <callTime:83> [ 四萬 , 五條 , 三條 , 四條 , 六條 , 七條 , 紅中 , ]
# samArr = [405,104,104,107,107,107,203,204,205,207,307,308,309]#執行時間:0:00:00.000844 <callTime:85> [ 四萬 , 七餅 , 二餅 , 五餅 , 六餅 , 八餅 , 九餅 , 紅中 , ]
# samArr = [405,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000799 <callTime:88> [ 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,103,104,105,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000859 <callTime:89> [ 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,103,104,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000836 <callTime:88> [ 二餅 , 三條 , 六條 , 紅中 , ]
# #測試兩個癩子的執行時間
# samArr = [405,405,103,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000955 <callTime:136> [ 四萬 , 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,103,105,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000696 <callTime:94> [ 四萬 , 三餅 , 三條 , 紅中 , ]
# samArr = [405,405,103,105,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000790 <callTime:94> [ 四萬 , 三餅 , 一條 , 四條 , 紅中 , ]
# #測試三個癩子的執行時間
# samArr = [405,405,405,105,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.001111 <callTime:135> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 二餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,405,105,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000926 <callTime:118> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 三餅 , 三條 , 六條 , 紅中 , ]
# samArr = [405,405,405,105,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000949 <callTime:116> [ 五萬 , 八萬 , 三萬 , 四萬 , 六萬 , 七萬 , 九萬 , 三餅 , 一條 , 四條 , 六條 , 紅中 , ]
# #測試四個癩子的執行時間
# samArr = [405,405,405,405,106,107,108,202,202,302,304,306,306]#執行時間:0:00:00.000607 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
# samArr = [405,405,405,405,106,107,108,201,202,302,304,306,306]#執行時間:0:00:00.000390 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
# samArr = [405,405,405,405,106,107,108,201,202,302,303,306,306]#執行時間:0:00:00.000758 <callTime:18> [ 一萬 , 二萬 , 三萬 , 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 一餅 , 二餅 , 三餅 , 四餅 , 五餅 , 六餅 , 七餅 , 八餅 , 九餅 , 一條 , 二條 , 三條 , 四條 , 五條 , 六條 , 七條 , 八條 , 九條 , 東風 , 西風 , 南風 , 北風 , 紅中 , 發財 , 白板 , ]
#####################################
#####################################
#測試打出哪些牌能聽
# tingNumArr = [405,202,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000704 <callTime:48> [ 二餅 , 三餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,104,104,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000649 <callTime:61> [ 七餅 , 五條 , ]
# tingNumArr = [405,103,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000874 <callTime:82> [ 三萬 , 六萬 , 九萬 , ]
# #測試兩個癩子
# tingNumArr = [405,405,203,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000424 <callTime:35> [ 三餅 , 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,104,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000616 <callTime:63> [ 四萬 , 七餅 , 五條 , ]
# tingNumArr = [405,405,104,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000551 <callTime:48> [ 四萬 , 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
# #測試三個癩子
# tingNumArr = [405,405,405,203,204,205,301,302,302,303,303]#執行時間:0:00:00.000493 <callTime:27> [ 三餅 , 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,405,107,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000518 <callTime:36> [ 七萬 , 三餅 , 四餅 , 五餅 , 七餅 , 五條 , 七條 , 八條 , 九條 , ]
# tingNumArr = [405,405,405,105,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000522 <callTime:53> [ 五萬 , 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
# #測試四個癩子
# tingNumArr = [405,405,405,405,204,205,301,302,302,303,303]#執行時間:0:00:00.000422 <callTime:24> [ 四餅 , 五餅 , 一條 , 二條 , 三條 , ]
# tingNumArr = [405,405,405,405,107,107,203,204,205,207,305,307,308,309]#執行時間:0:00:00.000604 <callTime:35> [ 七萬 , 三餅 , 四餅 , 五餅 , 七餅 , 五條 , 七條 , 八條 , 九條 , ]
# tingNumArr = [405,405,405,405,106,107,108,109,202,202,302,304,306,306]#執行時間:0:00:00.000678 <callTime:31> [ 六萬 , 七萬 , 八萬 , 九萬 , 二餅 , 四條 , 六條 , 二條 , ]
tingNumArr = [407,407,104,105,106,106,306,306,402,402,405,405,406,406]
##############################
# 測試特殊情況 單一花色重複多次
# tingNumArr = [405,201,201,201,201,202,202,202,202,205,205,205,205,209]#執行時間:0:00:00.006123 <callTime:356> [ 五餅 , 九餅 , ]
# tingNumArr = [405,405,202,204,205,205,206,206,207,208,208,208,209,306]#執行時間:0:00:00.002929 <callTime:358> [ 二餅 , 九餅 , 六條 , ]
# samArr = [405,201,201,201,201,201,202,202,202,202,204,204,205]#執行時間:0:00:00.016391 <callTime:1029> [ 三餅 , 六餅 , 紅中 , ]
# samArr = [405,405,201,201,201,201,202,202,202,202,204,204,209]#執行時間:0:00:00.026671 <callTime:1527> [ 三餅 , 四餅 , 七餅 , 八餅 , 九餅 , 紅中 , ]
##############################
global callTime
callTime = 0
begin = datetime.datetime.now()
# 測試摸哪些牌能胡牌
# tingArr = getTingArr(samArr,405)
#測試打哪些牌能聽牌
tingArr = getTingNumArr(tingNumArr,405)
#測試摸到這張牌是不是能胡牌
# tingArr = {}
# print testHu(209, samArr, 405)
# tingArr = []
# for i in tingNumArr:
# tmp = []
# tmp.extend(tingNumArr)
# tmp.remove(i)
# getTingNumArr(tmp,405)
end = datetime.datetime.now()
runTime = end-begin
rstr = "執行時間:" + str(runTime) + " <callTime:" + str(callTime) + "> [ "
for i in range(0,len(tingArr)):
key = str(tingArr[i])
rstr += majmap.get(key) + " , "
rstr += "]"
print rstr