从去年年底开始,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;
}
关于侠客自走旗,前两个月,数据都还可以。现在如此情景,其实挺遗憾的,但是也不遗憾。毕竟对于我而言,并不遗憾。