算法已验证,目前没有发现问题,还有待优化,请指正(没有考虑东南西北中发白);
M.CardTb = {
{0,0,0,0,0,0,0,0,0}, --筒子
{0,0,0,0,0,0,0,0,0}, --万字
{0,0,0,0,0,0,0,0,0}, --条字
{0}
}
---用于存放手牌个数,最后一个用来存放癞子,
首先创建一个table,用来存储手牌,我看到网上不少听牌算法用的都是一维数组,讲真我觉得一维数组有点眼花,所以用了二维数组。
M.Card = {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,}
---听的牌
这个数组就是用来求那些牌可以胡牌的。
做完这些就可以来实现胡牌方法了
M.checkHu = function(CardTb,indexTb,value)
local NewCardTb = M.deepCopy(CardTb)
local continue = true
local Log = false
local index1 = indexTb[1]
local index2 = indexTb[2]
if M.J258 then --有些麻将对将牌有特殊需求(比如长沙麻将)
if indexTb[2] ~= 2 and indexTb[2] ~= 5 and indexTb[2] ~= 8 then
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
end
if continue then
if index1 == 3 and index2 == 5 and value == 0x02 then
Log = true
end
if NewCardTb[index1][index2] == 0 then
continue = false
M.changeJiang(CardTb,index1,index2,value)
else
NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
if NewCardTb[index1][index2] > 0 then
NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
local result = M.check(NewCardTb,Log)
if result then
table.insert(M.HuCardList,value)
if not M.HuType[tostring(value)] then
M.HuType[tostring(value)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(value)] = hutype
return true
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
else
if M.LaiZi and NewCardTb[4][1] > 0 then
NewCardTb[4][1] = NewCardTb[4][1] - 1
local result = M.check(NewCardTb,Log)
if result then
table.insert(M.HuCardList,value)
table.insert(M.HuCardList,value)
if not M.HuType[tostring(value)] then
M.HuType[tostring(value)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(value)] = hutype
return true
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
end
end
end
end
M.changeJiang = function(CardTb,index1,index2,value)
index2 = index2 + 1
if index2 == 10 then
index1 = index1 + 1
index2 = 1
end
if index1 < 4 then
M.checkHu(CardTb,{index1,index2},value)
end
end
看这段可能有点突兀,CardTb 这个参数是将手牌转化成前面说的二维数组,indexTb 是将牌位置的索引,value 是判断是否能胡的牌,这张牌已经添加进手牌了。M.chengeJiang 的主要作用就是在不能胡的情况下变更将牌,M.check是胡牌逻辑,
M.check = function(CardTb,Log)
for k,valuetb in pairs(CardTb) do
if k < 4 then
for i = 1,7 do
local value1 = valuetb[i]
local value2 = valuetb[i + 1]
local value3 = valuetb[i + 2]
if value1 >= 3 then
valuetb[i] = valuetb[i] - 3
value1 = value1 - 3
end
if value2 >= 3 then
valuetb[i + 1] = valuetb[i + 1] - 3
value2 = value2 - 3
end
if value3 >= 3 then
valuetb[i + 2] = valuetb[i + 2] - 3
value3 = value3 - 3
end
if value1 + value2 + value3 == 6 then
valuetb[i] = 0
valuetb[i + 1] = 0
valuetb[i + 2] = 0
value3 = 0
value1 = 0
value2 = 0
end
if value1 + value2 + value3 == 5 and M.LaiZi and CardTb[4][1] > 0 then
value1 = 0
value2 = 0
value3 = 0
valuetb[i] = 0
valuetb[i + 1] = 0
valuetb[i + 2] = 0
CardTb[4][1] = CardTb[4][1] - 1
end
if value1 > 0 then
value1 = value1 -1
if value1 > 0 then
if M.LaiZi and CardTb[4][1] > 0 then
valuetb[i] = valuetb[i] - 2
CardTb[4][1] = CardTb[4][1] - 1
end
else
if value2 > 0 and value3 > 0 then
valuetb[i] = valuetb[i] - 1
valuetb[i + 1] = valuetb[i + 1] - 1
valuetb[i + 2] = valuetb[i + 2] - 1
value2 = value2 - 1
value3 = value3 - 1
elseif M.LaiZi and CardTb[4][1] > 0 then
if value2 + value3 > 0 then
valuetb[i] = valuetb[i] > 0 and valuetb[i] - 1 or 0
valuetb[i + 1] = valuetb[i + 1] > 0 and valuetb[i + 1] - 1 or 0
valuetb[i + 2] = valuetb[i + 2] > 0 and valuetb[i + 2] - 1 or 0
CardTb[4][1] = CardTb[4][1] - 1
else
if CardTb[4][1] >= 2 then
valuetb[i] = valuetb[i] - 1
CardTb[4][1] = CardTb[4][1] - 2
end
end
end
end
end
end
end
end
local count = 0
for k,vTb in pairs(CardTb) do
for k,v in pairs(vTb) do
count = count + v
end
end
return count == 0 and true or false
end
这个是优先把大于3张的做碰处理。然后是2张三连做吃处理(如果缺一张则用癞子补齐,有癞子的话),紧接者就是顺子,如果当前牌数为2的话,有癞子就用癞子补齐做碰处理
最后附上全部代码,
M = {}
M.CardTb = {
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0}
}
M.Card = {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,}
M.LaiZi = false
M.J258 = false
M.QingYiSe = false
M.JJH = false
M.PPH = false
M.QQR = false
M.QXD = false
M.HuCardList = {}
M.HuType = {}
M.TingCardList = {}
M.getTingCardLogic = function(handCardList, weaveCardList,gameType,liaZiTb,param1)
M.TingCardList = {}
local handCardCount = #handCardList
local temp = {} --计算过可以的牌,添加进temp,后面就不会重复计算
for i = 1,handCardCount do
repeat
local CardTb = M.deepCopy(handCardList)
local value = CardTb[i]
if M.isInTable(temp,value) then
break
end
if not M.isInTable(liaZiTb,value) then
CardTb[i] = nil
M.getHuCardLogic(CardTb,weaveCardList,gameType,liaZiTb,param1)
if #M.HuCardList > 0 then
if not M.TingCardList[tostring(value)] then
M.TingCardList[tostring(value)] = {}
end
M.TingCardList[tostring(value)]['hucard'] = M.HuCardList
M.TingCardList[tostring(value)]['hutype'] = M.HuType
end
end
table.insert(temp,value)
until true
end
end
M.getHuCardLogic = function(handCardList, weaveCardList,gameType,liaZiTb,param1)
M.LaiZi = false
M.J258 = false
M.QingYiSe = false
M.JJH = false
M.PPH = false
M.QQR = false
M.QXD = false
M.handCardList = handCardList
M.weaveCardList = weaveCardList
M.gameType = gameType
-------判断游戏是否有癞子,是否要2,5,8坐将--------------------------
M.LaiZi = #liaZiTb > 0
M.J258 = --根据具体游戏来判断是否需要2 5 8 坐将
-------判断游戏是否有癞子,是否要2,5,8坐将--------------------------
--------- 根据游戏类型判断大胡规则 ----------------------------------
M.QingYiSe = --根据具体游戏来判断是否可以胡此大胡
M.QXD = --根据具体游戏来判断是否可以胡此大胡
M.PPH = --根据具体游戏来判断是否可以胡此大胡
M.JJH = --根据具体游戏来判断是否可以胡此大胡
M.QQR = --根据具体游戏来判断是否可以胡此大胡
--------- 根据游戏类型判断大胡规则 ----------------------------------
local handCard = {}
for i,v in pairs(handCardList) do
table.insert(handCard,v)
end
M.HuCardList = {}
M.HuType = {}
for k,v in pairs(M.Card) do
local cardlist = M.deepCopy(handCard)
local needCheck = true
table.insert(cardlist,v)
local CardTb = M.convertToArr(cardlist,liaZiTb)
M.J258 = M.checkSpecialHu(CardTb)
if M.isQiXiaoDui(CardTb) then
needCheck = false
table.insert(M.HuCardList,v)
if not M.HuType[tostring(v)] then
M.HuType[tostring(v)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(v)] = hutype
end
if needCheck and M.isJiangJiangHu(CardTb) then
needCheck = false
table.insert(M.HuCardList,v)
if not M.HuType[tostring(v)] then
M.HuType[tostring(v)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(v)] = hutype
end
if needCheck then
M.checkHu(CardTb,{1,1},v)
end
end
M.removeRepeated(M.HuCardList)
end
M.checkSpecialHu = function(CardTb) --检查是否符合大胡规则,不确定是否胡牌,作用于是否需要2,5,8坐将
if M.QingYiSe then
if M.isQingYiSe(CardTb) then
return false
end
end
if M.PPH then
if M.isPengPengHu(CardTb) then
return false
end
end
if M.QQR then
if M.isQuanQiuRen(CardTb) then
return false
end
end
return true
end
M.checkHuType = function(CardTb,hutype)
if M.QingYiSe then
if M.isQingYiSe(CardTb) then
hutype = hutype .. '清一色\n'
end
end
if M.QXD then
if M.isQiXiaoDui(CardTb) then
hutype = hutype .. '七小对\n'
end
end
if M.PPH then
if M.isPengPengHu(CardTb) then
hutype = hutype .. '碰碰胡\n'
end
end
if M.JJH then
if M.isJiangJiangHu(CardTb) then
hutype = hutype .. '将将胡\n'
end
end
if M.QQR then
if M.isQuanQiuRen(CardTb) then
hutype = hutype .. '全求人\n'
end
end
return hutype
end
M.checkHu = function(CardTb,indexTb,value)
local NewCardTb = M.deepCopy(CardTb)
local continue = true
local Log = false
local index1 = indexTb[1]
local index2 = indexTb[2]
if M.J258 then
if indexTb[2] ~= 2 and indexTb[2] ~= 5 and indexTb[2] ~= 8 then
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
end
if continue then
if index1 == 3 and index2 == 5 and value == 0x02 then
Log = true
end
if NewCardTb[index1][index2] == 0 then
continue = false
M.changeJiang(CardTb,index1,index2,value)
else
NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
if NewCardTb[index1][index2] > 0 then
NewCardTb[index1][index2] = NewCardTb[index1][index2] - 1
local result = M.check(NewCardTb,Log)
if result then
-- logError('xx : '..Json.encode(CardTb))
table.insert(M.HuCardList,value)
if not M.HuType[tostring(value)] then
M.HuType[tostring(value)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(value)] = hutype
return true
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
else
if M.LaiZi and NewCardTb[4][1] > 0 then
NewCardTb[4][1] = NewCardTb[4][1] - 1
local result = M.check(NewCardTb,Log)
if result then
-- logError('bb : '..Json.encode(CardTb))
table.insert(M.HuCardList,value)
table.insert(M.HuCardList,value)
if not M.HuType[tostring(value)] then
M.HuType[tostring(value)] = ''
end
local hutype = '平胡\n'
hutype = M.checkHuType(CardTb,hutype)
M.HuType[tostring(value)] = hutype
return true
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
else
continue = false
M.changeJiang(CardTb,index1,index2,value)
end
end
end
end
end
M.changeJiang = function(CardTb,index1,index2,value)
index2 = index2 + 1
if index2 == 10 then
index1 = index1 + 1
index2 = 1
end
if index1 < 4 then
M.checkHu(CardTb,{index1,index2},value)
end
end
M.check = function(CardTb,Log)
for k,valuetb in pairs(CardTb) do
if k < 4 then
for i = 1,7 do
local value1 = valuetb[i]
local value2 = valuetb[i + 1]
local value3 = valuetb[i + 2]
if value1 >= 3 then
valuetb[i] = valuetb[i] - 3
value1 = value1 - 3
end
if value2 >= 3 then
valuetb[i + 1] = valuetb[i + 1] - 3
value2 = value2 - 3
end
if value3 >= 3 then
valuetb[i + 2] = valuetb[i + 2] - 3
value3 = value3 - 3
end
if value1 + value2 + value3 == 6 then
valuetb[i] = 0
valuetb[i + 1] = 0
valuetb[i + 2] = 0
value3 = 0
value1 = 0
value2 = 0
end
if value1 + value2 + value3 == 5 and M.LaiZi and CardTb[4][1] > 0 then
value1 = 0
value2 = 0
value3 = 0
valuetb[i] = 0
valuetb[i + 1] = 0
valuetb[i + 2] = 0
CardTb[4][1] = CardTb[4][1] - 1
end
if value1 > 0 then
value1 = value1 -1
if value1 > 0 then
if M.LaiZi and CardTb[4][1] > 0 then
valuetb[i] = valuetb[i] - 2
CardTb[4][1] = CardTb[4][1] - 1
end
else
if value2 > 0 and value3 > 0 then
valuetb[i] = valuetb[i] - 1
valuetb[i + 1] = valuetb[i + 1] - 1
valuetb[i + 2] = valuetb[i + 2] - 1
value2 = value2 - 1
value3 = value3 - 1
elseif M.LaiZi and CardTb[4][1] > 0 then
if value2 + value3 > 0 then
valuetb[i] = valuetb[i] > 0 and valuetb[i] - 1 or 0
valuetb[i + 1] = valuetb[i + 1] > 0 and valuetb[i + 1] - 1 or 0
valuetb[i + 2] = valuetb[i + 2] > 0 and valuetb[i + 2] - 1 or 0
CardTb[4][1] = CardTb[4][1] - 1
else
if CardTb[4][1] >= 2 then
valuetb[i] = valuetb[i] - 1
CardTb[4][1] = CardTb[4][1] - 2
end
end
end
end
end
end
end
end
local count = 0
for k,vTb in pairs(CardTb) do
for k,v in pairs(vTb) do
count = count + v
end
end
return count == 0 and true or false
end
M.convertToArr = function(handCardList,liaZiTb)
local CardTb = M.deepCopy(M.CardTb)
for k,value in ipairs(handCardList) do
if M.isInTable(liaZiTb,value) then
CardTb[4][1] = CardTb[4][1] + 1
else
local suit = math.modf(value/16) + 1
CardTb[suit][math.fmod(value, 16)] = CardTb[suit][math.fmod(value, 16)] + 1
end
end
return CardTb
end
M.isQingYiSe = function(CardTb)
local AllCardTb = M.deepCopy(CardTb)
for k,value in ipairs(M.weaveCardList) do
local suit = math.modf(value/16) + 1
AllCardTb[suit][math.fmod(value, 16)] = AllCardTb[suit][math.fmod(value, 16)] + 1
end
for k,valuetb in pairs(AllCardTb) do
local count = 0
for k,value in pairs(valuetb) do
count = count + value
end
count = count + AllCardTb[4][1]
if count >= 14 then
return true
end
end
return false
end
M.isQiXiaoDui = function(CardTb)
local newCardTb = M.deepCopy(CardTb)
local count = 0
for k,valueTb in pairs(newCardTb) do
if k <= 3 then
for k,v in pairs(valueTb) do
if newCardTb[4][1] > 0 and v%2 ~= 0 then
newCardTb[4][1] = newCardTb[4][1] - 1
else
if v%2 ~= 0 then
return false
end
end
end
end
end
for k,v1 in pairs(CardTb) do
for k,v in pairs(v1) do
count = count + v
end
end
if count ~= 14 then
return false
end
return true
end
M.isJiangJiangHu = function(CardTb)
local count = 0
for k,valueTb in pairs(CardTb) do
for k1,v in pairs(valueTb) do
if v > 0 and k1 ~= 2 and k1 ~= 5 and k1 ~= 8 then
return false
end
count = count + v
end
end
if count ~= 14 then
return false
end
return true
end
M.isQuanQiuRen = function(CardTb)
local count = 0
for k,valueTb in pairs(CardTb) do
for k1,v in pairs(valueTb) do
count = count + v
end
end
if count ~= 2 then
return false
end
return true
end
M.isPengPengHu = function(CardTb)
local AllCardTb = M.deepCopy(M.CardTb)
for k,value in ipairs(M.weaveCardList) do
local suit = math.modf(value/16) + 1
AllCardTb[suit][math.fmod(value, 16)] = AllCardTb[suit][math.fmod(value, 16)] + 1
end
for k,valueTb in pairs(AllCardTb) do
for k,v in pairs(valueTb) do
if v ~= 0 and v >= 3 then
return false
end
end
end
local count = 0
local pengcount = 0
for k,valueTb in pairs(CardTb) do
for k,v in pairs(valueTb) do
count = count + v
if v == 3 then
pengcount = pengcount + 1
end
end
end
if pengcount*3 + 2 ~= count then
return false
end
return true
end
M.isInTable = function(tb,value)
for k,v in ipairs(tb) do
if v == value then
return true
end
end
return false
end
M.deepCopy = function (object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end -- if
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
M.removeRepeated = function(a)
for k,v in pairs(a) do
local count=0
for j in pairs(a)do count=count+1 end
for i=k+1,count do
if v==a[i] then
table.remove(a,i)
end
end
end
end
return M
最后说明一下,外部用的方法 M.getTingCardLogic 可以用来计算打出那些牌可以听那些牌,M.getHuCardLogic 计算可以听那些牌。 M.HuCardList M.HuType 在使用 M.getHuCardLogic 会用到来存储胡牌信息 ,M.TingCardList 在使用M.getTingCardLogic用来存储听牌信息,两个方法参数一样,前三个参数就不解释了。liaZiTb 是有癞子玩法的时候把那些牌是癞子放到数组中。param1 大多数情况是没有用的,有玩法是选中大胡玩法才可以胡大胡,而大胡是不需要坐将的,所以param1根据自己的实际需要做处理