麻将胡牌算法
运用递归思路,先找出两张一样的牌作将牌,然后在剩下的牌中找顺子和三个一样的牌,当剩余的牌数为0,则排定可以胡牌。目前只是四川麻将的赢牌番型,除去风牌的。可自行进行扩展。(万:11-19,筒:21-29,条31-39),直接可以下载使用。
mjwintable类:
--赢牌倍率 gMJWinRate = { 1, 2, 4, 4, 4, 4, 8, 8, 8, 16, 16, 16, 16, 32, 64, 256 } gMJWinFJRate = { 2, 2 } --赢牌基本类型 gMJWinType = { } --翻1倍 gMJWinType.ordinary = 1 --平胡 --翻2倍 gMJWinType.duiduiHu = 2 --对对胡 --翻4倍 gMJWinType.ordinaryQ = 3 --清一色 gMJWinType.yaojiu = 4 --幺九 gMJWinType.sevendui = 5 --七小对 gMJWinType.jingou = 6 --金钩钓 --翻8倍 gMJWinType.duiduiHuQ = 7 --对对胡清一色 gMJWinType.duiduiHu258 = 8 --对对胡258 gMJWinType.sevenduiQ = 9 --清七小对 --翻16倍 gMJWinType.yaojiuQ = 10 --幺九清一色 gMJWinType.sevenduiL = 11 --龙七小对 gMJWinType.jingouQ = 12 --清金钩钓 gMJWinType.jingou258 = 13 --金钩钓258 --翻32倍 gMJWinType.sevenduiQL = 14 --清龙七小对 --翻64倍 gMJWinType.arhat = 15 --十八罗汉 --翻256倍 gMJWinType.arhatQ = 16 --清十八罗汉 --赢牌附加类型 gMJWinFJType = { } gMJWinFJType.noyaojiu = 1 --断幺九 gMJWinFJType.doorclear = 2 --门前清 --外部调用方法 --匹配牌型(1--总牌,2--手牌,3--杠数) --paislist所有牌table包括手牌、碰牌、杠牌(去掉一张按三张算)如:paislist = {11,12,13,14,15,33,21} --handpaisList手牌table 如:handpaisList = {11,12,13,14,15,33,21} --gangPengList杠碰牌table --gangNum杠个数 function CheckMJWinTable( paislist, handpaisList, gangPengList, gangNum ) if #paislist ~= 14 then do return end end table.sort( paislist, function( a, b ) return a < b end) table.sort( handpaisList, function( a, b ) return a < b end) local isWin = false local winType = nil local sameColour = TableBySameColour(paislist) if gangNum == 4 then -- 判断十八罗汉 if handpaisList[ 1 ] == handpaisList[ 2 ] then local paiType = math.floor( handpaisList[ 1 ] / 10 ) for pai, v in pairs( gangPengList ) do if math.floor( pai / 10 ) ~= paiType then winType = gMJWinType.arhat do return true, winType end end end winType = gMJWinType.arhatQ do return true, winType end end else local win, duiLong = MJWinTableBySevenDouble( handpaisList ) if win == true then -- 判断七对 if sameColour == true then if duiLong == true then winType = gMJWinType.sevenduiQL else winType = gMJWinType.sevenduiQ end else if duiLong == true then winType = gMJWinType.sevenduiL else winType = gMJWinType.sevendui end end do return win, winType end elseif MJWinTableByCommon( handpaisList ) then local duiWin = TableByDuiDuiHu( handpaisList, gangPengList, gangNum ) local win19 = MJWinTableByCommon( handpaisList, gangPengList, 19 ) local win258 = MJWinTableByCommon( handpaisList, gangPengList, 258 ) local jingouWin = #handpaisList == 2 if jingouWin == true and ( win258 == true or sameColour == true ) then if win258 == true then winType = gMJWinType.jingou258 else winType = gMJWinType.jingouQ end do return true, winType end elseif win19 == true and sameColour == true then -- 青19 winType = gMJWinType.yaojiuQ do return true, winType end elseif duiWin == true and ( win258 == true or sameColour == true ) then if win258 == true then winType = gMJWinType.duiduiHu258 else winType = gMJWinType.duiduiHuQ end do return true, winType end elseif sameColour == true or win19 == true or jingouWin == true then if sameColour == true then winType = gMJWinType.ordinaryQ elseif win19 == true then winType = gMJWinType.yaojiu else winType = gMJWinType.jingou end do return true, winType end elseif duiWin == true then winType = gMJWinType.duiduiHu do return true, winType end else winType = gMJWinType.ordinary do return true, winType end end end end return false end --检测附加翻型(在胡牌的基础上判断)参数1--断幺九,参数2--门清 function CheckMJFJType( paislist, handpaisList ) local isDuanYaoJiu = false local isMenQing = false local paiNum = 0 for index, pai in pairs( paislist ) do if pai % 10 ~= 9 and pai % 10 ~= 1 then paiNum = paiNum + 1 end end if paiNum == 14 then isDuanYaoJiu = true end if #handpaisList == 14 then isMenQing = true end return isDuanYaoJiu, isMenQing end -- 普通胡牌 function MJWinTableByCommon( handpaisList, gangPengList, winType ) if winType == 19 then for pai, v in pairs( gangPengList ) do if pai % 10 ~= 1 and pai % 10 ~= 9 then return false end end elseif winType == 258 then for pai, v in pairs( gangPengList ) do if pai % 10 ~= 2 and pai % 10 ~= 5 and pai % 10 ~= 8 then return false end end end if #handpaisList == 2 then do return handpaisList[ 1 ] == handpaisList[ 2 ] end end local genList = MJFindGen( handpaisList, winType ) if genList == nil then return false else for num, paiList in pairs( genList ) do local state = MJWinTableCommonCheckWin( paiList, winType ) if state == true then return true end end end return false end function MJWinTableCommonCheckWin( paiList, winType ) local shunziList = MFFindShunZi( paiList, winType ) if shunziList == nil then return false else for num, pailist in pairs( shunziList ) do if #pailist == 0 then return true else local state = MJWinTableCommonCheckWin( pailist, winType ) if state == true then return true end end end end end -- genType: 19 19根 -- genType: 258 258根 function MJFindGen( handpaisList, genType ) local genList = {} local haveGen = false for index1 = 1, #handpaisList - 1 do local findNum = handpaisList[ index1 ] if genList[ findNum ] == nil then for index2 = index1 + 1, #handpaisList do if genType == 19 then if handpaisList[ index2 ] == findNum and ( findNum % 10 == 1 or findNum % 10 == 9 ) then genList[ findNum ] = Util.CloneTable( handpaisList ) table.remove( genList[ findNum ], index2 ) table.remove( genList[ findNum ], index1 ) haveGen = true break end elseif genType == 258 then if handpaisList[ index2 ] == findNum and ( findNum % 10 == 2 or findNum % 10 == 5 or findNum % 10 == 8 ) then genList[ findNum ] = Util.CloneTable( handpaisList ) table.remove( genList[ findNum ], index2 ) table.remove( genList[ findNum ], index1 ) haveGen = true break end else if handpaisList[ index2 ] == findNum then genList[ findNum ] = Util.CloneTable( handpaisList ) table.remove( genList[ findNum ], index2 ) table.remove( genList[ findNum ], index1 ) haveGen = true break end end end end end if haveGen == true then return genList else return nil end end -- sType: 19 19顺子 -- sType: 258 258顺子 function MFFindShunZi( handpaisList, sType ) local shunziList = {} local haveShunzi = false for index, value in pairs( handpaisList ) do if sType == 19 then if ( value % 10 == 1 or value % 10 == 9 ) and shunziList[ value .. value .. value ] == nil then local findList1 = Util.TableFind( handpaisList, value ) if #findList1 >= 3 then local sign = value .. value .. value shunziList[ sign ] = Util.CloneTable( handpaisList ) table.remove( shunziList[ sign ], findList1[ 3 ] ) table.remove( shunziList[ sign ], findList1[ 2 ] ) table.remove( shunziList[ sign ], findList1[ 1 ] ) haveShunzi = true end end if ( value % 10 == 1 or value % 10 == 7 ) and shunziList[ value .. value + 1 .. value + 2 ] == nil then local findList1 = Util.TableFind( handpaisList, value + 1 ) if #findList1 ~= 0 then local findList2 = Util.TableFind( handpaisList, value + 2 ) if #findList2 ~= 0 then local sign = value .. value + 1 .. value + 2 shunziList[ sign ] = Util.CloneTable( handpaisList ) local sorList = { index, findList1[ 1 ], findList2[ 1 ] } table.sort( sorList, MJPaiSort ) table.remove( shunziList[ sign ], sorList[ 3 ] ) table.remove( shunziList[ sign ], sorList[ 2 ] ) table.remove( shunziList[ sign ], sorList[ 1 ] ) haveShunzi = true end end end elseif sType == 258 then if ( value % 10 == 2 or value % 10 == 5 or value % 10 == 8 ) and shunziList[ value .. value .. value ] == nil then local findList1 = Util.TableFind( handpaisList, value ) if #findList1 >= 3 then local sign = value .. value .. value shunziList[ sign ] = Util.CloneTable( handpaisList ) table.remove( shunziList[ sign ], findList1[ 3 ] ) table.remove( shunziList[ sign ], findList1[ 2 ] ) table.remove( shunziList[ sign ], findList1[ 1 ] ) haveShunzi = true end end else if shunziList[ value .. value .. value ] == nil or shunziList[ value .. value + 1 .. value + 2 ] == nil then local findList1 = Util.TableFind( handpaisList, value + 1 ) if #findList1 ~= 0 then local findList2 = Util.TableFind( handpaisList, value + 2 ) if #findList2 ~= 0 then local sign = value .. value + 1 .. value + 2 shunziList[ sign ] = Util.CloneTable( handpaisList ) local sorList = { index, findList1[ 1 ], findList2[ 1 ] } table.sort( sorList, MJPaiSort ) table.remove( shunziList[ sign ], sorList[ 3 ] ) table.remove( shunziList[ sign ], sorList[ 2 ] ) table.remove( shunziList[ sign ], sorList[ 1 ] ) haveShunzi = true end end findList1 = Util.TableFind( handpaisList, value ) if #findList1 >= 3 then local sign = value .. value .. value shunziList[ sign ] = Util.CloneTable( handpaisList ) table.remove( shunziList[ sign ], findList1[ 3 ] ) table.remove( shunziList[ sign ], findList1[ 2 ] ) table.remove( shunziList[ sign ], findList1[ 1 ] ) haveShunzi = true end end end end if haveShunzi == true then return shunziList else return nil end end --七小对 function MJWinTableBySevenDouble( handpaisList ) if #handpaisList ~= 14 then return end local doubleList = {} local haveLong = false for index = 1, 13, 2 do if handpaisList[ index ] ~= handpaisList[ index + 1 ] then return false else table.insert( doubleList, handpaisList[ index ] ) end end local beforenum = doubleList[ 1 ] for index = 2, 7 do if beforenum == doubleList[index] then haveLong = true break else beforenum = doubleList[index] end end return true, haveLong end --清一色 function TableBySameColour( paisList ) if paisList[ 14 ] < 20 then return true elseif paisList[ 1 ] > 20 and paisList[ 14 ] < 30 then return true elseif paisList[ 1 ] > 30 and paisList[ 14 ] < 40 then return true end return false end --对对胡 function TableByDuiDuiHu( paislist, gangPengList, gangNum ) if gangNum ~= 0 then return false end local count3 = 0 local count2 = 0 local continuecount = 1 local beforenum = paislist[ 1 ] for index = 2, #paislist do if beforenum == paislist[ index ] then continuecount = continuecount + 1 else if continuecount == 2 then count2 = count2 + 1 elseif continuecount == 3 then count3 = count3 + 1 else return false end continuecount = 1 beforenum = paislist[ index ] end end if continuecount == 2 then count2 = count2 + 1 elseif continuecount == 3 then count3 = count3 + 1 end if count2 == 1 and count3 + Util.GetTableLength( gangPengList ) == 4 then return true end end -- --排序 function MJPaiSort( pai1, pai2 ) return pai1 < pai2 endUtil类
-- 深度拷贝table, 基础数据类型没有问题( number, string, boolean, table ),其他的比如:(function 等等)不要挑战 local function cloneTable( vTable ) if type( vTable ) ~= "table" then return nil; end local tClone = {} for i, v in pairs( vTable ) do if type( v ) == "table" then tClone[ i ] = cloneTable( v ) else tClone[ i ] = v end end return tClone end -- 深度比对拷贝table, 基础数据类型没有问题( number, string, boolean, table ),其他的比如:(function 等等)不要挑战 local function compareTable( vSrcTable, vDesTable ) if type( vSrcTable ) ~= "table" then return nil; end for i, v in pairs( vSrcTable ) do if type( v ) == "table" then if vDesTable[ i ] == nil then vDesTable[ i ] = {} end compareTable( v, vDesTable[ i ] ) else if vDesTable[ i ] == nil then vDesTable[ i ] = v end end end end local function printTable( vTable, vLevel ) local indent ="" -- i缩进,当前调用缩进 if vLevel == nil then vLevel = 0 end for i = 1, vLevel do indent = indent.." " end local tHasElm = false for k, v in pairs( vTable ) do if tHasElm == false then System.Log( indent.."{" ) tHasElm = true end if ( type( v ) == "table" ) then -- type(v) 当前类型时否table 如果是,则需要递归, System.Log( indent.." " .. "[" .. k .. "]" ) printTable( v, vLevel + 1 ) else -- 否则直接输出当前值 System.Log( indent.." " .. "[" .. k .. "] = [" ..tostring( v ).."]" ) end end if tHasElm == true then System.Log( indent.."}" ) end end local function splitString( text, split, len ) if len == nil then len = 1 end local textSet = {} local startIndex = 0 local length = string.len( text ) while startIndex <= length do local findSI, findEI = string.find( text, split, startIndex ) if findEI == nil then findEI = length + len end local textItem = string.sub( text, startIndex, findEI - len ) table.insert( textSet, textItem ) startIndex = findEI + 1 end return textSet end local base32 = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y'} local function str10Convert32( strnum ) local num = tonumber(strnum) local numtb = {} local ret = "" if num > 0 then while num > 0 do numtb[#numtb + 1] = num %32 num = math.floor( num / 32) end for i = #numtb, 1, -1 do ret = ret .. base32[numtb[i] + 1] end elseif num == 0 then ret = "0" else num = math.abs(num) while num > 0 do numtb[#numtb + 1] = num %32 num = math.floor( num / 32) end ret = ret .. "-" for i = #numtb, 1, -1 do ret = ret .. base32[numtb[i] + 1] end end return ret end -- 不区分大小写 local function str32Convert10( numStr ) assert(numStr, "can't be nil") numStr = string.upper(numStr) local ret = 0 local function findBase32Index( ch ) for k, v in pairs( base32 ) do if v == ch then return k end end end local pownum = 0 for i = #numStr, 1, -1 do local temp = string.sub( numStr, i, i) local index = findBase32Index( temp ) if not index then return end ret = ret + (index-1)*math.pow(32, pownum) pownum = pownum + 1 end return tostring(ret) end local function formatNumber( num ) if num < 10000 then return num else return math.floor( num / 10000 ) .. "万" end end local function getStringCharCount( str ) local charCount = 0 local byteCount = 0 for i = 1, #str do if byteCount > 1 then byteCount = byteCount - 1 else local curByte = string.byte( str, i ) if curByte > 0 and curByte <= 127 then byteCount = 1 elseif curByte >= 192 and curByte < 224 then byteCount = 2 elseif curByte >= 224 and curByte < 240 then byteCount = 3 elseif curByte >= 240 and curByte < 248 then byteCount = 4 elseif curByte >= 248 and curByte < 252 then byteCount = 5 else byteCount = 6 end charCount = charCount + 1 end end return charCount end local function getStringCharArray( str ) local charArray = {} local byteCount = 0 for index = 1, #str do if byteCount > 1 then byteCount = byteCount - 1 else local curByte = string.byte( str, index ) if curByte > 0 and curByte <= 127 then byteCount = 1 elseif curByte >= 192 and curByte < 224 then byteCount = 2 elseif curByte >= 224 and curByte < 240 then byteCount = 3 elseif curByte >= 240 and curByte < 248 then byteCount = 4 elseif curByte >= 248 and curByte < 252 then byteCount = 5 else byteCount = 6 end table.insert( charArray, string.sub( str, index, index + byteCount - 1 ) ) end end return charArray end local function getUserTableInfo( userTableInfo ) local tableInfo = splitString( userTableInfo, "_" ) if #tableInfo == 2 then return tableInfo[ 1 ], tonumber( tableInfo[ 2 ] ) end end local function isInt( num ) return num == math.floor( num ) end local function getTableLength( t ) local length = 0 for key, value in pairs( t ) do length = length + 1 end return length end local function dateToSecond( date ) local dateStr = Util.SplitString( date, "-" ) local time = os.time({year = "20"..dateStr[1], month = dateStr[2], day = dateStr[3]}) return time end local function getToday0ClockTime( ) local date = os.date( "*t" ) return os.time( { year = date.year, month = date.month, day = date.day, hour = 0, minute = 0, second = 0 } ) end local function jsonGetValue( text, name ) local _, findEnd = string.find( text, [["]] .. name .. [[":]] ) if findEnd == nil then System.Log( "findEnd " .. tostring( findEnd ) .. " " .. tostring( text ) .. " " .. tostring( name ) ) return nil end local startPos, endPos = string.find( text, ",", findEnd + 1 ) System.Log( "startPos " .. tostring( startPos ) ) if startPos == nil then startPos, endPos = string.find( text, "}", findEnd + 1 ) end System.Log( "startPos2 " .. tostring( startPos ) ) local valueDir = string.sub( text, findEnd + 1, startPos - 1 ) local tTextSet = splitString( valueDir, [["]] ) System.Log( "tTextSet[ 2 ] " .. tostring( tTextSet[ 2 ] ) ) return tTextSet[ 2 ] == nil and tTextSet[ 1 ] or tTextSet[ 2 ] end local function formatNumEx2( num ) num = num + 0.0001 if num >= 100000000 then if math.floor( num / 10000000 ) / 10 == math.floor( num / 100000000 ) then return math.floor( num / 100000000 ) .. "亿" else return math.floor( num / 10000000 ) / 10 .. "亿" end elseif num >= 10000 then if math.floor( num / 1000 ) / 10 == math.floor( num / 10000 ) then return math.floor( num / 10000 ) .. "万" else return math.floor( num / 1000 ) / 10 .. "万" end else return math.floor( num ) end end function delTableKeys( vTable, vKeys ) local newTables = {} for key, value in pairs( vTable ) do if vKeys[ key ] == nil then newTables[ key ] = value end end return newTables end function keepTableKeys( vTable, vKeys ) local newTables = {} for key, value in pairs( vTable ) do if vKeys[ key ] ~= nil then newTables[ key ] = value end end return newTables end local function jsonObjToTable( jsonObj ) if jsonObj[ "_keys" ] ~= nil then local objTable = {} for index = 1, #jsonObj[ "_keys" ] do local key = jsonObj[ "_keys" ][ index ] local value = jsonObj[ "_values" ][ index ] if type( value ) == "table" then objTable[ key ] = jsonObjToTable( value ) else objTable[ key ] = value end end return objTable end end local lJson = _G[ 'json' ] local function jsonFKLJDecode( jsonStr ) if jsonStr ~= nil and type( jsonStr ) == "string" then local jsonObj = lJson.decode( jsonStr, 1, nil ) local jsonTable = jsonObjToTable( jsonObj ) return jsonTable end end local function jsonFKLJEncode( jsonObj ) if jsonObj ~= nil then local jsonKeysStr = "" local jsonValuesStr = "" local spacePoint = "" if type( jsonObj ) == "number" then return jsonObj elseif type( jsonObj ) == "string" then return jsonObj elseif type( jsonObj ) == "boolean" then return jsonObj end if Util.GetTableLength( jsonObj ) == 0 then return '{"_keys":[],"_values":[]}' end for key, value in pairs( jsonObj ) do if type( key ) == "number" then jsonKeysStr = jsonKeysStr .. ( jsonKeysStr == "" and '\"_keys\":[' .. spacePoint .. key or spacePoint .. key ) elseif type( key ) == "string" then jsonKeysStr = jsonKeysStr .. ( jsonKeysStr == "" and '\"_keys\":[' .. spacePoint .. '\"' .. key .. '\"' or spacePoint .. '\"' .. key .. '\"' ) end if type( value ) == "table" then jsonValuesStr = jsonValuesStr .. ( jsonValuesStr == "" and '\"_values\":[' .. spacePoint .. jsonFKLJEncode( value ) or spacePoint .. jsonFKLJEncode( value ) ) else if type( value ) == "number" then jsonValuesStr = jsonValuesStr .. ( jsonValuesStr == "" and '\"_values\":[' .. spacePoint .. value or spacePoint .. value ) elseif type( value ) == "string" then jsonValuesStr = jsonValuesStr .. ( jsonValuesStr == "" and '\"_values\":[' .. spacePoint .. '\"' .. value .. '\"' or spacePoint .. '\"' .. value .. '\"' ) elseif type( value ) == "boolean" then jsonValuesStr = jsonValuesStr .. ( jsonValuesStr == "" and '\"_values\":[' .. spacePoint .. tostring( value ) or spacePoint .. tostring( value ) ) end end spacePoint = "," end return jsonKeysStr == "" and jsonKeysStr or "{" .. jsonKeysStr .. "]," .. jsonValuesStr .. "]}" end return "" end local lSQLBadStr = "sitename|net user|xp_cmdshell|and|exec|execute|insert|create|drop|" .. "table|from|grant|use|group_concat|column_name|" .. "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" .. "chr|mid|master|truncate|char|declare|or|;|like|//|/|#" local lSQLBadWords = {} local function sqlCheck( str ) if #lSQLBadWords == 0 then lSQLBadWords = Util.SplitString( lSQLBadStr, "|" ) end local lowerStr = string.lower( str ) System.Log( "lowerStr " .. tostring( lowerStr ) ) for index = 1, #lSQLBadWords do if string.find( lowerStr, lSQLBadWords[ index ] ) ~= nil then System.Log( "lSQLBadWords[ index ] " .. " " .. tostring( lSQLBadWords[ index ] ) .. " " .. tostring( string.find( lowerStr, lSQLBadWords[ index ] ) ) ) return false end end return true end local function removeTableValue( srcTable, delValue ) for key, value in pairs( srcTable ) do if value == delValue then table.remove( srcTable, key ) break end end end local function checkTableValueExist( srcTable, value ) for key, tableValue in pairs( srcTable ) do if value == tableValue then return true end end return false end local function tableFind( srcTable, desValue ) local keyList = {} for key, value in pairs( srcTable ) do if value == desValue then table.insert( keyList, key ) end end return keyList end Util = { CloneTable = cloneTable, CompareTable = compareTable, PrintTable = printTable, SplitString = splitString, Str10Convert32 = str10Convert32, Str32Convert10 = str32Convert10, FormatNumber = formatNumber, GetStringCharCount = getStringCharCount, GetStringCharArray = getStringCharArray, GetUserTableInfo = getUserTableInfo, IsInt = isInt, GetTableLength = getTableLength, DateToSecond = dateToSecond, GetToday0ClockTime = getToday0ClockTime, JSONGetValue = jsonGetValue, JSONGetTable = jsonGetTable, FormatNumEx2 = formatNumEx2, DelTableKeys = delTableKeys, KeepTableKeys = keepTableKeys, JSONFKLJDecode = jsonFKLJDecode, JSONFKLJEncode = jsonFKLJEncode, SQLCheck = sqlCheck, RemoveTableValue = removeTableValue, CheckTableValueExist= checkTableValueExist, TableFind = tableFind, }