PokerRule.lua
-- 扑克规则模块,主要用于判断玩家出牌的时候符不符合规则
PokerRule = {}
function table_leng(t)
local leng=0
for k, v in pairs(t) do
leng=leng+1
end
return leng;
end
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
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
--- 判断是否是王炸
function PokerRule.IsWangZha( pokerList )
if ( (pokerList[1]:getNum() == PokerType.BigKing and pokerList[2]:getNum() == PokerType.SmallKing)
or (pokerList[1]:getNum() == PokerType.SmallKing and pokerList[2]:getNum() == PokerType.BigKing))
then
return true
end
return false
end
--- 判断 list 里面是否有相同的牌,
-- @param count 表示连续count张
-- @return true:表示连续count一样,false:表示不一样
function PokerRule.IsHaveSame(pokerList, count)
--- 从 count 变化到 1, 每次变化 -1的步长
for i = count, 2, -1 do
local p1_name = pokerList[i]:getNum()
local p2_name = pokerList[i - 1]:getNum()
if (p1_name ~= p2_name)
then
return false
end
end
return true
end
-- 判断是否是 三带一
-- 因为我们的扑克牌是已经排序好的,所以判断 是不是 3带1,
-- 是要判断这2种类型就可以了: 1. AAAB 2. ABBB
function PokerRule.Is3DaiYi(pokerList)
--- 先判断 AAAB 的类型
if (PokerRule.IsHaveSame(pokerList, 3))
then
return true
end
--- 如果不是,则判断 是不是 ABBB , 我们可以先把 A 删掉
local tmpList = deepcopy(pokerList)
table.remove(tmpList, 1)
if (PokerRule.IsHaveSame(tmpList, 3))
then
return true
end
-- 不是 三带一
return false
end
-- 判断是否是 三带一对
-- 因为我们的扑克牌是已经排序好的,所以判断三带一对,
-- 是要判断这2种类型就可以了: 1. AAABB 2. AABBB
function PokerRule.Is3DaiDui(pokerList)
local tmpList = deepcopy(pokerList)
local table_len = table_leng(tmpList)
if (table_len == 5)
then
--- 先判断 AAABB 的类型
if (PokerRule.IsHaveSame(tmpList, 3))
then
table.remove(tmpList, 1)
table.remove(tmpList, 1)
table.remove(tmpList, 1)
if (PokerRule.IsHaveSame(tmpList, 2))
then
return true
end
return false
end
-- 判断 AABBB
if (PokerRule.IsHaveSame(tmpList, 2))
then
table.remove(tmpList, 1)
table.remove(tmpList, 1)
if (PokerRule.IsHaveSame(tmpList, 3))
then
return true
end
return false
end
end
-- 不是 三带一对
return false
end
--- 判断是不是顺子
-- 因为我们的扑克牌已经从大到小排序好了,所以可以相减判断
function PokerRule.IsShunZi(pokerList)
--- local table_len = table_leng(pokerList)
for k, v in pairs(pokerList) do
local p1 = v
local p2 = pokerList[k+1]
if ( p1 ~= nil and p2 ~= nil and (p1:getNum() - p2:getNum() ~= 1))
then
return false
end
end
return true
end
-------判断是不是连对
function PokerRule.IsLianDui(pokerList)
local index = 1
for k, v in pairs(pokerList) do
local p1 = pokerList[index]
local p2 = pokerList[index+1]
if ( p1 ~= nil and p2 ~= nil and (p1:getNum() ~= p2:getNum()) )
then
return false
end
index = index + 1
end
end
--- 获取三个头的有几个, 即飞机头有几个
-- @return 返回值是一个table,里面装了 飞机头的牌 例如 KKK3QQQ4, 则返回 talbe {K, Q}
function PokerRule.GetFeiJiTouCount(pokerList)
count_table = {}
local index = 1
for k, v in pairs(pokerList) do
local p1 = pokerList[index]
local p2 = pokerList[index+1]
local p3 = pokerList[index+2]
if (p1 ~= nil and p2 ~= nil and p3 ~= nil and ((p1:getNum() == p2:getNum()) and (p2:getNum() == p3:getNum())) )
then
table.insert(count_table, p1)
end
index = index + 1
end
return count_table
end
-- 获取飞机中的单张有几个
function PokerRule.GetDanZhangCountInFeiJi( pokerList , feijiList)
local tmpList = deepcopy(pokerList)
local count = 0;
for k, v in pairs(tmpList) do
for feiji_k, feiji_v in pairs(feijiList) do
local feiji_p1 = feiji_v
local p1 = v
if (p1 ~= nil and feiji_p1 ~= nil and (feiji_p1:getNum() == p1:getNum()) )
then
table.remove(tmpList, 1)
end
end
end
local len = table_leng(tmpList)
if (len > 0)
then
local index = 1
for k, v in pairs(tmpList) do
local p1 = tmpList[index]
local p2 = tmpList[index + 1]
if (p1 ~= nil and p2 ~= nil and (p1:getNum() ~= p2:getNum()) )
then
count = count + 1
end
end
end
return count
end
-- 获取 飞机中的对子 有几个
-- 把飞机头删掉,留下了的就是翅膀了,例如 KKK33QQQ44 , 飞机头就是 K ,Q, 返回值就是 33, 44 的个数,为2个
function PokerRule.GetDuiZiCountInFeiJi(pokerList, feijiList)
local tmpList = deepcopy(pokerList)
local count = 0;
for k, v in pairs(tmpList) do
for feiji_k, feiji_v in pairs(feijiList) do
local feiji_p1 = feiji_v
local p1 = v
if (p1 ~= nil and feiji_p1 ~= nil and (feiji_p1:getNum() == p1:getNum()) )
then
table.remove(tmpList, 1)
end
end
end
-- 剩下的都是 对子
local len = table_leng(tmpList)
if (len > 0 and len % 2 == 0 )
then
local index = 1
for k, v in pairs(tmpList) do
local p1 = tmpList[index]
local p2 = tmpList[index + 1]
if (p1 ~= nil and p2 ~= nil and (p1:getNum() == p2:getNum()) )
then
count = count + 1
end
end
end
return count
end
-- 判断是不是 双飞
function PokerRule.IsShuangFei(pokerList)
local tmp_table = PokerRule.GetFeiJiTouCount(pokerList)
if (tmp_table == nil)
then
return false
end
local len = table_leng(tmp_table)
if (len >= 2)
then
local index = 1
for k, v in pairs(tmp_table) do
local p1 = tmp_table[index]
local p2 = tmp_table[index + 1]
if ( p1 ~= nil and p2 ~= nil and (p1:getNum() - p2:getNum() ~= 1))
then
return false
end
index = index + 1
end
local dui_count = GetDuiZiCountInFeiJi(pokerList, tmp_table)
if (dui_count == 0)
then
return true
end
end
return false
end
-- 判断是不是飞机带翅膀 一般表现形式为: KKK34QQQ56 当然还有很多种
function PokerRule.IsFeiJiDaiChiBang2( pokerList )
local feiji_table = PokerRule.GetFeiJiTouCount(pokerList)
if (feiji_table == nil)
then
return false
end
local len = table_leng(feiji_table)
if (len >= 2)
then
local index = 1
for k, v in pairs(tmp_table) do
local p1 = tmp_table[index]
local p2 = tmp_table[index + 1]
if ( p1 ~= nil and p2 ~= nil and (p1:getNum() - p2:getNum() ~= 1))
then
return false
end
index = index + 1
end
local dui = GetDuiZiCountInFeiJi(pokerList, feiji_table)
local feiji_table_len = table_leng(feiji_table)
if (dui == feiji_table_len)
then
return true
end
end
return false
end
-- 判断是不是飞机带翅膀 一般表现形式为: KKK3QQQ4 当然还有很多种
function PokerRule.IsFeiJiDaiChiBang1( pokerList )
local feiji_table = PokerRule.GetFeiJiTouCount(pokerList)
if (feiji_table == nil)
then
return false
end
local len = table_leng(feiji_table)
if (len >= 2)
then
local index = 1
for k, v in pairs(tmp_table) do
local p1 = tmp_table[index]
local p2 = tmp_table[index + 1]
if ( p1 ~= nil and p2 ~= nil and (p1:getNum() - p2:getNum() ~= 1))
then
return false
end
index = index + 1
end
-- 获取单张
local danzhang_cnt = GetDanZhangCountInFeiJi(pokerList, feiji_table)
local feiji_table_len = table_leng(feiji_table)
if (danzhang_cnt == feiji_table_len)
then
return true
end
end
return false
end
-- 获取牌型
function PokerRule.GetPokerType( pokerList )
local tmpList = deepcopy(pokerList)
table.sort(tmpList, function(a,b) return a:getNum() < b:getNum() end)
local len = table_leng(tmpList)
if ( len == 1)
then
return PokerType.p_A
elseif ( len == 2)
then
if (PokerRule.IsHaveSame(tmpList, len))
then
return PokerType.p_AA
end
if (PokerRule.IsWangZha(tmpList))
then
return PokerType.p_KK
end
-- 不符合规则
return PokerType.p_can_not_put
elseif (len == 3)
then
-- 三张
if (PokerRule.IsHaveSame(tmpList, len))
then
return PokerType.p_AAA
end
-- 不符合规则
return PokerType.p_can_not_put
elseif (len == 4)
then
-- 炸弹
if (PokerRule.IsHaveSame(tmpList, len))
then
return PokerType.p_AAAA
end
-- 三带一
if (PokerRule.Is3DaiYi(tmpList))
then
return PokerType.p_AAAB
end
-- 不符合规则
return PokerType.p_can_not_put
elseif (len >= 5)
then
-- 顺子
if (PokerRule.IsShunZi(tmpList))
then
return PokerType.p_n
-- 三带一对
elseif (PokerRule.Is3DaiDui(tmpList))
then
return PokerType.p_AAABC
-- 连对
elseif (PokerRule.IsLianDui(tmpList))
then
return PokerType.p_AABB
-- 双飞 或者 双飞双带
elseif (PokerRule.IsShuangFei(tmpList))
then
return PokerType.p_AAABBB
-- 飞机带单牌
elseif (PokerRule.IsFeiJiDaiChiBang1(tmpList))
then
return PokerType.p_AAABBBCD
-- 飞机带对子
elseif (PokerRule.IsFeiJiDaiChiBang2(tmpList))
then
return PokerType.p_AAABBBCCDD
end
-- 不符合规则
return PokerType.p_can_not_put
end
end
-- 比较最后一张牌
-- @param prePokerList:上一个牌 currentPokerList:当前要出的牌
-- @return true:表示当前出的牌比上一个出的牌大
function PokerRule.CompareLast( prePokerList, currentPokerList )
local pre_len = table_leng(prePokerList)
local current_len = table_leng(currentPokerList)
-- 因为我们设置的num 是 num越小,牌越大
if (prePokerList[pre_len]:getNum() > currentPokerList[current_len]:getNum())
then
return true
end
return false
end
-- 获取飞机头
function PokerRule.GetFeiJiTou( pokerList )
local index = 1
for k, v in pairs(pokerList) do
local p1 = pokerList[index]
local p2 = pokerList[index + 1]
local p3 = pokerList[index + 2]
if (p1 ~= nil and p2 ~= nil and p3 ~= nil )
then
if (p1:getNum() == p2:getNum() and p2:getNum() == p3:getNum())
then
return p1:getNum()
end
end
end
return -1
end
--- 比较大小飞机头大小
function PokerRule.Compare( prePokerList, currentPokerList )
local pre_tou = PokerRule.GetFeiJiTou(prePokerList)
local current_tou = PokerRule.GetFeiJiTou(currentPokerList)
if (pre_tou == -1 or current_tou == -1)
then
return false
end
if (pre_tou > current_tou)
then
return true
end
return false
end
-- 比较大小
function PokerRule.IsBigger( prePokerList, currentPokerList )
-- 获取上一个出牌的牌型
local pre_poker_type = PokerRule.GetPokerType(prePokerList)
-- 获取当前出牌的牌型
local current_poker_type = PokerRule.GetPokerType(currentPokerList)
if (pre_poker_type == current_poker_type)
then
-- 单张
if (pre_poker_type == PokerType.p_A)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 王炸
elseif (pre_poker_type == PokerType.p_KK)
then
return false
-- 对子
elseif (pre_poker_type == PokerType.p_AA)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 三张
elseif (pre_poker_type == PokerType.p_AAA)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 三带一
elseif (pre_poker_type == PokerType.p_AAAB)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 三带二
elseif (pre_poker_type == PokerType.p_AAABC)
then
if (PokerRule.Compare(prePokerList, currentPokerList))
then
return true
end
return false
-- 炸弹
elseif (pre_poker_type == PokerType.p_AAAA)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 顺子
elseif (pre_poker_type == PokerType.p_n)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 连对
elseif (pre_poker_type == PokerType.p_AABB)
then
if (PokerRule.CompareLast(prePokerList, currentPokerList))
then
return true
end
return false
-- 双飞
elseif (pre_poker_type == PokerType.p_AAABBB)
then
if (PokerRule.Compare(prePokerList, currentPokerList))
then
return true
end
return false
-- 飞机带一
elseif (pre_poker_type == PokerType.p_AAABBBCD)
then
if (PokerRule.Compare(prePokerList, currentPokerList))
then
return true
end
return false
-- 飞机带二
elseif (pre_poker_type == PokerType.p_AAABBBCCDD)
then
if (PokerRule.Compare(prePokerList, currentPokerList))
then
return true
end
return false
end
-- 如果牌型不相同
elseif (current_poker_type == PokerType.p_KK)
then
-- 判断当前出的牌是不是王炸
if (PokerRule.IsWangZha(currentPokerList))
then
return true
end
return false
elseif (current_poker_type == PokerType.p_AAAA)
then
--- 判断当前出的牌是不是炸弹
if (PokerRule.IsHaveSame(currentPokerList, 4))
then
return true
end
return false
end
return false
end
ps 注意事项
上面写的代码,需要优化几个地方:
- 重复的代码比较多,需要优化一下。
- 还有我们的 PokerType.num 是从小到大,而牌的大小是从大到小,这样看起来比较难看,需要调整成一致的。
- 最好写一个单元测试样例来测试这些规则