use of top.hcode.hoj.pojo.vo.ACMContestRankVo in project HOJ by HimitZH.
the class ContestRecordServiceImpl method calcACMRank.
/**
* @param isOpenSealRank 是否是查询封榜后的数据
* @param removeStar 是否需要移除打星队伍
* @param contest 比赛实体信息
* @param contestRecordList 比赛记录数据
* @param currentUserId 当前查看榜单的用户uuid,不为空则将该数据复制一份放置列表最前
* @param concernedList 关注的用户(uuid)列表
* @MethodName calcACMRank
* @Description TODO
* @Return
* @Since 2021/12/10
*/
public List<ACMContestRankVo> calcACMRank(boolean isOpenSealRank, boolean removeStar, Contest contest, List<ContestRecordVo> contestRecordList, String currentUserId, List<String> concernedList) {
List<UserInfo> superAdminList = getSuperAdminList();
List<String> superAdminUidList = superAdminList.stream().map(UserInfo::getUuid).collect(Collectors.toList());
List<ACMContestRankVo> result = new ArrayList<>();
HashMap<String, Integer> uidMapIndex = new HashMap<>();
int index = 0;
HashMap<String, Long> firstACMap = new HashMap<>();
for (ContestRecordVo contestRecord : contestRecordList) {
if (superAdminUidList.contains(contestRecord.getUid())) {
// 超级管理员的提交不入排行榜
continue;
}
ACMContestRankVo ACMContestRankVo;
if (!uidMapIndex.containsKey(contestRecord.getUid())) {
// 如果该用户信息没还记录
// 初始化参数
ACMContestRankVo = new ACMContestRankVo();
ACMContestRankVo.setRealname(contestRecord.getRealname()).setAvatar(contestRecord.getAvatar()).setSchool(contestRecord.getSchool()).setGender(contestRecord.getGender()).setUid(contestRecord.getUid()).setUsername(contestRecord.getUsername()).setNickname(contestRecord.getNickname()).setAc(0).setTotalTime(0L).setTotal(0);
HashMap<String, HashMap<String, Object>> submissionInfo = new HashMap<>();
ACMContestRankVo.setSubmissionInfo(submissionInfo);
result.add(ACMContestRankVo);
uidMapIndex.put(contestRecord.getUid(), index);
index++;
} else {
// 根据记录的index进行获取
ACMContestRankVo = result.get(uidMapIndex.get(contestRecord.getUid()));
}
HashMap<String, Object> problemSubmissionInfo = ACMContestRankVo.getSubmissionInfo().get(contestRecord.getDisplayId());
if (problemSubmissionInfo == null) {
problemSubmissionInfo = new HashMap<>();
problemSubmissionInfo.put("errorNum", 0);
}
ACMContestRankVo.setTotal(ACMContestRankVo.getTotal() + 1);
// 如果是当前是开启封榜的时段和同时该提交是处于封榜时段 尝试次数+1
if (isOpenSealRank && isInSealTimeSubmission(contest, contestRecord.getSubmitTime())) {
int tryNum = (int) problemSubmissionInfo.getOrDefault("tryNum", 0);
problemSubmissionInfo.put("tryNum", tryNum + 1);
} else {
// 如果该题目已经AC过了,其它都不记录了
if ((Boolean) problemSubmissionInfo.getOrDefault("isAC", false)) {
continue;
}
// 通过的话
if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_AC.getCode()) {
// 总解决题目次数ac+1
ACMContestRankVo.setAc(ACMContestRankVo.getAc() + 1);
// 判断是不是first AC
boolean isFirstAC = false;
Long time = firstACMap.getOrDefault(contestRecord.getDisplayId(), null);
if (time == null) {
isFirstAC = true;
firstACMap.put(contestRecord.getDisplayId(), contestRecord.getTime());
} else {
// 相同提交时间也是first AC
if (time.longValue() == contestRecord.getTime().longValue()) {
isFirstAC = true;
}
}
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("isAC", true);
problemSubmissionInfo.put("isFirstAC", isFirstAC);
problemSubmissionInfo.put("ACTime", contestRecord.getTime());
problemSubmissionInfo.put("errorNum", errorNumber);
// 同时计算总耗时,总耗时加上 该题目未AC前的错误次数*20*60+题目AC耗时
ACMContestRankVo.setTotalTime(ACMContestRankVo.getTotalTime() + errorNumber * 20 * 60 + contestRecord.getTime());
// 未通过同时需要记录罚时次数
} else if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_NOT_AC_PENALTY.getCode()) {
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("errorNum", errorNumber + 1);
} else {
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("errorNum", errorNumber);
}
}
ACMContestRankVo.getSubmissionInfo().put(contestRecord.getDisplayId(), problemSubmissionInfo);
}
List<ACMContestRankVo> orderResultList = result.stream().sorted(// 先以总ac数降序
Comparator.comparing(ACMContestRankVo::getAc, Comparator.reverseOrder()).thenComparing(// 再以总耗时升序
ACMContestRankVo::getTotalTime)).collect(Collectors.toList());
// 需要打星的用户名列表
HashMap<String, Boolean> starAccountMap = starAccountToMap(contest.getStarAccount());
// 如果选择了移除打星队伍,同时该用户属于打星队伍,则将其移除
if (removeStar) {
orderResultList.removeIf(acmContestRankVo -> starAccountMap.containsKey(acmContestRankVo.getUsername()));
}
// 记录当前用户排名数据和关注列表的用户排名数据
List<ACMContestRankVo> topACMRankVoList = new ArrayList<>();
boolean needAddConcernedUser = false;
if (!CollectionUtils.isEmpty(concernedList)) {
needAddConcernedUser = true;
// 移除关注列表与当前用户重复
concernedList.remove(currentUserId);
}
int rankNum = 1;
int len = orderResultList.size();
ACMContestRankVo lastACMRankVo = null;
for (int i = 0; i < len; i++) {
ACMContestRankVo currentACMRankVo = orderResultList.get(i);
if (starAccountMap.containsKey(currentACMRankVo.getUsername())) {
// 打星队伍排名为-1
currentACMRankVo.setRank(-1);
} else {
if (rankNum == 1) {
currentACMRankVo.setRank(rankNum);
} else {
// 当前用户的总罚时和AC数跟前一个用户一样的话,同时前一个不应该为打星,排名则一样
if (lastACMRankVo.getAc().equals(currentACMRankVo.getAc()) && lastACMRankVo.getTotalTime().equals(currentACMRankVo.getTotalTime())) {
currentACMRankVo.setRank(lastACMRankVo.getRank());
} else {
currentACMRankVo.setRank(rankNum);
}
}
lastACMRankVo = currentACMRankVo;
rankNum++;
}
if (!StringUtils.isEmpty(currentUserId) && currentACMRankVo.getUid().equals(currentUserId)) {
topACMRankVoList.add(currentACMRankVo);
}
// 需要添加关注用户
if (needAddConcernedUser) {
if (concernedList.contains(currentACMRankVo.getUid())) {
topACMRankVoList.add(currentACMRankVo);
}
}
}
topACMRankVoList.addAll(orderResultList);
return topACMRankVoList;
}
use of top.hcode.hoj.pojo.vo.ACMContestRankVo in project HOJ by HimitZH.
the class FileEntityEntityServiceImpl method changeACMContestRankToExcelRowList.
@Override
public List<List<Object>> changeACMContestRankToExcelRowList(List<ACMContestRankVo> acmContestRankVoList, List<String> contestProblemDisplayIDList, String rankShowName) {
List<List<Object>> allRowDataList = new LinkedList<>();
for (ACMContestRankVo acmContestRankVo : acmContestRankVoList) {
List<Object> rowData = new LinkedList<>();
rowData.add(acmContestRankVo.getRank() == -1 ? "*" : acmContestRankVo.getRank().toString());
rowData.add(acmContestRankVo.getUsername());
if ("username".equals(rankShowName)) {
rowData.add(acmContestRankVo.getUsername());
} else if ("realname".equals(rankShowName)) {
rowData.add(acmContestRankVo.getRealname());
} else if ("nickname".equals(rankShowName)) {
rowData.add(acmContestRankVo.getNickname());
} else {
rowData.add("");
}
rowData.add(acmContestRankVo.getRealname());
rowData.add(acmContestRankVo.getSchool());
rowData.add(acmContestRankVo.getAc());
rowData.add(acmContestRankVo.getTotal());
rowData.add(acmContestRankVo.getTotalTime());
HashMap<String, HashMap<String, Object>> submissionInfo = acmContestRankVo.getSubmissionInfo();
for (String displayID : contestProblemDisplayIDList) {
HashMap<String, Object> problemInfo = submissionInfo.getOrDefault(displayID, null);
if (problemInfo != null) {
// 如果是有提交记录的
boolean isAC = (boolean) problemInfo.getOrDefault("isAC", false);
String info = "";
int errorNum = (int) problemInfo.getOrDefault("errorNum", 0);
int tryNum = (int) problemInfo.getOrDefault("tryNum", 0);
if (isAC) {
if (errorNum == 0) {
info = "+(1)";
} else {
info = "-(" + (errorNum + 1) + ")";
}
} else {
if (tryNum != 0 && errorNum != 0) {
info = "-(" + errorNum + "+" + tryNum + ")";
} else if (errorNum != 0) {
info = "-(" + errorNum + ")";
} else if (tryNum != 0) {
info = "?(" + tryNum + ")";
}
}
rowData.add(info);
} else {
rowData.add("");
}
}
allRowDataList.add(rowData);
}
return allRowDataList;
}
use of top.hcode.hoj.pojo.vo.ACMContestRankVo in project HOJ by HimitZH.
the class ContestCalculateRankManager method getACMOrderRank.
private List<ACMContestRankVo> getACMOrderRank(Contest contest, Boolean isOpenSealRank) {
List<ContestRecordVo> contestRecordList = contestRecordEntityService.getACMContestRecord(contest.getUid(), contest.getId());
List<String> superAdminUidList = getSuperAdminUidList(contest.getGid());
List<ACMContestRankVo> result = new ArrayList<>();
HashMap<String, Integer> uidMapIndex = new HashMap<>();
int index = 0;
HashMap<String, Long> firstACMap = new HashMap<>();
for (ContestRecordVo contestRecord : contestRecordList) {
if (superAdminUidList.contains(contestRecord.getUid())) {
// 超级管理员的提交不入排行榜
continue;
}
ACMContestRankVo ACMContestRankVo;
if (!uidMapIndex.containsKey(contestRecord.getUid())) {
// 如果该用户信息没还记录
// 初始化参数
ACMContestRankVo = new ACMContestRankVo();
ACMContestRankVo.setRealname(contestRecord.getRealname()).setAvatar(contestRecord.getAvatar()).setSchool(contestRecord.getSchool()).setGender(contestRecord.getGender()).setUid(contestRecord.getUid()).setUsername(contestRecord.getUsername()).setNickname(contestRecord.getNickname()).setAc(0).setTotalTime(0L).setTotal(0);
HashMap<String, HashMap<String, Object>> submissionInfo = new HashMap<>();
ACMContestRankVo.setSubmissionInfo(submissionInfo);
result.add(ACMContestRankVo);
uidMapIndex.put(contestRecord.getUid(), index);
index++;
} else {
// 根据记录的index进行获取
ACMContestRankVo = result.get(uidMapIndex.get(contestRecord.getUid()));
}
HashMap<String, Object> problemSubmissionInfo = ACMContestRankVo.getSubmissionInfo().get(contestRecord.getDisplayId());
if (problemSubmissionInfo == null) {
problemSubmissionInfo = new HashMap<>();
problemSubmissionInfo.put("errorNum", 0);
}
ACMContestRankVo.setTotal(ACMContestRankVo.getTotal() + 1);
// 如果是当前是开启封榜的时段和同时该提交是处于封榜时段 尝试次数+1
if (isOpenSealRank && isInSealTimeSubmission(contest, contestRecord.getSubmitTime())) {
int tryNum = (int) problemSubmissionInfo.getOrDefault("tryNum", 0);
problemSubmissionInfo.put("tryNum", tryNum + 1);
} else {
// 如果该题目已经AC过了,其它都不记录了
if ((Boolean) problemSubmissionInfo.getOrDefault("isAC", false)) {
continue;
}
// 通过的话
if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_AC.getCode()) {
// 总解决题目次数ac+1
ACMContestRankVo.setAc(ACMContestRankVo.getAc() + 1);
// 判断是不是first AC
boolean isFirstAC = false;
Long time = firstACMap.getOrDefault(contestRecord.getDisplayId(), null);
if (time == null) {
isFirstAC = true;
firstACMap.put(contestRecord.getDisplayId(), contestRecord.getTime());
} else {
// 相同提交时间也是first AC
if (time.longValue() == contestRecord.getTime().longValue()) {
isFirstAC = true;
}
}
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("isAC", true);
problemSubmissionInfo.put("isFirstAC", isFirstAC);
problemSubmissionInfo.put("ACTime", contestRecord.getTime());
problemSubmissionInfo.put("errorNum", errorNumber);
// 同时计算总耗时,总耗时加上 该题目未AC前的错误次数*20*60+题目AC耗时
ACMContestRankVo.setTotalTime(ACMContestRankVo.getTotalTime() + errorNumber * 20 * 60 + contestRecord.getTime());
// 未通过同时需要记录罚时次数
} else if (contestRecord.getStatus().intValue() == Constants.Contest.RECORD_NOT_AC_PENALTY.getCode()) {
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("errorNum", errorNumber + 1);
} else {
int errorNumber = (int) problemSubmissionInfo.getOrDefault("errorNum", 0);
problemSubmissionInfo.put("errorNum", errorNumber);
}
}
ACMContestRankVo.getSubmissionInfo().put(contestRecord.getDisplayId(), problemSubmissionInfo);
}
List<ACMContestRankVo> orderResultList = result.stream().sorted(// 先以总ac数降序
Comparator.comparing(ACMContestRankVo::getAc, Comparator.reverseOrder()).thenComparing(// 再以总耗时升序
ACMContestRankVo::getTotalTime)).collect(Collectors.toList());
return orderResultList;
}
use of top.hcode.hoj.pojo.vo.ACMContestRankVo in project HOJ by HimitZH.
the class ContestCalculateRankManager method calcACMRank.
/**
* @param isOpenSealRank 是否是查询封榜后的数据
* @param removeStar 是否需要移除打星队伍
* @param contest 比赛实体信息
* @param currentUserId 当前查看榜单的用户uuid,不为空则将该数据复制一份放置列表最前
* @param concernedList 关注的用户(uuid)列表
* @param useCache 是否对初始排序计算的结果进行缓存
* @param cacheTime 缓存的时间 单位秒
* @MethodName calcACMRank
* @Description TODO
* @Return
* @Since 2021/12/10
*/
public List<ACMContestRankVo> calcACMRank(boolean isOpenSealRank, boolean removeStar, Contest contest, String currentUserId, List<String> concernedList, boolean useCache, Long cacheTime) {
List<ACMContestRankVo> orderResultList;
if (useCache) {
String key = Constants.Contest.CONTEST_RANK_CAL_RESULT_CACHE.getName() + "_" + contest.getId();
orderResultList = (List<ACMContestRankVo>) redisUtils.get(key);
if (orderResultList == null) {
orderResultList = getACMOrderRank(contest, isOpenSealRank);
redisUtils.set(key, orderResultList, cacheTime);
}
} else {
orderResultList = getACMOrderRank(contest, isOpenSealRank);
}
// 需要打星的用户名列表
HashMap<String, Boolean> starAccountMap = starAccountToMap(contest.getStarAccount());
// 如果选择了移除打星队伍,同时该用户属于打星队伍,则将其移除
if (removeStar) {
orderResultList.removeIf(acmContestRankVo -> starAccountMap.containsKey(acmContestRankVo.getUsername()));
}
// 记录当前用户排名数据和关注列表的用户排名数据
List<ACMContestRankVo> topACMRankVoList = new ArrayList<>();
boolean needAddConcernedUser = false;
if (!CollectionUtils.isEmpty(concernedList)) {
needAddConcernedUser = true;
// 移除关注列表与当前用户重复
concernedList.remove(currentUserId);
}
int rankNum = 1;
int len = orderResultList.size();
ACMContestRankVo lastACMRankVo = null;
for (int i = 0; i < len; i++) {
ACMContestRankVo currentACMRankVo = orderResultList.get(i);
if (starAccountMap.containsKey(currentACMRankVo.getUsername())) {
// 打星队伍排名为-1
currentACMRankVo.setRank(-1);
} else {
if (rankNum == 1) {
currentACMRankVo.setRank(rankNum);
} else {
// 当前用户的总罚时和AC数跟前一个用户一样的话,同时前一个不应该为打星,排名则一样
if (lastACMRankVo.getAc().equals(currentACMRankVo.getAc()) && lastACMRankVo.getTotalTime().equals(currentACMRankVo.getTotalTime())) {
currentACMRankVo.setRank(lastACMRankVo.getRank());
} else {
currentACMRankVo.setRank(rankNum);
}
}
lastACMRankVo = currentACMRankVo;
rankNum++;
}
if (!StringUtils.isEmpty(currentUserId) && currentACMRankVo.getUid().equals(currentUserId)) {
topACMRankVoList.add(currentACMRankVo);
}
// 需要添加关注用户
if (needAddConcernedUser) {
if (concernedList.contains(currentACMRankVo.getUid())) {
topACMRankVoList.add(currentACMRankVo);
}
}
}
topACMRankVoList.addAll(orderResultList);
return topACMRankVoList;
}
use of top.hcode.hoj.pojo.vo.ACMContestRankVo in project HOJ by HimitZH.
the class FileServiceImpl method changeACMContestRankToExcelRowList.
@Override
public List<List<Object>> changeACMContestRankToExcelRowList(List<ACMContestRankVo> acmContestRankVoList, List<String> contestProblemDisplayIDList, String rankShowName) {
List<List<Object>> allRowDataList = new LinkedList<>();
for (ACMContestRankVo acmContestRankVo : acmContestRankVoList) {
List<Object> rowData = new LinkedList<>();
rowData.add(acmContestRankVo.getRank() == -1 ? "*" : acmContestRankVo.getRank().toString());
rowData.add(acmContestRankVo.getUsername());
if ("username".equals(rankShowName)) {
rowData.add(acmContestRankVo.getUsername());
} else if ("realname".equals(rankShowName)) {
rowData.add(acmContestRankVo.getRealname());
} else if ("nickname".equals(rankShowName)) {
rowData.add(acmContestRankVo.getNickname());
} else {
rowData.add("");
}
rowData.add(acmContestRankVo.getRealname());
rowData.add(acmContestRankVo.getSchool());
rowData.add(acmContestRankVo.getAc());
rowData.add(acmContestRankVo.getTotal());
rowData.add(acmContestRankVo.getTotalTime());
HashMap<String, HashMap<String, Object>> submissionInfo = acmContestRankVo.getSubmissionInfo();
for (String displayID : contestProblemDisplayIDList) {
HashMap<String, Object> problemInfo = submissionInfo.getOrDefault(displayID, null);
if (problemInfo != null) {
// 如果是有提交记录的
boolean isAC = (boolean) problemInfo.getOrDefault("isAC", false);
String info = "";
int errorNum = (int) problemInfo.getOrDefault("errorNum", 0);
int tryNum = (int) problemInfo.getOrDefault("tryNum", 0);
if (isAC) {
if (errorNum == 0) {
info = "+(1)";
} else {
info = "-(" + (errorNum + 1) + ")";
}
} else {
if (tryNum != 0 && errorNum != 0) {
info = "-(" + errorNum + "+" + tryNum + ")";
} else if (errorNum != 0) {
info = "-(" + errorNum + ")";
} else if (tryNum != 0) {
info = "?(" + tryNum + ")";
}
}
rowData.add(info);
} else {
rowData.add("");
}
}
allRowDataList.add(rowData);
}
return allRowDataList;
}
Aggregations