unity3d + lua + 斗地主 系列 (2) 创建扑克规则

mvc框架

我们把我们的项目改造成mvc的机构,上一篇文章
创建的那两个基本模型,我们放入了Model文件夹里面,记得修改require 时的路径哦。
这篇文章我们来一起实现 扑克的一些规则,主要是斗地主的规则,这个是比较通用的,所以我们放入了工具文件夹 Utils里面。
目录结构

  • PokerRule: 斗地主的一些规则
  • PokerType: 斗地主的出牌类型

PokerType.lua

PokerType = {}

PokerType.p_A = 0  ---单张
PokerType.p_AA = 1  ---对子
PokerType.p_KK = 2  ---王炸
PokerType.p_AAA = 3  ---三 不带
PokerType.p_AAAA = 4  --- 炸弹
PokerType.p_n = 5   ---顺子
PokerType.p_AAAB = 6  ---三带一
PokerType.p_AAABC = 7  --- 三带二
PokerType.p_AABB = 8   --- 连对
PokerType.p_AAABBB = 9 --- 飞机
PokerType.p_AAABBBCD  = 10 ---飞机带单牌
PokerType.p_AAABBBCCDD = 11 ---飞机带对子
--- 四带二 ? 有的地方没有这个牌型, 需要的可以自行添加
PokerType.p_can_not_put = 12      ---不能出牌


---- 扑克牌编码
-- 大小王
PokerType.BigKing = 17
PokerType.SmallKing = 18

---斗地主玩法,我们可以按照从大到小 排序, 方便我们判断 顺子等牌型
PokerType.Poker_2 =		19    --- 2
PokerType.Poker_A =		20
PokerType.Poker_K =		21
PokerType.Poker_Q =		22
PokerType.Poker_J =		23
PokerType.Poker_10 =	24
PokerType.Poker_9 =		25
PokerType.Poker_8 =		26
PokerType.Poker_7 =		27
PokerType.Poker_6 =		28
PokerType.Poker_5 =		29
PokerType.Poker_4 =		30
PokerType.Poker_3 =		31

-- 广告牌? ,没玩过带广告牌的斗地主,我们可以不需要
PokerType.Poker_AD =		32


return PokerType

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 注意事项

上面写的代码,需要优化几个地方:

  1. 重复的代码比较多,需要优化一下。
  2. 还有我们的 PokerType.num 是从小到大,而牌的大小是从大到小,这样看起来比较难看,需要调整成一致的。
  3. 最好写一个单元测试样例来测试这些规则
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tui_GuiGe

鼓励一下作者吧,请他喝一瓶啤酒

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值