judge: subtasks dep (#35)

pull/39/head
undefined 4 years ago
parent 8c86923869
commit 88a9394836

@ -1,7 +1,7 @@
{ {
"name": "@hydrooj/hydrojudge", "name": "@hydrooj/hydrojudge",
"bin": "bin/hydrojudge.js", "bin": "bin/hydrojudge.js",
"version": "2.1.28", "version": "2.1.29",
"main": "package.json", "main": "package.json",
"author": "masnn", "author": "masnn",
"repository": "https://github.com/hydro-dev/Hydro.git", "repository": "https://github.com/hydro-dev/Hydro.git",

@ -253,6 +253,7 @@ export async function readYamlCases(folder: string, cfg: Dictionary<any> = {}, a
} }
config.subtasks.push({ config.subtasks.push({
score: parseInt(subtask.score, 10), score: parseInt(subtask.score, 10),
if: subtask.if || [],
cases, cases,
time_limit_ms: parseTimeMS(subtask.time || cfg.time), time_limit_ms: parseTimeMS(subtask.time || cfg.time),
memory_limit_mb: parseMemoryMB(subtask.memory || cfg.time), memory_limit_mb: parseMemoryMB(subtask.memory || cfg.time),

@ -16,10 +16,11 @@ const Score = {
min: Math.min, min: Math.min,
}; };
function judgeCase(c) { function judgeCase(c, sid) {
return async (ctx, ctxSubtask) => { return async (ctx, ctxSubtask) => {
if ((ctxSubtask.subtask.type === 'min' && !ctxSubtask.score) if ((ctxSubtask.subtask.type === 'min' && !ctxSubtask.score)
|| (ctxSubtask.subtask.type === 'max' && ctxSubtask.score === ctxSubtask.subtask.score)) { || (ctxSubtask.subtask.type === 'max' && ctxSubtask.score === ctxSubtask.subtask.score)
|| (ctxSubtask.subtask.if && ctx.failed[sid])) {
ctx.next({ ctx.next({
status: STATUS.STATUS_JUDGING, status: STATUS.STATUS_JUDGING,
case: { case: {
@ -99,7 +100,7 @@ function judgeCase(c) {
}; };
} }
function judgeSubtask(subtask) { function judgeSubtask(subtask, sid) {
return async (ctx) => { return async (ctx) => {
subtask.type = subtask.type || 'min'; subtask.type = subtask.type || 'min';
const ctxSubtask = { const ctxSubtask = {
@ -111,11 +112,12 @@ function judgeSubtask(subtask) {
}; };
const cases = []; const cases = [];
for (const cid in subtask.cases) { for (const cid in subtask.cases) {
cases.push(ctx.queue.add(() => judgeCase(subtask.cases[cid])(ctx, ctxSubtask))); cases.push(ctx.queue.add(() => judgeCase(subtask.cases[cid], sid)(ctx, ctxSubtask)));
} }
await Promise.all(cases); await Promise.all(cases);
ctx.total_status = Math.max(ctx.total_status, ctxSubtask.status); ctx.total_status = Math.max(ctx.total_status, ctxSubtask.status);
ctx.total_score += ctxSubtask.score; if (ctx.total_status !== STATUS.STATUS_ACCEPTED) ctx.failed[sid] = true;
return ctxSubtask.score;
}; };
} }
@ -158,10 +160,17 @@ export const judge = async (ctx) => {
ctx.total_score = 0; ctx.total_score = 0;
ctx.total_memory_usage_kb = 0; ctx.total_memory_usage_kb = 0;
ctx.total_time_usage_ms = 0; ctx.total_time_usage_ms = 0;
// sandbox seems cannot handle concurrent tasks with output file correctly
ctx.queue = new Queue({ concurrency: ctx.config.concurrency || 2 }); ctx.queue = new Queue({ concurrency: ctx.config.concurrency || 2 });
for (const sid in ctx.config.subtasks) tasks.push(judgeSubtask(ctx.config.subtasks[sid])(ctx)); ctx.failed = {};
await Promise.all(tasks); for (const sid in ctx.config.subtasks) tasks.push(judgeSubtask(ctx.config.subtasks[sid], sid)(ctx));
const scores = await Promise.all(tasks);
for (const sid in ctx.config.subtasks) {
let effective = true;
for (const required of ctx.config.subtasks[sid].if || []) {
if (ctx.failed[required]) effective = false;
}
if (effective) ctx.total_score += scores[sid];
}
ctx.stat.done = new Date(); ctx.stat.done = new Date();
if (argv.debug) ctx.next({ message: JSON.stringify(ctx.stat) }); if (argv.debug) ctx.next({ message: JSON.stringify(ctx.stat) });
ctx.end({ ctx.end({

Loading…
Cancel
Save