在上篇文章中,介绍了下pvp玩法中的匹配算法的简单实现具体的可参见https://my.oschina.net/hzxu/blog/755483,最近不忙了,回过头来改进下原来的实现机制,原来的实现是在最后整合出的对战组数据中找出匹分最相近的对阵目标。这样就会有个问题在运算后期还是会将积分差值很大的双方阵营匹配到一个战场中,这样公平性就降低了。于是就改进下,在整合出对战数据时对待匹配的数据进行再一次的分类,根据其平局积分或者总积分score,算出一个区间索引。如规定其区间步长为step=100(可根据匹配人数动态调整改值),那么其索引值为 index = score / 100;这样积分差值在100以内的所有数据都会命中同一个index索引值。在匹配运算时很容易根据自己当前的队伍组算出自己在哪个索引下,然后再在这个索引下找和自己积分差最相近的对阵队伍。同样在为避免匹配时间过长可以在等待了一定的时间后山下浮动几个索引组扩大匹配数。主要代码实现如下:
private final static int danStep = 100;
public void process() {
if (TestMatch.matchTeamInfos.isEmpty())
return;
int totalMatchRoleNum = 0;
for (Map.Entry entry : TestMatch.matchTeamInfos.entrySet()) {
totalMatchRoleNum += entry.getValue().roleinfos.size();
}
System.err.println("当前正在匹配中的玩家:"+totalMatchRoleNum);
List matchResults = new ArrayList<>();//匹配成功的玩家
Map> matchingCalssifyTeam = classifyTeams(TestMatch.matchTeamInfos);
List matchingGroupResult = getCampMatchGroupResult(matchingCalssifyTeam);
Map> danGroupResult = getdanGroupResult(matchingGroupResult);
System.err.println("一共整合出:"+matchingGroupResult.size() +"个匹配组");
if (matchingGroupResult.isEmpty())
return;
int size = matchingGroupResult.size();
Set alreadyOccupied = new HashSet<>();
List danKeys = new ArrayList<>();
danKeys.addAll(matchingCalssifyTeam.keySet());
Collections.sort(danKeys);
for (int i = 0; i < size; ++i) {
MatchGroupResult tempGroup = matchingGroupResult.get(i);
if (alreadyOccupied.contains(tempGroup.teamId))
continue;
final int KeyValue = indexOf(tempGroup.averageScore);
List currentDanMatchGroup = danGroupResult.get(KeyValue);
if (null == currentDanMatchGroup)
continue;
int minVal = danStep;
MatchResult result = getFinalResult(alreadyOccupied, matchingGroupResult, tempGroup, i, minVal, matchResults);
int currenStepNum = currentDanStepNum(tempGroup.startMatchTime);
if (null == result && currenStepNum > 1) {
int keyindex = danKeys.indexOf(KeyValue);
List offsetKeys = new ArrayList<>();
for (int j = 1; j < currenStepNum; ++j) {
if (keyindex - j > 0) {
offsetKeys.add(keyindex - j);
}
if (keyindex + j < offsetKeys.size()) {
offsetKeys.add(keyindex + j);
}
}
currentDanMatchGroup.clear();
minVal = currentdanStep(tempGroup.startMatchTime);
for (int listIndex : offsetKeys) {
currentDanMatchGroup.addAll(danGroupResult.get(offsetKeys.get(listIndex)));
}
result = getFinalResult(alreadyOccupied, matchingGroupResult, tempGroup, i, minVal, matchResults);
if (null == result && isOutOffMaxTime(tempGroup.startMatchTime))
result = getFinalResult(alreadyOccupied, matchingGroupResult, tempGroup, i, Integer.MAX_VALUE, matchResults);
}
}
for (MatchResult matchResult : matchResults) {
long now = System.currentTimeMillis();
for (long removeTeamId : matchResult.reGroup.teams.keySet()) {
TestMatch.matchTeamInfos.remove(removeTeamId);
if (now - matchResult.reGroup.startMatchTime > 20 * 1000) {
System.err.println("队伍:"+removeTeamId +"匹配时间是"+((now - matchResult.reGroup.startMatchTime)/ 1000)+"秒");
}
}
for (long removeTeamId : matchResult.blueGroup.teams.keySet()) {
TestMatch.matchTeamInfos.remove(removeTeamId);
if (now - matchResult.blueGroup.startMatchTime > 20 * 1000) {
System.err.println("队伍:"+removeTeamId +"匹配时间是"+((now - matchResult.blueGroup.startMatchTime)/ 1000)+"秒");
}
}
}
System.err.println("共创建了:"+matchResults.size()+"个战场");
}
public MatchResult getFinalResult(Set alreadyOccupied, List matchingGroupResult, MatchGroupResult tempGroup,
int i, int danstep, List matchResults) {
MatchResult matchResult = null;
int saveIndexI = -1;
int saveIndexJ = -1;
int minVal = danstep;
int size = matchingGroupResult.size();
for (int j = 0; j < size; ++j) {
if (i == j || alreadyOccupied.contains(j))
continue;
int subVal = Math.abs(tempGroup.averageScore - matchingGroupResult.get(j).averageScore);
if (subVal < minVal) {
matchResult = new MatchResult();
matchResult.blueGroup = matchingGroupResult.get(i);
matchResult.reGroup = matchingGroupResult.get(j);
minVal = subVal;
saveIndexI = i;
saveIndexJ = j;
}
}
if (null != matchResult && saveIndexI != -1 && saveIndexJ != -1) {
matchResults.add(matchResult);
alreadyOccupied.add(tempGroup.teamId);
alreadyOccupied.add(matchingGroupResult.get(saveIndexJ).teamId);
}
return matchResult;
}
private Map> getdanGroupResult(List matchingGroupResult){
Map> result = new HashMap<>();
for (MatchGroupResult matchGroupResult : matchingGroupResult) {
int indexKey = indexOf(matchGroupResult.averageScore);
List tempValue = result.get(indexKey);
if (null == tempValue) {
tempValue = new ArrayList<>();
result.put(indexKey, tempValue);
}
tempValue.add(matchGroupResult);
}
return result;
}
private int indexOf(int averageScore) {
return averageScore / danStep;
}
private int currentdanStep(long startMatchTime) {
return (int) Math.max(danStep, (System.currentTimeMillis() - startMatchTime) / 30000 * 300);
}
private int currentDanStepNum(long startMatchTime) {
return currentdanStep(startMatchTime) / danStep;
}
private boolean isOutOffMaxTime(long startMatchTime) {
return (System.currentTimeMillis() - startMatchTime) > 60 * 1000;
}