From 3ee29da3bda8eb4186e9ace2f5aa592218d45bc3 Mon Sep 17 00:00:00 2001 From: panda Date: Sun, 8 Jan 2023 22:52:09 +0800 Subject: [PATCH] core: contest: add ledo contest rule (#481) --- packages/hydrooj/locales/zh.yaml | 1 + packages/hydrooj/src/model/contest.ts | 72 ++++++++++++++++++- packages/ui-default/common/variables.inc.styl | 1 + packages/ui-default/locales/zh.yaml | 1 + .../ui-default/templates/contest_main.html | 6 +- .../templates/contest_scoreboard.html | 2 +- .../templates/partials/contest_sidebar.html | 2 +- .../templates/partials/homepage/contest.html | 2 +- packages/ui-default/templates/wiki_help.html | 4 ++ 9 files changed, 84 insertions(+), 7 deletions(-) diff --git a/packages/hydrooj/locales/zh.yaml b/packages/hydrooj/locales/zh.yaml index 76a20b1b4..dc1c0cb28 100644 --- a/packages/hydrooj/locales/zh.yaml +++ b/packages/hydrooj/locales/zh.yaml @@ -30,6 +30,7 @@ __langname: 简体中文 'Join {0}': '加入 {0}' 'No': 否 'Note: Problem title may not be hidden.': 注意:题目标题可能不会被隐藏。 +'Original score: {0}': '原得分: {0}' 'Role {1} already exists in domain {0}.': '域 {0} 中已存在角色 {1}。' 'Solved {0} problems, RP: {1} (No. {2})': '解决了 {0} 道题目,RP: {1} (No. {2})' 'The value `{1}` of {0} already exists.': '{0} 的值 `{1}` 已经存在。' diff --git a/packages/hydrooj/src/model/contest.ts b/packages/hydrooj/src/model/contest.ts index 09c0e64ea..703380458 100644 --- a/packages/hydrooj/src/model/contest.ts +++ b/packages/hydrooj/src/model/contest.ts @@ -356,6 +356,76 @@ const ioi = buildContestRule({ showScoreboard: (tdoc, now) => now > tdoc.beginAt, }, oi); +const ledo = buildContestRule({ + TEXT: 'Ledo', + check: () => { }, + submitAfterAccept: false, + showScoreboard: (tdoc, now) => now > tdoc.beginAt, + showSelfRecord: () => true, + showRecord: (tdoc, now) => now > tdoc.endAt, + stat(tdoc, journal) { + const ntry = Counter(); + const detail = {}; + for (const j of journal.filter((i) => tdoc.pids.includes(i.pid))) { + const vaild = ![STATUS.STATUS_COMPILE_ERROR, STATUS.STATUS_FORMAT_ERROR].includes(j.status); + if (vaild) ntry[j.pid]++; + const penaltyScore = vaild ? Math.round(Math.max(0.7, 0.95 ** (ntry[j.pid] - 1)) * j.score) : 0; + if (!detail[j.pid] || detail[j.pid].penaltyScore < penaltyScore) { + detail[j.pid] = { + ...j, + penaltyScore, + ntry: ntry[j.pid] - 1, + }; + } + } + let score = 0; + let originalScore = 0; + for (const pid of tdoc.pids) { + if (!detail[pid]) continue; + score += detail[pid].penaltyScore; + originalScore += detail[pid].score; + } + return { + score, originalScore, detail, + }; + }, + async scoreboardRow(isExport, _, tdoc, pdict, udoc, rank, tsdoc, meta) { + const tsddict = tsdoc.detail || {}; + const row: ScoreboardRow = [ + { type: 'rank', value: rank.toString() }, + { type: 'user', value: udoc.uname, raw: tsdoc.uid }, + ]; + if (isExport) { + row.push({ type: 'email', value: udoc.mail }); + row.push({ type: 'string', value: udoc.school || '' }); + row.push({ type: 'string', value: udoc.displayName || '' }); + row.push({ type: 'string', value: udoc.studentId || '' }); + } + row.push({ + type: 'total_score', + value: tsdoc.score || 0, + hover: tsdoc.score !== tsdoc.originalScore ? _('Original score: {0}').format(tsdoc.originalScore) : '', + }); + for (const s of tsdoc.journal || []) { + if (!pdict[s.pid]) continue; + pdict[s.pid].nSubmit++; + if (s.status === STATUS.STATUS_ACCEPTED) pdict[s.pid].nAccept++; + } + for (const pid of tdoc.pids) { + row.push({ + type: 'record', + value: tsddict[pid]?.penaltyScore || '', + hover: tsddict[pid]?.ntry ? `-${tsddict[pid].ntry} (${Math.round(Math.max(0.7, 0.95 ** tsddict[pid].ntry) * 100)}%)` : '', + raw: tsddict[pid]?.rid, + style: tsddict[pid]?.status === STATUS.STATUS_ACCEPTED && tsddict[pid]?.rid.generationTime === meta?.first?.[pid] + ? 'background-color: rgb(217, 240, 199);' + : undefined, + }); + } + return row; + }, +}, oi); + const homework = buildContestRule({ TEXT: 'Assignment', hidden: true, @@ -506,7 +576,7 @@ const homework = buildContestRule({ }); export const RULES: ContestRules = { - acm, oi, homework, ioi, + acm, oi, homework, ioi, ledo, }; function _getStatusJournal(tsdoc) { diff --git a/packages/ui-default/common/variables.inc.styl b/packages/ui-default/common/variables.inc.styl index f72f7fd62..d932d8570 100644 --- a/packages/ui-default/common/variables.inc.styl +++ b/packages/ui-default/common/variables.inc.styl @@ -254,5 +254,6 @@ $contest-color = { 'acm': #6BB67A, 'oi': #F5C735, 'ioi': #2E9AFE, + 'ledo': #8076A3, 'homework': #FFCDCD, } diff --git a/packages/ui-default/locales/zh.yaml b/packages/ui-default/locales/zh.yaml index 7a1078569..20e587c7b 100644 --- a/packages/ui-default/locales/zh.yaml +++ b/packages/ui-default/locales/zh.yaml @@ -461,6 +461,7 @@ Last Update At: 最后活动时间 LaTeX Expressions: LaTeX 表达式 Learn More: 了解更多 Leave blank to use numeric pid.: 留空来使用数字题号。 +Ledo: 乐多 Light: 亮色 Limit user to finish contest within N hours: 限制用户在N小时内完成比赛 Limitations: 限制 diff --git a/packages/ui-default/templates/contest_main.html b/packages/ui-default/templates/contest_main.html index a4d28b33d..c2d0597a0 100644 --- a/packages/ui-default/templates/contest_main.html +++ b/packages/ui-default/templates/contest_main.html @@ -12,7 +12,7 @@