package com.cwa.qiji;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 将玩家ID按等级分组放在内存中。
* 内存中的玩家分布类似这样:
* level range | user id
* [1 - 5] [1, 2, 3, 4, 5]
* [6 -10] [6, 7, 8, 9,10]
*/
class ActiveUserCache {
private final int levelsPerPage; // 每一页有多少等级
private final ActiveUserCachePage[] pages;
/**
* 构造函数。
* @param minLevel 最小等级
* @param maxLevel 最大等级
* @param levelsPerPage 每页几个等级
* @param usersPerPage 每页多少玩家
*/
public ActiveUserCache(int minLevel, int maxLevel, int levelsPerPage, int usersPerPage) {
this.levelsPerPage = levelsPerPage;
int pageCount = calcPageCount(maxLevel, levelsPerPage);
this.pages = new ActiveUserCachePage[pageCount];
for (int i = 0; i < pageCount; i++) {
pages[i] = new ActiveUserCachePage(usersPerPage);
}
}
private int calcPageCount(int maxLevel, int levelsPerPage) {
return maxLevel/levelsPerPage + (maxLevel%levelsPerPage == 0 ? 0 : 1);
}
public ActiveUserCachePage[] getPages() {
return pages;
}
/*
* 更新活跃玩家。
* @param uid
* @param level
*/
public void update(int uid, int level) {
int pageIdx = getPageIndex(level);
pages[pageIdx].update(uid);
}
/*
* 返回随机玩家。
* @param level
* @param n
* @return
*/
public List<Integer> getRaodomUsers(int level, int n) {
int pageIdx = getPageIndex(level);
return pages[pageIdx].getRandomUsers(n);
}
/*
* 尽量返回足够数量的随机玩家。
* @param level
* @param n
* @return
*/
public List<Integer> getRandomUsersAround(int level, int n) {
int pageIdx = getPageIndex(level);
Set<Integer> result = new HashSet<Integer>();
result.addAll(pages[pageIdx].getRandomUsers(n));
// 有足够数量的活跃玩家和玩家等级差不多
if (result.size() >= n) {
return new ArrayList<Integer>(result);
}
// 在附近等级中查找
for (int step = 1; step < pages.length; step++) {
int pageUp = pageIdx + step;
int pageDown = pageIdx - step;
// 所有组都找遍了
if (pageUp >= pages.length && pageDown < 0) {
break;
}
// 优先查找比玩家等级高的玩家
if (pageUp < pages.length) {
result.addAll(pages[pageUp].getRandomUsers(n - result.size()));
if (result.size() >= n) {
return new ArrayList<Integer>(result);
}
}
// 查找等级比玩家低的玩家
if (pageDown >= 0) {
result.addAll(pages[pageDown].getRandomUsers(n - result.size()));
if (result.size() >= n) {
return new ArrayList<Integer>(result);
}
}
}
return new ArrayList<Integer>(result);
}
private int getPageIndex(int level) {
return (level - 1) / levelsPerPage;
}
}