mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
89 lines
3.5 KiB
TypeScript
89 lines
3.5 KiB
TypeScript
import { NormalizedCase, STATUS } from '@hydrooj/common';
|
|
import checkers from '../checkers';
|
|
import { runFlow } from '../flow';
|
|
import { del, runQueued } from '../sandbox';
|
|
import signals from '../signals';
|
|
import { Context, ContextSubTask } from './interface';
|
|
|
|
function judgeCase(c: NormalizedCase) {
|
|
return async (ctx: Context, ctxSubtask: ContextSubTask, runner?: Function) => {
|
|
const { address_space_limit, process_limit } = ctx.session.getLang(ctx.lang);
|
|
const res = await runQueued(
|
|
ctx.execute.execute,
|
|
{
|
|
stdin: { src: c.input },
|
|
copyIn: ctx.execute.copyIn,
|
|
filename: ctx.config.filename,
|
|
time: c.time,
|
|
memory: c.memory,
|
|
cacheStdoutAndStderr: true,
|
|
addressSpaceLimit: address_space_limit,
|
|
processLimit: process_limit,
|
|
},
|
|
`judgeCase[${c.id}]<${ctx.rid}>`,
|
|
);
|
|
const {
|
|
code, signalled, time, memory, fileIds,
|
|
} = res;
|
|
let { status } = res;
|
|
let message: any = '';
|
|
let score = 0;
|
|
const detail = ctx.config.detail ?? true;
|
|
if (status === STATUS.STATUS_ACCEPTED) {
|
|
if (time > c.time) {
|
|
status = STATUS.STATUS_TIME_LIMIT_EXCEEDED;
|
|
} else if (memory > c.memory * 1024) {
|
|
status = STATUS.STATUS_MEMORY_LIMIT_EXCEEDED;
|
|
} else {
|
|
({ status, score, message } = await checkers[ctx.config.checker_type]({
|
|
execute: ctx.checker.execute,
|
|
copyIn: ctx.checker.copyIn || {},
|
|
input: { src: c.input },
|
|
output: { src: c.output },
|
|
user_stdout: fileIds.stdout ? { fileId: fileIds.stdout } : { content: '' },
|
|
user_stderr: fileIds.stderr ? { fileId: fileIds.stderr } : { content: '' },
|
|
score: c.score,
|
|
detail,
|
|
env: {
|
|
...ctx.env,
|
|
HYDRO_TESTCASE: c.id.toString(),
|
|
HYDRO_TIME_USAGE: time.toString(),
|
|
HYDRO_MEMORY_USAGE: Math.floor(memory / 1024).toString(),
|
|
},
|
|
}));
|
|
}
|
|
} else if (status === STATUS.STATUS_RUNTIME_ERROR && code && detail) {
|
|
if (code < 32 && signalled) message = signals[code];
|
|
else message = { message: 'Your program returned {0}.', params: [code] };
|
|
}
|
|
await Promise.allSettled(Object.values(res.fileIds).map((id) => del(id)));
|
|
if (runner && ctx.rerun && c.time <= 5000 && status === STATUS.STATUS_TIME_LIMIT_EXCEEDED) {
|
|
ctx.rerun--;
|
|
return await runner(ctx, ctxSubtask);
|
|
}
|
|
if (!ctx.request.rejudged && !ctx.analysis && [STATUS.STATUS_WRONG_ANSWER, STATUS.STATUS_RUNTIME_ERROR].includes(status)) {
|
|
ctx.analysis = true;
|
|
await ctx.runAnalysis(ctx.execute, { src: c.input });
|
|
}
|
|
return {
|
|
id: c.id,
|
|
subtaskId: ctxSubtask.subtask.id,
|
|
status,
|
|
score,
|
|
time,
|
|
memory,
|
|
message,
|
|
};
|
|
};
|
|
}
|
|
|
|
export const judge = async (ctx: Context) => await runFlow(ctx, {
|
|
compile: async () => {
|
|
[ctx.execute, ctx.checker] = await Promise.all([
|
|
ctx.compile(ctx.lang, ctx.code),
|
|
ctx.compileLocalFile('checker', ctx.config.checker, ctx.config.checker_type),
|
|
]);
|
|
},
|
|
judgeCase,
|
|
});
|