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


aihuafeng66t
克里斯蒂亚诺诺 2024-01-11 18:31:51 62865 赞同 0 反对 0
分类: 资源 标签: 运维
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 条
克里斯蒂亚诺诺L1
粉丝 0 资源 831 + 关注 私信
最近热门资源
银河麒麟桌面操作系统V10SP1-2403-update1版本中,通过“麒麟管家-设备管理-硬件信息-硬盘”查看硬盘类型时,显示的是HDD(机械硬盘),而实际上该笔记本的硬盘类型为SSD  81
以openkylin为例编译安装内核  76
分享解决宏碁电脑关机时自动重启的方法  73
统信uosboot区分未挂载导致更新备份失败  63
分享如何解决报错:归档 xxx.deb 对成员 control.tar.zst 使用了未知的压缩,放弃操作  63
统信uos安装mysql的实例参考  60
格之格打印机dp3300系列国产系统uos打印机驱动选择  57
在银河麒麟高级服务器操作系统V10SP3中,需要将默认shell类型修改为csh。  51
MySQL国产平替最佳选择---万里数据库(GreatDB)  45
最近下载排行榜
银河麒麟桌面操作系统V10SP1-2403-update1版本中,通过“麒麟管家-设备管理-硬件信息-硬盘”查看硬盘类型时,显示的是HDD(机械硬盘),而实际上该笔记本的硬盘类型为SSD 0
以openkylin为例编译安装内核 0
分享解决宏碁电脑关机时自动重启的方法 0
统信uosboot区分未挂载导致更新备份失败 0
分享如何解决报错:归档 xxx.deb 对成员 control.tar.zst 使用了未知的压缩,放弃操作 0
统信uos安装mysql的实例参考 0
格之格打印机dp3300系列国产系统uos打印机驱动选择 0
在银河麒麟高级服务器操作系统V10SP3中,需要将默认shell类型修改为csh。 0
MySQL国产平替最佳选择---万里数据库(GreatDB) 0
作者收入月榜
1

prtyaa 收益400.83元

2

zlj141319 收益237.91元

3

哆啦漫漫喵 收益231.52元

4

IT-feng 收益219.92元

5

1843880570 收益214.2元

6

风晓 收益208.24元

7

777 收益173.17元

8

Fhawking 收益106.6元

9

信创来了 收益106.03元

10

克里斯蒂亚诺诺 收益91.08元

请使用微信扫码

添加我为好友,拉您入交流群!

请使用微信扫一扫!