From 474f495e0cd0b3122818cb60bd07bf86b308ec3d Mon Sep 17 00:00:00 2001 From: undefined Date: Sun, 3 May 2020 18:23:08 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E7=A6=BB=E6=AF=94=E8=B5=9B=E8=B5=9B?= =?UTF-8?q?=E5=88=B6=E4=B8=BA=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/contest-rule-basic/acm.js | 111 +++++++++++++++++++++++ module/contest-rule-basic/hydro.json | 4 + module/contest-rule-basic/model.js | 6 ++ module/contest-rule-basic/oi.js | 66 ++++++++++++++ module/contest-rule-homework/homework.js | 95 +++++++++++++++++++ module/contest-rule-homework/hydro.json | 4 + module/contest-rule-homework/model.js | 4 + 7 files changed, 290 insertions(+) create mode 100644 module/contest-rule-basic/acm.js create mode 100644 module/contest-rule-basic/hydro.json create mode 100644 module/contest-rule-basic/model.js create mode 100644 module/contest-rule-basic/oi.js create mode 100644 module/contest-rule-homework/homework.js create mode 100644 module/contest-rule-homework/hydro.json create mode 100644 module/contest-rule-homework/model.js diff --git a/module/contest-rule-basic/acm.js b/module/contest-rule-basic/acm.js new file mode 100644 index 000000000..b6c8d55f8 --- /dev/null +++ b/module/contest-rule-basic/acm.js @@ -0,0 +1,111 @@ +module.exports = { + TEXT: 'ACM/ICPC', + check: () => { }, + showScoreboard: () => true, + showRecord: (tdoc, now) => now > tdoc.endAt, + stat: (tdoc, journal) => { + const naccept = {}; + const effective = {}; + const detail = []; + let accept = 0; + let time = 0; + for (const j in journal) { + if (tdoc.pids.includes(j.pid) + && !(effective.includes(j.pid) && effective[j.pid].accept)) { + effective[j.pid] = j; + } + if (!j.accept) naccept[j.pid]++; + } + function _time(jdoc) { + const real = jdoc.rid.generationTime - Math.floor(tdoc.begin_at / 1000); + const penalty = 20 * 60 * naccept[jdoc.pid]; + return real + penalty; + } + for (const j of effective) detail.push({ ...j, naccept: naccept[j.pid], time: _time(j) }); + for (const d of detail) { + accept += d.accept; + if (d.accept) time += d.time; + } + return { accept, time, detail }; + }, + scoreboard(isExport, _, tdoc, rankedTsdocs, udict, pdict) { + const columns = [ + { type: 'rank', value: _('Rank') }, + { type: 'user', value: _('User') }, + { type: 'solved_problems', value: _('Solved Problems') }, + ]; + if (isExport) { + columns.push({ type: 'total_time', value: _('Total Time (Seconds)') }); + columns.push({ type: 'total_time_str', value: _('Total Time') }); + } + for (const i in tdoc.pids) { + if (isExport) { + columns.push({ + type: 'problem_flag', + value: '#{0} {1}'.format(i + 1, pdict[tdoc.pids[i]].title), + }); + columns.push({ + type: 'problem_time', + value: '#{0} {1}'.format(i + 1, _('Time (Seconds)')), + }); + columns.push({ + type: 'problem_time_str', + value: '#{0} {1}'.format(i + 1, _('Time')), + }); + } else { + columns.push({ + type: 'problem_detail', + value: '#{0}'.format(i + 1), + raw: pdict[tdoc.pids[i]], + }); + } + } + const rows = [columns]; + for (const [rank, tsdoc] of rankedTsdocs) { + const tsddict = {}; + if (tdoc.detail) { for (const item of tsdoc.detail) tsddict[item.pid] = item; } + const row = []; + row.push( + { type: 'string', value: rank }, + { type: 'user', value: udict[tsdoc.uid].uname, raw: udict[tsdoc.uid] }, + { type: 'string', value: tsdoc.accept || 0 }, + ); + if (isExport) { + row.push( + { type: 'string', value: tsdoc.time || 0.0 }, + { type: 'string', value: tsdoc.time || 0.0 }, + ); + } + for (const pid of tdoc.pids) { + let rdoc; + let colAccepted; + let colTime; + let colTimeStr; + if ((tsddict[pid] || {}).accept) { + rdoc = tsddict[pid].rid; + colAccepted = _('Accepted'); + colTime = tsddict[pid].time; + colTimeStr = colTime; + } else { + rdoc = null; + colAccepted = '-'; + colTime = '-'; + colTimeStr = '-'; + } + if (isExport) { + row.push({ type: 'string', value: colAccepted }); + row.push({ type: 'string', value: colTime }); + row.push({ type: 'string', value: colTimeStr }); + } else { + row.push({ + type: 'record', + value: '{0}\n{1}'.format(colAccepted, colTimeStr), + raw: rdoc, + }); + } + rows.push(row); + } + } + return rows; + }, +}; diff --git a/module/contest-rule-basic/hydro.json b/module/contest-rule-basic/hydro.json new file mode 100644 index 000000000..1260c440b --- /dev/null +++ b/module/contest-rule-basic/hydro.json @@ -0,0 +1,4 @@ +{ + "name": "contest-rule-basic", + "version": "1.0.0" +} \ No newline at end of file diff --git a/module/contest-rule-basic/model.js b/module/contest-rule-basic/model.js new file mode 100644 index 000000000..77d995248 --- /dev/null +++ b/module/contest-rule-basic/model.js @@ -0,0 +1,6 @@ +const acm = require('./acm'); +const oi = require('./oi'); + +const rules = global.Hydro['model.contest'].RULES; +rules.oi = oi; +rules.acm = acm; diff --git a/module/contest-rule-basic/oi.js b/module/contest-rule-basic/oi.js new file mode 100644 index 000000000..1e8813cb1 --- /dev/null +++ b/module/contest-rule-basic/oi.js @@ -0,0 +1,66 @@ +/** + * @type {import('../../hydro/lib/rank')} + */ +const ranked = global.Hydro['lib.rank']; + +module.exports = { + TEXT: 'OI', + check: () => { }, + stat: (tdoc, journal) => { + const detail = {}; + let score = 0; + for (const j in journal) { + if (tdoc.pids.includes(j.pid)) { + detail[j.pid] = j; + score += j.score; + } + } + return { score, detail }; + }, + showScoreboard(tdoc, now) { + return now > tdoc.endAt; + }, + showRecord(tdoc, now) { + return now > tdoc.endAt; + }, + scoreboard(isExport, _, tdoc, rankedTsdocs, udict, pdict) { + const columns = [ + { type: 'rank', value: _('Rank') }, + { type: 'user', value: _('User') }, + { type: 'total_score', value: _('Total Score') }, + ]; + for (const i in tdoc.pids) { + if (isExport) { + columns.push({ + type: 'problem_score', + value: '#{0} {1}'.format(i + 1, pdict[tdoc.pids[i]].title), + }); + } else { + columns.push({ + type: 'problem_detail', + value: '#{0}'.format(i + 1), + raw: pdict[tdoc.pids[i]], + }); + } + } + const rows = [columns]; + for (const [rank, tsdoc] of rankedTsdocs) { + const tsddict = {}; + if (tsdoc.journal) { for (const item of tsdoc.journal) tsddict[item.pid] = item; } + const row = []; + row.push({ type: 'string', value: rank }); + row.push({ type: 'user', value: udict[tsdoc.uid].uname, raw: udict[tsdoc.uid] }); + row.push({ type: 'string', value: tsdoc.score || 0 }); + for (const pid of tdoc.pids) { + row.push({ + type: 'record', + value: (tsddict[pid] || {}).score || '-', + raw: (tsddict[pid] || {}).rid || null, + }); + } + rows.push(row); + } + return rows; + }, + rank: (tdocs) => ranked(tdocs, (a, b) => a.score === b.score), +}; diff --git a/module/contest-rule-homework/homework.js b/module/contest-rule-homework/homework.js new file mode 100644 index 000000000..7e24c5a26 --- /dev/null +++ b/module/contest-rule-homework/homework.js @@ -0,0 +1,95 @@ +module.exports = { + TEXT: 'Assignment', + check() {}, + stat(tdoc, journal) { + const effective = {}; + const detail = []; + let score = 0; + let time = 0; + for (const j in journal) { + if (tdoc.pids.includes(j.pid) + && !(effective.includes(j.pid) && effective[j.pid].accept)) { + effective[j.pid] = j; + } + } + const _time = (jdoc) => jdoc.rid.generationTime - Math.floor(tdoc.beginAt / 1000); + for (const j in effective) { + detail.push({ + ...effective[j], + time: _time(effective[j]), + }); + } + for (const d of detail) { + score += d.score; + time += d.time; + } + return { + score, time, detail, + }; + }, + scoreboard(isExport, _, tdoc, rankedTsdocs, udict, pdict) { + const columns = [ + { type: 'rank', value: _('Rank') }, + { type: 'user', value: _('User') }, + { type: 'display_name', value: _('Display Name') }, + { type: 'total_score', value: _('Score') }, + ]; + if (isExport) { + columns.push( + { type: 'total_original_score', value: _('Original Score') }, + { type: 'total_time', value: _('Total Time (Seconds)') }, + ); + } + columns.push({ type: 'total_time_str', value: _('Total Time') }); + for (const i in tdoc.pids) { + if (isExport) { + columns.push( + { type: 'problem_score', value: '#{0} {1}'.format(i + 1, pdict[tdoc.pids[i]].title) }, + { type: 'problem_original_score', value: '#{0} {1}'.format(i + 1, _('Original Score')) }, + { type: 'problem_time', value: '#{0} {1}'.format(i + 1, _('Time (Seconds)')) }, + { type: 'problem_time_str', value: '#{0} {1}'.format(i + 1, _('Time')) }, + ); + } else columns.push({ type: 'problem_detail', value: '#{0}'.format(i + 1), raw: pdict[tdoc.pids[i]] }); + } + const rows = [columns]; + for (const [rank, tsdoc] in rankedTsdocs) { + const tsddict = {}; + if (tsdoc.detail) { for (const item of tsdoc.detail) tsddict[item.pid] = item; } + const row = [ + { type: 'string', value: rank }, + { type: 'user', value: udict[tsdoc.uid].uname, raw: udict[tsdoc.uid] }, + { type: 'string', value: tsdoc.penalty_score || 0 }, + ]; + if (isExport) { + row.push( + { type: 'string', value: tsdoc.score || 0 }, + { type: 'string', value: tsdoc.time || 0.0 }, + ); + } + row.push({ type: 'string', value: tsdoc.time || 0 }); + for (const pid of tdoc.pids) { + const rdoc = (tsddict[pid] || {}).rid || null; + const colScore = (tsddict[pid] || {}).penalty_score || '-'; + const colOriginalScore = (tsddict[pid] || {}).score || '-'; + const colTime = (tsddict[pid] || {}).time || '-'; + const colTimeStr = colTime !== '-' ? colTime : '-'; + if (isExport) { + row.push( + { type: 'string', value: colScore }, + { type: 'string', value: colOriginalScore }, + { type: 'string', value: colTime }, + { type: 'string', value: colTimeStr }, + ); + } else { + row.push({ + type: 'record', + value: '{0} / {1}\n{2}'.format(colScore, colOriginalScore, colTimeStr), + raw: rdoc, + }); + } + } + rows.push(row); + } + return rows; + }, +}; diff --git a/module/contest-rule-homework/hydro.json b/module/contest-rule-homework/hydro.json new file mode 100644 index 000000000..f3eb3fee3 --- /dev/null +++ b/module/contest-rule-homework/hydro.json @@ -0,0 +1,4 @@ +{ + "name": "contest-rule-homework", + "version": "1.0.0" +} \ No newline at end of file diff --git a/module/contest-rule-homework/model.js b/module/contest-rule-homework/model.js new file mode 100644 index 000000000..f1ceb4975 --- /dev/null +++ b/module/contest-rule-homework/model.js @@ -0,0 +1,4 @@ +const homework = require('./homework'); + +const rules = global.Hydro['model.contest'].RULES; +rules.homework = homework;