diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index e3ab9f97e..e000488d9 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -1,7 +1,7 @@ { "name": "@hydrooj/hydrojudge", "bin": "bin/hydrojudge.js", - "version": "2.10.10", + "version": "2.10.11", "main": "package.json", "author": "undefined ", "repository": "https://github.com/hydro-dev/Hydro.git", diff --git a/packages/hydrojudge/setting.yaml b/packages/hydrojudge/setting.yaml index 636919017..8decf7d60 100644 --- a/packages/hydrojudge/setting.yaml +++ b/packages/hydrojudge/setting.yaml @@ -52,6 +52,11 @@ rate: name: rate desc: (?) default: 1 +rerun: + type: number + name: rerun + desc: Re-Run testcase if time-limit-exceeded (max per submission) + default: 0 disable: type: boolean name: disable diff --git a/packages/hydrojudge/src/config.ts b/packages/hydrojudge/src/config.ts index 8bab652fd..d97a1978f 100644 --- a/packages/hydrojudge/src/config.ts +++ b/packages/hydrojudge/src/config.ts @@ -20,6 +20,7 @@ let config = { testcases_max: 100, total_time_limit: 60, parallelism: 2, + rerun: 0, rate: 1, config: null, langs: null, diff --git a/packages/hydrojudge/src/judge/default.ts b/packages/hydrojudge/src/judge/default.ts index 6ff900d0f..06106b37e 100644 --- a/packages/hydrojudge/src/judge/default.ts +++ b/packages/hydrojudge/src/judge/default.ts @@ -17,7 +17,7 @@ const Score = { }; function judgeCase(c, sid: string) { - return async (ctx, ctxSubtask) => { + return async (ctx, ctxSubtask, runner?: Function) => { if (ctx.errored || (ctx.failed[sid] && ctxSubtask.subtask.type === 'min') || (ctxSubtask.subtask.type === 'max' && ctxSubtask.score === ctxSubtask.subtask.score) || ((ctxSubtask.subtask.if || []).filter((i: string) => ctx.failed[i]).length) @@ -86,6 +86,11 @@ function judgeCase(c, sid: string) { fs.remove(stdout), fs.remove(stderr), ]).catch(() => { /* Ignore file doesn't exist */ }); + if (runner && ctx.rerun && status === STATUS.STATUS_TIME_LIMIT_EXCEEDED) { + ctx.rerun--; + await runner(ctx, ctxSubtask); + return; + } ctxSubtask.score = Score[ctxSubtask.subtask.type](ctxSubtask.score, score); ctxSubtask.status = Math.max(ctxSubtask.status, status); if (ctxSubtask.status > STATUS.STATUS_ACCEPTED) ctx.failed[sid] = true; @@ -116,7 +121,8 @@ function judgeSubtask(subtask, sid: string) { }; const cases = []; for (const cid in subtask.cases) { - cases.push(ctx.queue.add(() => judgeCase(subtask.cases[cid], sid)(ctx, ctxSubtask))); + const runner = judgeCase(subtask.cases[cid], sid); + cases.push(ctx.queue.add(() => runner(ctx, ctxSubtask, runner))); } await Promise.all(cases).catch((e) => { ctx.errored = true; @@ -167,6 +173,7 @@ export const judge = async (ctx) => { ctx.total_score = 0; ctx.total_memory_usage_kb = 0; ctx.total_time_usage_ms = 0; + ctx.rerun = getConfig('rerun') || 0; ctx.queue = new Queue({ concurrency: getConfig('parallelism') }); ctx.failed = {}; for (const sid in ctx.config.subtasks) tasks.push(judgeSubtask(ctx.config.subtasks[sid], sid)(ctx));