组队逻辑(使用GenServer)

今天记录一下自己构建出来的,使用GenServer调控多个线程,用于实现4人组队的相关逻辑代码.

defmodule PartyAttackController1 do
 use GenServer

 def start_link(), do: GenServer.start_link(__MODULE__, [], name: __MODULE__)

 def get_target(uuid) do
   GenServer.call PartyAttackController1, {:get_target, uuid}
 end

 def set_target({uuid, serial}) do
   GenServer.cast PartyAttackController1, {:set_target, {uuid, serial}}
 end

 def leave_member(name) do
   GenServer.cast PartyAttackController1, {:leave_member, name}
 end

 def get_all_member_enter_state(uuid) do
   GenServer.call PartyAttackController1, {:get_all_member_enter_state, uuid}
 end

 def set_dragon_member({uuid, server_id}) do
   GenServer.cast PartyAttackController1, {:dragon_member_register, {uuid, server_id}}
 end

 def get_member_identity({uuid, server_id}) do
   GenServer.call PartyAttackController1, {:get_member_identity, {uuid, server_id}}
 end

 def relieve_acc({uuid, server_id, identity}) do
   GenServer.cast PartyAttackController1, {:relieve_acc, {uuid, server_id, identity}}
 end

 def get_invite_members({uuid, server_id}) do
   GenServer.call PartyAttackController1, {:get_invite_members, {uuid, server_id}}
 end

 def check_state() do
   GenServer.call PartyAttackController1, :check_state
 end

 def allot(members, acc) when length(members) < 4 do
   Map.put acc, :members, members
 end

 def allot(members = [uuid, uuid1, uuid2, uuid3 | tail], acc) do
   master_members = (acc[:master_members] || []) ++ [uuid]
   member_members = (acc[:member_members] || []) ++ [uuid1, uuid2, uuid3]
   allot_members = (acc[:allot_members] || %{}) |> Map.merge(%{uuid => %{members: [uuid1, uuid2, uuid3]}})
   sum_members = (acc[:sum_members] || %{}) |> Map.merge(%{uuid => %{master: uuid}, uuid1 => %{master: uuid}, uuid2 => %{master: uuid}, uuid3 => %{master: uuid}})
   acc = %{
     master_members: master_members,
     member_members: member_members,
     allot_members: allot_members,
     sum_members: sum_members
   }
   allot(tail, acc)
 end

 def init(state) do
   {:ok, %{}}
 end

 def handle_call(:check_state, _from, state) do
   {:reply, state, state}
 end

 def handle_call({:get_invite_members, {uuid, server_id}}, _from, state) do
   members = state[:fight_members][:allot][uuid][:members]
   {:reply, members, state}
 end

 def handle_cast({:relieve_acc, {uuid, server_id, identity}}, state) do
   local_master_members = state[:master_members][server_id] || []
   local_member_members = state[:member_members][server_id] || []
   fight_members = state[:fight_members] || %{}
   state = case identity do
     :master ->
       local_master_members = local_master_members -- [uuid]
       state = put_in(state, [:master_members, server_id], local_master_members)

       mem_uuids = (fight_members[:allot][uuid][:members] || [])

       fight_members = put_in(fight_members, [:sum], Map.drop(fight_members[:sum], ([uuid] ++ mem_uuids))) |> put_in([:allot], Map.delete(fight_members[:allot], uuid))
       local_member_members = local_member_members -- mem_uuids
       state = put_in(state, [:member_members, server_id], local_member_members)
       state = put_in(state, [:fight_members], fight_members)
     :member ->
       local_member_members = local_member_members -- [uuid]
       state = put_in(state, [:member_members, server_id], local_member_members)
       fight_members = put_in(fight_members, [:sum], Map.drop(fight_members[:sum], [uuid]))
       state = put_in(state, [:fight_members], fight_members)
     _ ->
       state
   end
   {:noreply, state}
 end

 def handle_call({:get_member_identity, {uuid, server_id}}, _from, state) do
   local_master_members = state[:master_members][server_id] || []
   local_member_members = state[:member_members][server_id] || []

   {identity, state} = cond do
     !state[:fight_members][:sum][uuid] ->
       {:unknow, state}

     uuid in local_master_members ->
       mem = state[:fight_members][:sum][uuid] |> Map.merge(%{fight: true})

       state = put_in(state, [:fight_members, :sum, uuid], mem)
       {:master, state}

     uuid in local_member_members ->
       mem = state[:fight_members][:sum][uuid] |> Map.merge(%{fight: true})

       state = put_in(state, [:fight_members, :sum, uuid], mem)
       {:member, state}

     true ->
       {:unknow, state}

   end

   {:reply, identity, state}
 end

 def handle_cast({:dragon_member_register, {uuid, server_id}}, state) do
   members = state[:members] || %{}

   doing_fight_members = state[:fight_members][:sum] || %{} 
   allot_members = state[:fight_members][:allot] || %{}
   sum_members = state[:fight_members][:sum] || %{}

   local_members = members[server_id] || []
   local_master_members = state[:master_members][server_id] || []
   local_member_members = state[:member_members][server_id] || []

   # already allot
   flag = uuid in local_members || uuid in Map.keys(doing_fight_members) || uuid in local_master_members || uuid in local_member_members

   state = cond do
     flag ->
       state

     true ->
       local_members = :lists.append(local_members, [uuid])
       acc = %{
         master_members: local_master_members,
         member_members: local_member_members,
         allot_members: allot_members,
         sum_members: sum_members
       }     
       acc = allot(local_members, acc)

       local_master_members = acc[:master_members] || []
       local_member_members = acc[:member_members] || []
       local_members = acc[:members] || []
       allot_members = acc[:allot_members] || %{}
       sum_members = acc[:sum_members] || %{}

       members = put_in(members, [server_id], local_members)
       master_members = put_in((state[:master_members] || %{}), [server_id], local_master_members)
       member_members = put_in((state[:member_members] || %{}), [server_id], local_member_members)
       fight_members = put_in((state[:fight_members] || %{}), [:allot], allot_members)
       fight_members = put_in(fight_members, [:sum], sum_members)

       state = Map.merge(state, %{master_members: master_members, member_members: member_members, members: members, fight_members: fight_members})

   end
   {:noreply, state}
 end

 def handle_call({:get_target,uuid}, _from, state) do
   master = state[:fight_members][:sum][uuid][:master]
   target = state[:fight_members][:allot][master][:target]
   {:reply, target, state}
 end

 def handle_cast({:set_target, {uuid,serial}}, state) do
   master = state[:fight_members][:sum][uuid][:master]
   mas = state[:fight_members][:allot][master] |> Map.merge(%{target: serial})
   state = put_in(state, [:fight_members, :allot, master], mas) 
   {:noreply, state}
 end

 def handle_cast({:leave_member, name}, state) do
   enter_members = (state[:enter_members] || []) |> List.delete(name)
   state = Map.merge state, %{enter_members: enter_members}
   {:noreply, state}
 end
end

整个代码搭建的数据结构是下面这样

   #    %{
   #      members: %{server_id: [member1, member2, member3 ...]},
   #      master_members: %{server_id: [master_member1, master_member2 ...]},
   #      member_members: %{server_id: [member_member1, member_member2 ...]},
   #      fight_members: %{
   #        allot: %{uuid => %{members: [uuid1, ...], target: serial}},
   #        sum: %{uuid_mem => %{fight: true, master: uuid_mas}} 
   #      }
   #    }

主要的组队逻辑就是当线程执行的时候,调用register_把成员的uuid注册到GenServer中的state,根据人物的server_id,把成员uuid添加到相应server_id下,

每当此server_id中的成员数大于等于4的时候都会进行成员身份分配,

排在第一位的成员是队长,进而根据server_id被存储到master_members中, 而后面的3个uuid都根据server_id被相继储存到member_members中,(用于往后的get_identity获取成员身份做准备)

确定的一组成员以队长的uuid作为key值把数据储存到fight_member中的allot,(用于往后的队长邀请队员做准备)

而每个成员都会以

%{
mem_uuid => %{master: mas_uuid}
}

的数据形式储存在fight_members中的sum中(用于往后确定成员应该共同攻击的monster),相应的逻辑是每个过来找怪物id的进程都是先找到自己的队长,然后在allot -> server_id -> mas_uuid -> target_id

紧接着下面就是复杂的解除账号的逻辑,如果是master账号,就从allot中找到其成员uuid,删除其allot中的数据,也把fight_members中的每个成员的数据以及master_members和member_members中的相关成员的数据都删除,

如果是队员的uuid,就只是把fight_members和member_members中相关成员数据删除.

什么!你说allot中还留有残余的队员的垃圾数据?好吧,这个就是此算法逻辑的bug吧,不过队员和队长是同时离开副本的所以基本上都是队长在干清理数据的活,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C墨羽

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值