core&ui&judge: show subtask status & score (#524)

This commit is contained in:
panda authored and GitHub committed 2023-03-02 11:23:25 +08:00
1 parent 26a39501c2
commit 0998982ec7
4 files changed
+43 -7

No files matched your search

+12 -5
View File
@@ -63,7 +63,10 @@ function judgeSubtask(subtask: NormalizedSubtask, sid: string, judgeCase: Task['
throw e; throw e;
} }
ctx.total_status = Math.max(ctx.total_status, ctxSubtask.status); 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 }); ctx.end({ nop: true });
} }
} else { } else {
const scores = {}; const infos = {};
await Promise.all(Object.entries(ctx.config.subtasks).map(async ([key, value]) => { await Promise.all(Object.entries(ctx.config.subtasks).map(async ([key, value]) => {
const sid = value.id?.toString() || key; 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)) { for (const [key, value] of Object.entries(ctx.config.subtasks)) {
let effective = true; let effective = true;
@@ -111,14 +114,18 @@ export const runFlow = async (ctx: Context, task: Task) => {
for (const required of value.if || []) { for (const required of value.if || []) {
if (ctx.failed[required.toString()]) effective = false; if (ctx.failed[required.toString()]) effective = false;
} }
if (effective) ctx.total_score += scores[sid]; if (effective) ctx.total_score += infos[sid].score;
else ctx.failed[sid] = true; else {
ctx.failed[sid] = true;
delete infos[sid];
}
} }
ctx.end({ ctx.end({
status: ctx.total_status, status: ctx.total_status,
score: ctx.total_score, score: ctx.total_score,
time: Math.floor(ctx.total_time * 1000000) / 1000000, time: Math.floor(ctx.total_time * 1000000) / 1000000,
memory: ctx.total_memory, memory: ctx.total_memory,
subtasks: infos,
}); });
} }
ctx.stat.done = new Date(); ctx.stat.done = new Date();
+1
View File
@@ -59,6 +59,7 @@ function processPayload(rdoc: RecordDoc, body: Partial<JudgeResultBody>) {
if (Number.isFinite(body.time)) $set.time = body.time; if (Number.isFinite(body.time)) $set.time = body.time;
if (Number.isFinite(body.memory)) $set.memory = body.memory; if (Number.isFinite(body.memory)) $set.memory = body.memory;
if (body.progress !== undefined) $set.progress = body.progress; if (body.progress !== undefined) $set.progress = body.progress;
if (body.subtasks) $set.subtasks = body.subtasks;
return { $set, $push }; return { $set, $push };
} }
+7
View File
@@ -331,6 +331,7 @@ export interface RecordDoc {
contest?: ObjectId; contest?: ObjectId;
files?: Record<string, string> files?: Record<string, string>
subtasks?: Record<number, SubtaskResult>;
} }
export interface JudgeMeta { export interface JudgeMeta {
@@ -547,6 +548,11 @@ export interface JudgeMessage {
stack?: string; stack?: string;
} }
export interface SubtaskResult {
score: number;
status: number;
}
export interface JudgeResultBody { export interface JudgeResultBody {
key: string; key: string;
domainId: string; domainId: string;
@@ -565,6 +571,7 @@ export interface JudgeResultBody {
message?: string | JudgeMessage; message?: string | JudgeMessage;
compilerText?: string; compilerText?: string;
nop?: boolean; nop?: boolean;
subtasks?: Record<number, SubtaskResult>;
} }
export interface Task { export interface Task {
@@ -19,6 +19,7 @@
</div> </div>
{% endif %} {% endif %}
{% if rdoc.testCases.length %} {% if rdoc.testCases.length %}
{% set _key = 'id' if rdoc.testCases|groupby('subtaskId')|length == 1 else 'subtaskId' %}
<div class="section__body no-padding"> <div class="section__body no-padding">
<table class="data-table record_detail__table"> <table class="data-table record_detail__table">
<colgroup> <colgroup>
@@ -30,19 +31,34 @@
<thead> <thead>
<tr> <tr>
<th class="col--case record-status--border">#</th> <th class="col--case record-status--border">#</th>
<th class="col--status">{{ _('Status') }}</th> <th class="col--status">
{{ _('Status') }}
{% if rdoc.subtasks and _key != 'id' %}
<span class="float-right">{{ _('Score') }}</span>
{% endif %}
</th>
<th class="col--time">{{ _('Time Cost') }}</th> <th class="col--time">{{ _('Time Cost') }}</th>
<th class="col--memory">{{ _('Memory Cost') }}</th> <th class="col--memory">{{ _('Memory Cost') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% set _key = 'id' if rdoc.testCases|groupby('subtaskId')|length == 1 else 'subtaskId' %}
{%- for subtaskId, rcdocs in rdoc.testCases|sort(false,false,_key)|groupby(_key) -%} {%- for subtaskId, rcdocs in rdoc.testCases|sort(false,false,_key)|groupby(_key) -%}
{% if rcdocs.length > 1 %} {% if rcdocs.length > 1 %}
<tr class="subtask"> <tr class="subtask">
<td class="col--case"> <td class="col--case">
#{{ subtaskId|int|default(1) }} #{{ subtaskId|int|default(1) }}
</td> </td>
{% if rdoc.subtasks %}
<td class="col--status">
<span class="icon record-status--icon {{ model.builtin.STATUS_CODES[rdoc.subtasks[subtaskId]['status']] }}"></span>
<span class="record-status--text {{ model.builtin.STATUS_CODES[rdoc.subtasks[subtaskId]['status']] }}">
{{ model.builtin.STATUS_TEXTS[rcdocs[0]['status']] }}
</span>
<span class="float-right record-status--text {{ model.builtin.STATUS_CODES[rdoc.subtasks[subtaskId]['status']] }}">{{ rdoc.subtasks[subtaskId]['score']|default(0) }}</span>
</td>
<td class="col--time"></td>
<td class="col--memory"></td>
{% endif %}
</tr> </tr>
{% endif %} {% endif %}
{%- for rcdoc in rcdocs|sort(false,false,'id') -%} {%- for rcdoc in rcdocs|sort(false,false,'id') -%}
@@ -55,6 +71,11 @@
<span class="record-status--text {{ model.builtin.STATUS_CODES[rcdoc['status']] }}"> <span class="record-status--text {{ model.builtin.STATUS_CODES[rcdoc['status']] }}">
{{ model.builtin.STATUS_TEXTS[rcdoc['status']] }} {{ model.builtin.STATUS_TEXTS[rcdoc['status']] }}
</span> </span>
{% if rcdocs.length == 1 and _key != 'id' %}
<span class="float-right record-status--text {{ model.builtin.STATUS_CODES[rdoc.subtasks[subtaskId]['status']] }}">
{{ rdoc.subtasks[subtaskId]['score']|default(0) }}
</span>
{% endif %}
<span>{{ formatJudgeTexts([rcdoc.message]) if rcdoc.message else '' }}</span> <span>{{ formatJudgeTexts([rcdoc.message]) if rcdoc.message else '' }}</span>
</td> </td>
<td class="col--time">{% if rcdoc['status'] == STATUS.STATUS_TIME_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_MEMORY_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rcdoc.time|round|int }}ms</td> <td class="col--time">{% if rcdoc['status'] == STATUS.STATUS_TIME_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_MEMORY_LIMIT_EXCEEDED or rcdoc['status'] == STATUS.STATUS_OUTPUT_LIMIT_EXCEEDED %}&ge;{% endif %}{{ rcdoc.time|round|int }}ms</td>