【算法】跑得快AI

54 篇文章 0 订阅

代码不全,但是函数可以复用

--
-- Author: baiyufei
-- Date: 2022-07-13 
-- 跑得快AI
--
local commonfunc = require('lua.base.commonfunc')
require('lua.game.AI.dz')
require('lua.base.bit')

local Poker  = require('lua.game.paodekuai.poker')

local aipaodekuai = class("aipaodekuai")

local TIME_SPACE = 1
local OVER_TIME = 10
local TUO_GUANG_TIMES = 2  --超时进入托管次数

function aipaodekuai:ctor(Table)
    self.gameId = Table.mAction:getId()
	self.base_gameId = GET_BASE_GAMEID(self.gameId)
	self.Table = Table
	self.upTime = os.time() + 5
	self.stateTime = 0
    self.lastPlayer = 0
end

function aipaodekuai:run()
    local tmNow = os.time()
    if(tmNow < self.upTime)then
        return
    end
	local Table = self.Table
	local playerOperator = Table:getOperator()
	if(playerOperator and playerOperator:getRobot())then
		TIME_SPACE = math.random(1,2)
	else
		TIME_SPACE = 1
	end
    self.upTime = tmNow + TIME_SPACE
    --根据桌子的状态,判断机器人行为
    local state = self.Table.mState:getState().state
   
    print("-------j机器人----------- androidServiceMgr:run() --------- %, %, %, %", self.gameId, state, self.lastPlayer, self.stateTime)

    --如果卡住了,就强制结束吧

    if(Table.START <= state and playerOperator ~= nil)then
        if(self.lastPlayer == playerOperator:getId())then
            self.stateTime = self.stateTime + TIME_SPACE
        else
            self.stateTime = 0
            self.lastPlayer = playerOperator:getId()
        end
        if(60 <= self.stateTime)then
            --return Table:onFin()
        end
    end

    --准备阶段
    if(state == Table.START)then
        self:ready()
        return
    end
	
	if(not playerOperator or not self:checkAuto(playerOperator))then
		return
	end

	--托管时间随机延迟
	if not playerOperator:getRobot() and playerOperator:getTuoGuan() and self.stateTime < math.random(1,2) then
		return
	end

	--玩家打牌阶段
	if(state == Table.OPERATION)then
		self:OnOPERATION(playerOperator)
		return
	end

end

--托管超时判断
function aipaodekuai:playerOutTime(player)
    local Table = self.Table
    LOGD("player out times-----------------------------table[%] [%] [%] [%] [%]", Table:getOnlyIdStr(), player:getId(), player:getRobot(),  player:getTuoGuan(), self.stateTime)
    if not player:getRobot() and player:getTuoGuan() ~= true then
        if OVER_TIME <= self.stateTime then
            if(not player.tickOutTimes)then
				player.tickOutTimes = 1
			else
				player.tickOutTimes = player.tickOutTimes + 1
				if(TUO_GUANG_TIMES <= player.tickOutTimes)then
					self.Table:onChangeTuoGuanState(player:getSession(), {tuoGuan=true})
					player.tickOutTimes = 0
				end
			end
			LOGD("player out times-----------------------------table[%] [%] [%]", Table:getOnlyIdStr(), player:getId(), player.tickOutTimes)
			return true
        end
    end
	return false
end

function aipaodekuai:checkAuto(player)
	print("-------机器人直接代打-----aipaodekuai:checkAuto(player)-----%  % --------------",player:getSession(), player:getRobot())
	--机器人直接代打
	if(player:getRobot())then
		return true
	else
		if(player:getTuoGuan() == true or self:playerOutTime(player))then
			return true
		end
	end	
	return false
end

--统计相同牌
function aipaodekuai:AnalysebCardData(cbCardData, AnalyseResult)
    local cbCardCount = #cbCardData
    local cbTempCardData = commonfunc.deepcopy2(cbCardData)
	--扑克分析
	for i=1, cbCardCount do
		local cbLogicValue = ddzGetCardValue(cbTempCardData[i])
		if(AnalyseResult[cbLogicValue] == nil)then
			AnalyseResult[cbLogicValue] = {}
		end
		table.insert(AnalyseResult[cbLogicValue], cbTempCardData[i])
	end
	print("--------------统计相同牌-----% % ------------", cbCardData, AnalyseResult)
end

--先手
function aipaodekuai:before(player, oPtion)
	--强调:炸弹永远不会成为第一手出牌选择,任何情况下,不拆除炸弹,只作为炸弹出牌
	print("主动出牌~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	local handCards = player:getCards()
	oPtion.op = Poker.OpOut
	oPtion.card = {handCards[#handCards]}

    local table = self.Table
	local cbHandCardData = commonfunc.deepcopy2(handCards)
	--若只有一手牌全出
	local cardType = table.mPoker:getCardsType(cbHandCardData)
	if cardType ~= Poker.ErrorType then
		oPtion.card = commonfunc.deepcopy2(cbHandCardData)
		return
	end

	local AnalyseResult = {}
	self:AnalysebCardData(cbHandCardData, AnalyseResult)

	--想出的牌,出牌后手数
	local outCards, minHands = {}, 100

	--如果没有单牌,或者单牌很大,打对子
	local minSingle ,minDouble = 100, 100
	for i = 3, 14 do
		local tmpOutCards = {}
		if  minDouble == 100 and AnalyseResult[i] and 2 == #AnalyseResult[i] then
			minDouble = AnalyseResult[i][1]
			tmpOutCards = AnalyseResult[i]
			local hands = self:getHands(handCards, tmpOutCards)
			if(hands < minHands)then
				minHands = hands
				outCards = tmpOutCards
				logd("---minDouble---outCards----%, %",minHands, outCards)
			end
		end
		if minSingle == 100 and AnalyseResult[i] and 1 == #AnalyseResult[i] then
			minSingle = AnalyseResult[i][1]
			tmpOutCards = AnalyseResult[i]
			local hands = self:getHands(handCards, tmpOutCards)
			if(hands <= minHands and minSingle < minDouble)then
				minHands = hands
				outCards = tmpOutCards
				logd("----minSingle--outCards----%, %",minHands, outCards)
			end
		end
	end		

	--iii.第三步:在不具明面统治牌权情况下,判断出牌一次性,一次能出最多张数的牌型
	--是否有顺子
	local first = 0 -- 顺子第一个位置
	local last = 0  -- 顺子最长位置
	for i = 3, 14 do
		if AnalyseResult[i] then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0  and 4 <= last - first then
				local tmpOutCards = {}
				for j = first, last  do
					--顺子最后一张是对子,不拆
					if(j == last and 2 <= #AnalyseResult[j] and 5 <= #tmpOutCards)then
						break
					end
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
				end
				local hands = self:getHands(handCards, tmpOutCards)
				if(hands <= minHands and #outCards < #tmpOutCards)then
					minHands = hands
					outCards = tmpOutCards
					logd("----顺子--outCards----%, %",minHands, outCards)
				end
				break
			end
			first = 0
			last = 0
		end
	end
	
	first = 0 
 	last = 0
	--是否有连队
	for i = 3, 14 do
		--不拆炸弹
		if AnalyseResult[i] and 2<= #AnalyseResult[i] and #AnalyseResult[i] <= 3 then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0  and 1 <= last - first then
				local tmpOutCards = {}
				for j = first, last  do
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][2]
				end
				local hands = self:getHands(handCards, tmpOutCards)
				if(hands <= minHands and #outCards < #tmpOutCards)then
					minHands = hands
					outCards = tmpOutCards
					logd("----连队--outCards----%, %",minHands, outCards)
				end
				break
			end
			first = 0
			last = 0
		end		
	end
	
	first = 0 
	last = 0
	--是否有飞机,是否有三代2
	for i = 3, 14 do
		--不拆炸弹
		if AnalyseResult[i] and #AnalyseResult[i] == 3 then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0 then
				local tmpOutCards = {}
				for j = first, last  do
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][2]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][3]
				end
				local adds = {}
				local bAdd = self:getAdds(handCards, AnalyseResult, adds, last - first + 1)
				if(bAdd and adds)then
					commonfunc.copyAdd(tmpOutCards, adds)
					local hands = self:getHands(handCards, tmpOutCards)
					if(hands <= minHands and #outCards < #tmpOutCards)then
						minHands = hands
						outCards = tmpOutCards
						logd("----飞机--outCards----%, %",minHands, outCards)
					end
				end
				break	
			end
			first = 0
			last = 0
		end		
	end

	if(#outCards == 1)then
		--下家只有一张牌时,只能出最大的单排
		local opInfo = { uid = player:getId(), op = Poker.OpOut, opCards = oPtion.card }
		if table.show:checkIsNeedOutMaxValueCardAllCard(player,opInfo) then
			oPtion.card = {handCards[1]}
			return
		end
	end

	if(0 < #outCards)then
		oPtion.card = outCards
	end

	logd("-------------outCards--oPtion--------%, %", outCards, oPtion)
end

--计算手
function aipaodekuai:getHands(handCards, outCards)
	local cbHandCardData = commonfunc.deepcopy2(handCards)
	--先把要出的牌剔除
	for _, card in pairs(outCards) do
		for k, v in pairs(cbHandCardData) do
			if(card == v)then
				table.remove(cbHandCardData, k)
				break
			end
		end
	end

	--顺子也剔除
	local AnalyseResult = {}
	self:AnalysebCardData(cbHandCardData, AnalyseResult)
	local first = 0 -- 顺子第一个位置
	local last = 0  -- 顺子最长位置
	local tmpOutCards = {}
	for i = 3, 14 do
		if AnalyseResult[i] then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0  and 4 <= last - first then
				for j = first, last  do
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
				end
				break
			end
			first = 0
			last = 0
		end
	end
	for _, card in pairs(tmpOutCards) do
		for k, v in pairs(cbHandCardData) do
			if(card == v)then
				table.remove(cbHandCardData, k)
				break
			end
		end
	end

	AnalyseResult = {}
	self:AnalysebCardData(cbHandCardData, AnalyseResult)
	local hand = 0
	for k, v in pairs(AnalyseResult) do
		if(#v < 3)then
			hand = hand + 1
		end
	end
	return hand
end


--获得飞机的翅膀, 只能带2个单牌
function aipaodekuai:getAdds(handCards, AnalyseResult, cardsLlist, count)
	logd("----------------%,%,%,%",handCards, AnalyseResult, cardsLlist, count)
	--要获得多张单牌
	local singleList = {}
	for i = 3, 14 do
		if(AnalyseResult[i] and 1 == #AnalyseResult[i] and AnalyseResult[i][1])then
			table.insert(cardsLlist, AnalyseResult[i][1])
			if(count*2 <= #cardsLlist)then
				return true
			end
		end
	end
	logd("-----------cardsLlist----------%", cardsLlist)
	return false
end

--后手
function aipaodekuai:after(player, Table, oPtion, canOutCards)
	oPtion.op = Poker.OpOut 
	oPtion.card = canOutCards[1]
	--下家只有一张牌时,只能出最大的单排
	local opInfo = { uid = player:getId(), op = Poker.OpOut, opCards = oPtion.card }
	local handCards = player:getCards()
	if Table.show:checkIsNeedOutMaxValueCardAllCard(player,opInfo) then
		oPtion.op = Poker.OpOut 
		oPtion.card = {handCards[1]}
		return
	end

	--找一个出牌后手数最少的
	local index, minhand, count = 1, 100, 1
	for k, v in pairs(canOutCards) do
		local hand = aipaodekuai:getHands(handCards, v)
		if(hand < minhand)then
			minhand = hand
			count = #v
			index = k
		elseif(hand == minhand and count < #v)then	
			minhand = hand
			count = #v
			index = k
		end
	end

	--[[
	炸弹必炸	
	--单牌太多炸弹不拆
	local cardType = Table.mPoker:getCardsType(canOutCards[index])
	if cardType == Poker.ZhaDan then
		local hand = aipaodekuai:getHands(handCards, canOutCards[index])
		if(aipaodekuai:getHands(handCards, {}) + 2 <= hand)then
			oPtion.op = Poker.OpGiveUp 
			return
		end
	end
	]]
	oPtion.card = canOutCards[index]
	logd("-------oPtion---------%", oPtion)
end

--是否有方块3
function aipaodekuai:hasFangkuai3(cards)
	for k, card in pairs(cards) do
		if(card == 63)then
			return true
		end
	end
	return false
end

--第一次出牌
function aipaodekuai:onFirst(player, oPtion)
	--强调:炸弹永远不会成为第一手出牌选择,任何情况下,不拆除炸弹,只作为炸弹出牌
	print("主动出牌~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
	local handCards = player:getCards()
    local table = self.Table
	local cbHandCardData = commonfunc.deepcopy2(handCards)
	--若只有一手牌全出
	local cardType = table.mPoker:getCardsType(cbHandCardData)
	if cardType ~= Poker.ErrorType then
		oPtion.card = commonfunc.deepcopy2(cbHandCardData)
		return
	end

	local AnalyseResult = {}
	self:AnalysebCardData(cbHandCardData, AnalyseResult)

	--想出的牌,出牌后手数
	local outCards, minHands = {}, 100

	--如果没有单牌,或者单牌很大,打对子
	local minSingle ,minDouble = 100, 100
	for i = 3, 14 do
		if(not AnalyseResult[3] or not self:hasFangkuai3(AnalyseResult[3]))then
			break
		end
		local tmpOutCards = {}
		if  minDouble == 100 and AnalyseResult[i] and 2 == #AnalyseResult[i] then
			minDouble = AnalyseResult[i][1]
			tmpOutCards = AnalyseResult[i]
			local hands = self:getHands(handCards, tmpOutCards)
			if(hands < minHands and self:hasFangkuai3(tmpOutCards))then
				minHands = hands
				outCards = tmpOutCards
				logd("---minDouble---outCards----%, %",minHands, outCards)
			end
		end
		if minSingle == 100 and AnalyseResult[i] and 1 == #AnalyseResult[i] then
			minSingle = AnalyseResult[i][1]
			tmpOutCards = AnalyseResult[i]
			local hands = self:getHands(handCards, tmpOutCards)
			if(hands <= minHands and minSingle < minDouble and self:hasFangkuai3(tmpOutCards))then
				minHands = hands
				outCards = tmpOutCards
				logd("----minSingle--outCards----%, %",minHands, outCards)
			end
		end
	end		

	--iii.第三步:在不具明面统治牌权情况下,判断出牌一次性,一次能出最多张数的牌型
	--是否有顺子
	local first = 0 -- 顺子第一个位置
	local last = 0  -- 顺子最长位置
	for i = 3, 14 do
		if(not AnalyseResult[3] or not self:hasFangkuai3(AnalyseResult[3]))then
			break
		end
		if AnalyseResult[i] then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0  and 4 <= last - first then
				local tmpOutCards = {}
				for j = first, last  do
					--顺子最后一张是对子,不拆
					if(j == last and 2 <= #AnalyseResult[j] and 5 <= #tmpOutCards)then
						break
					end
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
				end
				local hands = self:getHands(handCards, tmpOutCards)
				if(hands <= minHands and self:hasFangkuai3(tmpOutCards))then
					minHands = hands
					outCards = tmpOutCards
					logd("----顺子--outCards----%, %",minHands, outCards)
				end
				break
			end
			first = 0
			last = 0
		end
	end
	
	first = 0 
 	last = 0
	--是否有连队
	for i = 3, 14 do
		if(not AnalyseResult[3] or not self:hasFangkuai3(AnalyseResult[3]))then
			break
		end
		--不拆炸弹
		if AnalyseResult[i] and 2<= #AnalyseResult[i] and #AnalyseResult[i] <= 3 then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0  and 1 <= last - first then
				local tmpOutCards = {}
				for j = first, last  do
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][2]
				end
				local hands = self:getHands(handCards, tmpOutCards)
				if(hands < minHands and self:hasFangkuai3(tmpOutCards))then
					minHands = hands
					outCards = tmpOutCards
					logd("----连队--outCards----%, %",minHands, outCards)
				end
				break
			end
			first = 0
			last = 0
		end		
	end

	first = 0 
	last = 0
	--是否有飞机, 是否有三代2
	for i = 3, 14 do
		if(not AnalyseResult[3] or not self:hasFangkuai3(AnalyseResult[3]))then
			break
		end
		--不拆炸弹
		if AnalyseResult[i] and #AnalyseResult[i] == 3 then
			if first == 0 then 
				first = i 
			end
			last = i	
		else
			if first > 0 then
				local tmpOutCards = {}
				for j = first, last  do
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][1]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][2]
					tmpOutCards[#tmpOutCards+1] = AnalyseResult[j][3]
				end
				local adds = {}
				local bAdd = self:getAdds(handCards, AnalyseResult, adds, last - first + 1)
				if(bAdd and adds)then
					commonfunc.copyAdd(tmpOutCards, adds)
					local hands = self:getHands(handCards, tmpOutCards)
					if(hands < minHands and self:hasFangkuai3(tmpOutCards))then
						minHands = hands
						outCards = tmpOutCards
						logd("----飞机--outCards----%, %",minHands, outCards)
					end
				end
				break	
			end
			first = 0
			last = 0
		end		
	end

	if(0 < #outCards)then
		oPtion.card = outCards
	end
end

--出牌
function aipaodekuai:OnOPERATION(player)

	local wMeChairID = player:getSeatId()
	local Table = self.Table
	--是否首次出牌
	local op = player.allowedOp.op
	print("AAAAAA getCircleCount=%  getCurrentSubCircleId=% op=%",Table.show:getCircleCount(),Table.show:getCurrentSubCircleId(),op)
	local oPtion = {op=op,card={}}
	if Table.show:getCurrentSubCircleId() == 1 and Table.show:getCircleCount() == 1 and  Table:getBanker():getId() == player:getId() then
		print("首次出牌```````````````````````````````````````````````")
		oPtion =  {op = op, card = {63}}
		self:onFirst(player, oPtion)
	else
		if btBit.AND(Poker.OpOut, op) ~= 0 then
			print("非首次出牌··········································")
			local circle = Table.show:getLastCircle()
			local canOutCards = player:getLargerWeightCardList2(circle.lastOutCards, circle.lastOutCardsType)
			print("canOutCards=============== %",canOutCards)
			if canOutCards[1] and circle.lastOutCardsType ~= Poker.ErrorType then
				self:after(player, Table, oPtion, canOutCards)
			else
				self:before(player, oPtion)
			end
		end
	end
	
	local bReslt = Table:onOperation(player:getSession(), oPtion, true)
    --LOGI("do auto card player[%] handcards[%] op[%] sub[%]", player:getId(), player:getCards(), player:getAllowedOp(), player:getSubmitOp())
    if(bReslt and 0 < bReslt)then
        LOGE("gameId=% oPtion=% ERROR,[%]", self.gameId, oPtion, debug.traceback())
        --player:clearAllowedOp()
        --Table:setOperator(Table:findNext(player))
        --Table.mState:change(Table.TURN)
        for _, p in pairs(self.Table:getPlayers()) do
            LOGE("EEEEEEEEEEEEEEEEEEEE  player[%] op[%] sub[%]", p:getId(), p.allowedOp, p.submitOp)
		end
	end
end

--自动准备
function aipaodekuai:ready()
    local Table = self.Table
    for _, player in pairs(Table:getPlayers()) do
        --不处理玩家操作
        if(player:getRobot() and not player:getReady() or OVER_TIME <= self.stateTime)then
            Table:UpdateDataOnTable(player:getSession(),"GoldCount",player:getGoldCount())
            Table:onReady(player:getSession())
            player:setTuoGuan(false)
            if(Table:isAllReady() == true)then
                Table.mState:change(Table.DEAL)
                break
            end
        end
    end
end

return aipaodekuai

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值