From 0998982ec72e0a9afe4d9982dd03b24626020c14 Mon Sep 17 00:00:00 2001 From: panda Date: Thu, 2 Mar 2023 11:23:25 +0800 Subject: [PATCH] core&ui&judge: show subtask status & score (#524) --- packages/hydrojudge/src/flow.ts | 17 +++++++++---- packages/hydrooj/src/handler/judge.ts | 1 + packages/hydrooj/src/interface.ts | 7 ++++++ .../templates/record_detail_status.html | 25 +++++++++++++++++-- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/packages/hydrojudge/src/flow.ts b/packages/hydrojudge/src/flow.ts index f88fed74b..11463acf1 100644 --- a/packages/hydrojudge/src/flow.ts +++ b/packages/hydrojudge/src/flow.ts @@ -63,7 +63,10 @@ function judgeSubtask(subtask: NormalizedSubtask, sid: string, judgeCase: Task[' throw e; } ctx.total_status = Math.max(ctx.total_status, ctxSubtask.status); - return ctxSubtask.score; + return { + score: ctxSubtask.score, + status: ctxSubtask.status, + }; }; } @@ -100,10 +103,10 @@ export const runFlow = async (ctx: Context, task: Task) => { ctx.end({ nop: true }); } } else { - const scores = {}; + const infos = {}; await Promise.all(Object.entries(ctx.config.subtasks).map(async ([key, value]) => { const sid = value.id?.toString() || key; - scores[sid] = await judgeSubtask(value, sid, task.judgeCase)(ctx); + infos[sid] = await judgeSubtask(value, sid, task.judgeCase)(ctx); })); for (const [key, value] of Object.entries(ctx.config.subtasks)) { let effective = true; @@ -111,14 +114,18 @@ export const runFlow = async (ctx: Context, task: Task) => { for (const required of value.if || []) { if (ctx.failed[required.toString()]) effective = false; } - if (effective) ctx.total_score += scores[sid]; - else ctx.failed[sid] = true; + if (effective) ctx.total_score += infos[sid].score; + else { + ctx.failed[sid] = true; + delete infos[sid]; + } } ctx.end({ status: ctx.total_status, score: ctx.total_score, time: Math.floor(ctx.total_time * 1000000) / 1000000, memory: ctx.total_memory, + subtasks: infos, }); } ctx.stat.done = new Date(); diff --git a/packages/hydrooj/src/handler/judge.ts b/packages/hydrooj/src/handler/judge.ts index 5f2c12d86..3e025468d 100644 --- a/packages/hydrooj/src/handler/judge.ts +++ b/packages/hydrooj/src/handler/judge.ts @@ -59,6 +59,7 @@ function processPayload(rdoc: RecordDoc, body: Partial) { if (Number.isFinite(body.time)) $set.time = body.time; if (Number.isFinite(body.memory)) $set.memory = body.memory; if (body.progress !== undefined) $set.progress = body.progress; + if (body.subtasks) $set.subtasks = body.subtasks; return { $set, $push }; } diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index e1d0d880a..60ee9c8e5 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -331,6 +331,7 @@ export interface RecordDoc { contest?: ObjectId; files?: Record + subtasks?: Record; } export interface JudgeMeta { @@ -547,6 +548,11 @@ export interface JudgeMessage { stack?: string; } +export interface SubtaskResult { + score: number; + status: number; +} + export interface JudgeResultBody { key: string; domainId: string; @@ -565,6 +571,7 @@ export interface JudgeResultBody { message?: string | JudgeMessage; compilerText?: string; nop?: boolean; + subtasks?: Record; } export interface Task { diff --git a/packages/ui-default/templates/record_detail_status.html b/packages/ui-default/templates/record_detail_status.html index 3a6f528b2..e170f61cc 100644 --- a/packages/ui-default/templates/record_detail_status.html +++ b/packages/ui-default/templates/record_detail_status.html @@ -19,6 +19,7 @@ {% endif %} {% if rdoc.testCases.length %} + {% set _key = 'id' if rdoc.testCases|groupby('subtaskId')|length == 1 else 'subtaskId' %}
@@ -30,19 +31,34 @@ - + - {% set _key = 'id' if rdoc.testCases|groupby('subtaskId')|length == 1 else 'subtaskId' %} {%- for subtaskId, rcdocs in rdoc.testCases|sort(false,false,_key)|groupby(_key) -%} {% if rcdocs.length > 1 %} + {% if rdoc.subtasks %} + + + + {% endif %} {% endif %} {%- for rcdoc in rcdocs|sort(false,false,'id') -%} @@ -55,6 +71,11 @@ {{ model.builtin.STATUS_TEXTS[rcdoc['status']] }} + {% if rcdocs.length == 1 and _key != 'id' %} + + {{ rdoc.subtasks[subtaskId]['score']|default(0) }} + + {% endif %} {{ formatJudgeTexts([rcdoc.message]) if rcdoc.message else '' }}
#{{ _('Status') }} + {{ _('Status') }} + {% if rdoc.subtasks and _key != 'id' %} + {{ _('Score') }} + {% endif %} + {{ _('Time Cost') }} {{ _('Memory Cost') }}
#{{ subtaskId|int|default(1) }} + + + {{ model.builtin.STATUS_TEXTS[rcdocs[0]['status']] }} + + {{ rdoc.subtasks[subtaskId]['score']|default(0) }} +
{% if rcdoc['status'] == STATUS.STATUS_TIME_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_MEMORY_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_OUTPUT_LIMIT_EXCEEDED %}≥{% endif %}{{ rcdoc.time|round|int }}ms