房间匹配机制--自走旗

       从去年年底开始,dota自走旗火了。国产手游厂商纷纷效仿,都想在手游上分一杯羹。我们自然也不例外,只可惜曾经还不错的数据已经快要被梦塔防、龙渊代理的快冲击完了,其实主要还是自己作死了一波。作为程序,还是把其中一些机制总结一下。

       房间匹配机制:目前的匹配机制是,按照房间匹配,也就是说,当玩家自由匹配的时候,会查找仍然有空位的房间,将玩家放进去,但是目前侠客的匹配机制有一点有待优化,如果玩家首先点击自有匹配,此时服务器上没有空余房间,将为玩家创建一个房间,这个房间只有该玩家一个人。此时另一个之前创建好的房间点击开始匹配,并不会将这两个房间的玩家合并到一个房间。虽然对于玩家这样的操作是不可见的,但是对于服务器程序来说,心里还是有个梗的。

        解决方法:在匹配检测的地方,增加一个匹配预处理的函数,该函数的主要功能就是将玩家聚拢。

        实现方法:开辟一个数组,数组每个元素是一个set。遍历两次所有玩家房间的集合,第一次将所有玩家房间按照人数放进我们开辟的数组当中,这样得到的就是:vector<set<uint>>  vector的下标就是对应玩家数量,set集合中就是这些玩家数量的房间的集合,如下图。第二步,处理这个数组。

①两个位置标量,一个从数组头开始,一个从数组尾开始。

②两个标量的房间人数相加,大于最大房间人数,最大标量减一。等于最大房间人数,合并。小于最大房间人数,合并,然后最大房间人数减去合并完的房间人数,再去找剩余人数的下标的集合是否有房间,有的话,刚好合并完这三个房间就是房间最大人数。此处存在一个优化点,最大房间人数减去合并完的房间人数,应该扫描多次。因为如果极端情况,房间人数全是1。

③合并房间人数,删除,插入。

处理代码:

        因为代码是在内网,外网就将该模块抽出来,写了个简单例子,可以正常运行,但是没有大量测试,还是主要看思路吧。

#ifndef _MATCH_H_
#define _MATCH_H_

#include <map>
#include <set>
#include <list>
#include <time.h>
#include <vector>
#include <iostream>
using namespace std;
#define MAX_ROOM_NUM 3
#define uint unsigned int

enum ROOM_TYPE
{
	ROOM_PUBLIC = 1,
	ROOM_PRIVATE = 2,
};

class CTime
{
public:
	static CTime &getMe()
	{
		if (NULL == instance)
		{
			instance = new CTime();
			if (NULL == instance)
				exit(1);
		}
		return *instance;
	}
	uint getNowTime()
	{
		time_t tmp;
		time(&tmp);
		return (uint)tmp;
	}
	uint getThisId()
	{
		uint uiNowSec = getNowTime();
		if (uiNowSec != uiBeforeTime)
		{
			uiBeforeTime = uiNowSec;
			uiMaxNumSec = 0;
		}
		return (uiBeforeTime << 14) + (++uiMaxNumSec);
	}
private:
	//上一次时间戳
	uint uiBeforeTime;
	//每秒最大累加数
	uint uiMaxNumSec;
	static CTime *instance;
	CTime():uiBeforeTime(0), uiMaxNumSec(0)
	{}
};
struct CRoom
{
	uint uiRoomNum;
	uint uiCreateTime;
	uint uiRoomType;
	std::multiset<uint> setRoomMember;

	CRoom(uint uiRoomtype = ROOM_PUBLIC)
	{
		uiRoomType = uiRoomtype;
		uiRoomNum = CTime::getMe().getThisId();
		uiCreateTime = CTime::getMe().getNowTime();
	}
};
class CMatchManager
{
public:
	static CMatchManager &getMe()
	{
		if (NULL == instance)
		{
			instance = new CMatchManager();
			if (NULL == instance)
			{
				exit(1);
			}
		}
		return *instance;
	}
	uint createRoomPub(uint uiCreateId)
	{
		//不在房间
		if (m_mapUserRoom.find(uiCreateId) != m_mapUserRoom.end())
		{
			return 0;
		}
		CRoom croom(ROOM_PUBLIC);
		croom.setRoomMember.insert(uiCreateId);
		m_mapWaitingRoom.insert(std::make_pair(croom.uiRoomNum, croom));
		m_mapUserRoom.insert(std::make_pair(uiCreateId, croom.uiRoomNum));
		std::cout << "create publicroom success,user:" << uiCreateId << ",room:" << croom.uiRoomNum << std::endl;
		return croom.uiRoomNum;
	}
	uint createRoomPri(uint uiCreateId)
	{
		if (m_mapUserRoom.find(uiCreateId) != m_mapUserRoom.end())
		{
			return 0;
		}
		CRoom croom(ROOM_PRIVATE);
		croom.setRoomMember.insert(uiCreateId);
		m_mapWaitingRoom.insert(std::make_pair(croom.uiRoomNum, croom));
		m_mapUserRoom.insert(std::make_pair(uiCreateId, croom.uiRoomNum));
		std::cout << "create privateroom success,user:" << uiCreateId << ",room:" << croom.uiRoomNum << std::endl;
		return croom.uiRoomNum;
	}
	void intoRoomByRoomId(uint uiRoomid, uint uiRoleid)
	{
		if (m_mapUserRoom.find(uiRoleid) != m_mapUserRoom.end())
		{
			std::cout << "error: user have room" << std::endl;
			return;
		}
		auto it = m_mapWaitingRoom.find(uiRoomid);
		if (it == m_mapWaitingRoom.end())
		{
			std::cout << "error: into room error" << std::endl;
			return;
		}
		it->second.setRoomMember.insert(uiRoleid);
	}
	void changeRoomType(uint uiRoomid, uint uiRoleid, ROOM_TYPE type)
	{
		auto it = m_mapWaitingRoom.find(uiRoomid);
		if (it == m_mapWaitingRoom.end())
		{
			std::cout << "error: room not exists" << std::endl;
			return;
		}
		if (0 == (uint)it->second.setRoomMember.size())
		{
			std::cout << "error: room number size is 0" << std::endl;
			return;
		}
		if (uiRoleid != *(it->second.setRoomMember.begin()))
		{
			std::cout << "error: you aren't room creater" << std::endl;
			return;
		}
		it->second.uiRoomType = type;
	}
	void beginMatch(uint uiRoleid)
	{
		//是否有房间
		auto it = m_mapUserRoom.find(uiRoleid);
		if (it == m_mapUserRoom.end())
		{
			if (m_setMatchingUser.find(uiRoleid) == m_setMatchingUser.end())
			{
				m_setMatchingUser.insert(uiRoleid);
			}
		}
		else
		{
			auto itroom = m_mapWaitingRoom.find(it->second);
			if (itroom == m_mapWaitingRoom.end())
			{
				std::cout << "error: room not exists" << std::endl;
			}
			//private房间
			else if (ROOM_PRIVATE == itroom->second.uiRoomType)
			{
				if (1 < (uint)itroom->second.setRoomMember.size())
				{
					beginGameWaiting(itroom);
				}
			}
			//房间人数已满
			else if (MAX_ROOM_NUM <= (uint)itroom->second.setRoomMember.size())
			{
				beginGameWaiting(itroom);
			}
			//未满 匹配
			else
			{
				m_mapMatchingRoom.insert(std::make_pair(itroom->second.uiRoomNum, itroom->second));
				m_mapWaitingRoom.erase(itroom++);
			}
		}
		checkMatch();
	}
	void checkMatch()
	{
		//房间优先
		auto it = m_mapMatchingRoom.begin();
		for (; it != m_mapMatchingRoom.end(); ++it)
		{
			if (ROOM_PRIVATE == it->second.uiRoomType)
			{
				beginGameMatching(it);
				continue;
			}
			if (MAX_ROOM_NUM <= (uint)it->second.setRoomMember.size())
			{
				beginGameMatching(it);
				continue;
			}
			if (m_setMatchingUser.empty())
			{
				break;
			}
			bool bFlag = false;
			auto ituser = m_setMatchingUser.begin();
			for (; ituser != m_setMatchingUser.end(); )
			{
				it->second.setRoomMember.insert(*ituser);
				m_setMatchingUser.erase(ituser++);
				if (MAX_ROOM_NUM <= (uint)it->second.setRoomMember.size())
				{
						beginGameMatching(it);
						bFlag = true;
						break;
				}
			}
			if (bFlag)
				break;
		}
		if(it == m_mapMatchingRoom.end())
		{
			//查找玩家集合,合并
			while (MAX_ROOM_NUM <= (uint)m_setMatchingUser.size())
			{
				CRoom croom(ROOM_PUBLIC);
				int i = 0;
				for (auto ittmp = m_setMatchingUser.begin(); i < MAX_ROOM_NUM && ittmp != m_setMatchingUser.end(); ++i)
				{
					croom.setRoomMember.insert(*ittmp);
					m_setMatchingUser.erase(ittmp++);
				}
				beginGame(croom);
			}
		}
		else
		{
			///
			//开辟数组,每个元素是对应下标房间人数的集合,然后两个下标,一个前一个后,
			//优先合并相加等于房间最大人数的多个房间,剩余的,可以合并则合并
			///
			//查找多个房间,合并    vector<set<roomid>>
			std::vector<std::multiset<uint>> veTmp;
			for (int i = 0; i < MAX_ROOM_NUM; ++i)
			{
				std::multiset<uint> setTmp;
				veTmp.push_back(setTmp);
			}
			for (it = m_mapMatchingRoom.begin(); it != m_mapMatchingRoom.end(); )
			{
				if (it->second.setRoomMember.empty())
				{
					m_mapMatchingRoom.erase(it++);
				}
				else
				{
					veTmp[(uint)it->second.setRoomMember.size() - 1].insert(it->second.uiRoomNum);
					++it;
				}
			}

			//Begin和End前后相向走,遇到合适的就合并
			std::vector<std::vector<uint>> vecComRoom;
			uint uiBegin = 0;
			uint uiEnd = MAX_ROOM_NUM - 1;
			while (uiBegin < uiEnd)
			{
				while (uiBegin < uiEnd && veTmp[uiBegin].empty()) uiBegin++;
				if (uiBegin >= uiEnd) break;
				while (uiBegin < uiEnd && veTmp[uiEnd].empty()) uiEnd--;
				if (uiBegin >= uiEnd) break;

				if (uiBegin + uiEnd > MAX_ROOM_NUM)
				{
					uiEnd--;
					continue;
				}
				else if (uiBegin + uiEnd == MAX_ROOM_NUM)
				{
					for (auto itbegin = veTmp[uiBegin].begin(); itbegin != veTmp[uiBegin].end(); )
					{
						auto itend = veTmp[uiEnd].begin();
						if (itend != veTmp[uiEnd].end())
						{
							std::vector<uint> vec;
							vec.push_back(*itend);
							vec.push_back(*itbegin);
							veTmp[uiBegin].erase(itbegin++);
							veTmp[uiEnd].erase(itend++);
							vecComRoom.push_back(vec);
						}
						else
						{
							++itbegin;
						}
					}
				}
				else
				{
					for (auto itbegin = veTmp[uiBegin].begin(); itbegin != veTmp[uiBegin].end(); )
					{
						auto itend = veTmp[uiEnd].begin();
						if (itend != veTmp[uiEnd].end())
						{
							std::vector<uint> vec;
							vec.push_back(*itend);
							vec.push_back(*itbegin);
							veTmp[uiBegin].erase(itbegin++);
							veTmp[uiEnd].erase(itend++);
							//查找最后符合的
							uint uiSub = MAX_ROOM_NUM - uiBegin - uiEnd;
							auto itsub = veTmp[uiSub].begin();
							if (itsub != veTmp[uiSub].end())
							{
								vec.push_back(*itsub);
							}
							vecComRoom.push_back(vec);
						}
						else
						{
							++itbegin;
						}
					}
				}
			}
			if (0 < uiBegin && uiBegin <= MAX_ROOM_NUM / 2 && !veTmp[uiBegin].empty())
			{
				uint uiNum = 0;
				std::vector<uint> vec;
				for (auto it = veTmp[uiBegin].begin(); it != veTmp[uiEnd].end(); ++it)
				{
					if (2 == uiNum)
					{
						vecComRoom.push_back(vec);
						vec.clear();
						uiNum = 0;
					}
					vec.push_back(*it);
					uiNum += 1;
				}
				if (!vec.empty())
				{
					vecComRoom.push_back(vec);
				}
			}
			/*
			//前后先查找一遍,将符合的提出来,然后在走一遍,每次叠加,找到叠加值的互补值
			for (uint i = 0; i < MAX_ROOM_NUM; ++i)
			{
				if (veTmp[i].empty())
				{
					continue;
				}
				if (veTmp[MAX_ROOM_NUM - i - 1].empty())
				{
					continue;
				}
				auto itroomfirst = veTmp[i].begin();
				auto itroomsecond = veTmp[MAX_ROOM_NUM - i - 1].begin();
				while (itroomfirst != veTmp[i].end() && itroomsecond != veTmp[MAX_ROOM_NUM - i - 1].end())
				{
					uint uitmpfirst = *itroomfirst;
					auto ittmpfirst = m_mapMatchingRoom.find(uitmpfirst);
					uint uitmpsecond = *itroomsecond;
					auto ittmpsecond = m_mapMatchingRoom.find(uitmpsecond);
					if (ittmpfirst == m_mapMatchingRoom.end() || ittmpsecond == m_mapMatchingRoom.end())
					{
						continue;
					}

				}
			}*/
			mergeRoom(vecComRoom);
		}
	}
	void mergeRoom(std::vector<std::vector<uint>> &vecComRoom)
	{
		for (uint dwI = 0; dwI < vecComRoom.size(); ++dwI)
		{
			uint uiRoomid = (uint)-1;
			for (uint dwJ = 0; dwJ < vecComRoom[dwI].size(); ++dwJ)
			{
				if ((uint)-1 == uiRoomid)
				{
					uiRoomid = vecComRoom[dwI][dwJ];
					continue;
				}
				auto it = m_mapMatchingRoom.find(uiRoomid);
				auto ittmp = m_mapMatchingRoom.find(vecComRoom[dwI][dwJ]);
				if (it == m_mapMatchingRoom.end() || ittmp == m_mapMatchingRoom.end())
				{
					break;
				}
				for (auto itnow = ittmp->second.setRoomMember.begin(); itnow != ittmp->second.setRoomMember.end(); ++itnow)
				{
					auto itindex = m_mapMatchingRoom.find(*itnow);
					if (itindex == m_mapMatchingRoom.end())
					{
						return;
					}
					m_mapMatchingRoom.erase(itindex);
					it->second.setRoomMember.insert(*itnow);
				}
			}
		}
	}
	//beginGame
	void beginGameWaiting(std::map<uint, CRoom>::iterator &itroom)
	{
		if (itroom != m_mapWaitingRoom.end())
		{
			std::cout << "into game success" << std::endl;
			std::cout << "-------------------" << std::endl;
			for (auto &it : itroom->second.setRoomMember)
			{
				cout << "user: " << it << endl;
			}
			std::cout << "-------------------" << std::endl;
			itroom = m_mapWaitingRoom.erase(itroom);
		}
	}
	void beginGameMatching(std::map<uint, CRoom>::iterator &itroom)
	{
		if (itroom != m_mapMatchingRoom.end())
		{
			std::cout << "into game success" << std::endl;
			std::cout << "-------------------" << std::endl;
			for (auto &it : itroom->second.setRoomMember)
			{
				cout << "user: " << it << endl;
			}
			std::cout << "-------------------" << std::endl;
			itroom = m_mapMatchingRoom.erase(itroom);
		}
	}
	std::multiset<uint>::iterator beginGame(std::multiset<uint>::iterator ituser)
	{
		if (ituser != m_setMatchingUser.end())
		{
			std::cout << "into game success" << std::endl;
			std::cout << "-------------------" << std::endl;
			cout << "user: " << *ituser << endl;
			std::cout << "-------------------" << std::endl;
			m_setMatchingUser.erase(ituser++);
		}
		return ituser;
	}
	void beginGame(CRoom &croom)
	{
		std::cout << "into game success" << std::endl;
		std::cout << "-------------------" << std::endl;
		for (auto &it : croom.setRoomMember)
		{
			cout << "user: " << it << endl;
		}
		std::cout << "-------------------" << std::endl;
	}
private:
	//正在匹配房间 <roomid, room>
	std::map<uint, CRoom> m_mapMatchingRoom;
	//<userid, roomid>
	std::map<uint, uint> m_mapUserRoom;
	//未匹配房间  <roomid, room>
	std::map<uint, CRoom> m_mapWaitingRoom;
	//玩家等待列表
	std::multiset<uint> m_setMatchingUser;
	static CMatchManager *instance;
	CMatchManager() {}
};

#endif // !_MATCH_H_

测试文件:

#include "match.h"
#include <iostream>
using namespace std;
CTime *CTime::instance = NULL;
CMatchManager *CMatchManager::instance = NULL;

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;
int main()
{
	uint uiRoomid = CMatchManager::getMe().createRoomPri(10);
	CMatchManager::getMe().beginMatch(10);
	CMatchManager::getMe().intoRoomByRoomId(uiRoomid, 11);
	CMatchManager::getMe().beginMatch(10);
	CMatchManager::getMe().createRoomPub(12);
	CMatchManager::getMe().beginMatch(12);
	CMatchManager::getMe().beginMatch(13);
	CMatchManager::getMe().beginMatch(14);


	//for (uint i = 10; i < 30; ++i)
	{
		//CMatchManager::getMe().beginMatch(i);
	}
	return 0;
}

        关于侠客自走旗,前两个月,数据都还可以。现在如此情景,其实挺遗憾的,但是也不遗憾。毕竟对于我而言,并不遗憾。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值