Search in sources :

Example 1 with ACMContestRankVo

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;
}
Also used : UserInfo(top.hcode.hoj.pojo.entity.user.UserInfo) ContestRecordVo(top.hcode.hoj.pojo.vo.ContestRecordVo) ACMContestRankVo(top.hcode.hoj.pojo.vo.ACMContestRankVo) JSONObject(cn.hutool.json.JSONObject)

Example 2 with ACMContestRankVo

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;
}
Also used : ACMContestRankVo(top.hcode.hoj.pojo.vo.ACMContestRankVo) HashMap(java.util.HashMap) List(java.util.List) LinkedList(java.util.LinkedList) LinkedList(java.util.LinkedList)

Example 3 with ACMContestRankVo

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;
}
Also used : ContestRecordVo(top.hcode.hoj.pojo.vo.ContestRecordVo) ACMContestRankVo(top.hcode.hoj.pojo.vo.ACMContestRankVo) JSONObject(cn.hutool.json.JSONObject)

Example 4 with ACMContestRankVo

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;
}
Also used : ACMContestRankVo(top.hcode.hoj.pojo.vo.ACMContestRankVo)

Example 5 with ACMContestRankVo

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;
}
Also used : ACMContestRankVo(top.hcode.hoj.pojo.vo.ACMContestRankVo) HashMap(java.util.HashMap) List(java.util.List) LinkedList(java.util.LinkedList) LinkedList(java.util.LinkedList)

Aggregations

ACMContestRankVo (top.hcode.hoj.pojo.vo.ACMContestRankVo)7 JSONObject (cn.hutool.json.JSONObject)2 QueryWrapper (com.baomidou.mybatisplus.core.conditions.query.QueryWrapper)2 HashMap (java.util.HashMap)2 LinkedList (java.util.LinkedList)2 List (java.util.List)2 Contest (top.hcode.hoj.pojo.entity.contest.Contest)2 ContestProblem (top.hcode.hoj.pojo.entity.contest.ContestProblem)2 ContestRecordVo (top.hcode.hoj.pojo.vo.ContestRecordVo)2 OIContestRankVo (top.hcode.hoj.pojo.vo.OIContestRankVo)2 UserRolesVo (top.hcode.hoj.pojo.vo.UserRolesVo)2 HttpSession (javax.servlet.http.HttpSession)1 RequiresAuthentication (org.apache.shiro.authz.annotation.RequiresAuthentication)1 Session (org.apache.shiro.session.Session)1 GetMapping (org.springframework.web.bind.annotation.GetMapping)1 StatusFailException (top.hcode.hoj.common.exception.StatusFailException)1 StatusForbiddenException (top.hcode.hoj.common.exception.StatusForbiddenException)1 CommonResult (top.hcode.hoj.common.result.CommonResult)1 UserInfo (top.hcode.hoj.pojo.entity.user.UserInfo)1