You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/packages/hydrojudge/src/checkers.ts

188 lines
6.3 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* eslint-disable no-template-curly-in-string */
import fs from 'fs-extra';
import * as STATUS from './status';
import { run } from './sandbox';
import { SystemError } from './error';
interface CheckResult {
status: number,
score: number,
message: string,
code?: number,
}
type Checker = (config: any) => Promise<CheckResult>;
const checkers: Record<string, Checker> = {
async default(config) {
const { stdout } = await run('/usr/bin/diff -BZ usrout stdout', {
copyIn: {
usrout: { src: config.user_stdout },
stdout: { src: config.output },
...config.copyIn,
},
});
let status;
let message = '';
if (stdout) {
status = STATUS.STATUS_WRONG_ANSWER;
if (config.detail) {
try {
const pt = stdout.split('---');
const u = pt[0].split('\n')[1];
let usr = u.substr(2, u.length - 2).trim().split(' ');
const t = pt[1].split('\n')[1];
let std = t.substr(2, t.length - 2).trim().split(' ');
if (usr.length < std.length) message = '标准输出比选手输出长。';
else if (usr.length > std.length) message = '选手输出比标准输出长。';
else {
for (const i in usr) {
if (usr[i] !== std[i]) {
usr = usr[i];
std = std[i];
break;
}
}
if (usr.length > 20) usr = `${usr.substring(0, 16)}...`;
if (std.length > 20) std = `${std.substring(0, 16)}...`;
message = `读取到 ${usr} ,应为 ${std}`;
}
} catch (e) {
message = stdout.substring(0, stdout.length - 1 <= 30 ? stdout.length - 1 : 30);
}
}
} else status = STATUS.STATUS_ACCEPTED;
return {
score: status === STATUS.STATUS_ACCEPTED ? config.score : 0,
status,
message,
};
},
/*
* argv[1]:输入
* argv[2]:标准输出
* argv[3]:选手输出
* exit code返回判断结果
*/
async hustoj(config) {
const { code, stdout } = await run('${dir}/checker input stdout usrout', {
copyIn: {
usrout: { src: config.user_stdout },
stdout: { src: config.output },
input: { src: config.input },
...config.copyIn,
},
});
const status = code ? STATUS.STATUS_WRONG_ANSWER : STATUS.STATUS_ACCEPTED;
const message = (await fs.readFile(stdout)).toString();
return {
status,
score: status === STATUS.STATUS_ACCEPTED ? config.score : 0,
message,
};
},
/*
* argv[1]:输入文件
* argv[2]:选手输出文件
* argv[3]:标准输出文件
* argv[4]:单个测试点分值
* argv[5]:输出最终得分的文件
* argv[6]:输出错误报告的文件
*/
async lemon(config) {
const { files } = await run(`\${dir}/checker input usrout stdout ${config.score} score message`, {
copyIn: {
usrout: { src: config.user_stdout },
stdout: { src: config.output },
input: { src: config.input },
...config.copyIn,
},
copyOut: ['score', 'message'],
});
const { message } = files;
const score = parseInt(files.score, 10);
return {
score,
message,
status: score === config.score
? STATUS.STATUS_ACCEPTED
: STATUS.STATUS_WRONG_ANSWER,
};
},
/*
* argv[1]:输入
* argv[2]:选手输出
* exit code返回判断结果
*/
async qduoj(config) {
const { status, stdout } = await run('${dir}/checker input usrout', {
copyIn: {
usrout: { src: config.user_stdout },
input: { src: config.input },
...config.copyIn,
},
});
const st = (status === STATUS.STATUS_ACCEPTED)
? STATUS.STATUS_ACCEPTED : STATUS.STATUS_WRONG_ANSWER;
return {
status: st,
score: (status === STATUS.STATUS_ACCEPTED) ? config.score : 0,
message: stdout,
};
},
/*
* in输入
* user_out选手输出
* answer标准输出
* code选手代码
* stdout输出最终得分
* stderr输出错误报告
*/
async syzoj(config) {
// eslint-disable-next-line prefer-const
let { status, stdout, stderr } = await run('${dir}/checker', {
copyIn: {
in: { src: config.input },
user_out: { src: config.user_stdout },
answer: { src: config.output },
code: { content: config.code },
...config.copyIn,
},
});
if (status !== STATUS.STATUS_ACCEPTED) throw new SystemError('Checker returned a non-zero value', [status]);
const score = parseInt(stdout, 10);
status = score === config.score ? STATUS.STATUS_ACCEPTED : STATUS.STATUS_WRONG_ANSWER;
return { status, score, message: stderr };
},
async testlib(config) {
console.log(config);
const { stderr, status } = await run('${dir}/checker ${dir}/in ${dir}/user_out ${dir}/answer', {
copyIn: {
in: { src: config.input },
user_out: { src: config.user_stdout },
answer: { src: config.output },
...config.copyIn,
},
});
if (status === STATUS.STATUS_SYSTEM_ERROR) {
return {
status: STATUS.STATUS_SYSTEM_ERROR,
score: 0,
message: '',
};
}
return {
status: stderr.startsWith('ok ') ? STATUS.STATUS_ACCEPTED : STATUS.STATUS_WRONG_ANSWER,
score: stderr.startsWith('ok ') ? config.score : 0,
message: stderr.split(' ').splice(1).join(' '),
};
},
};
export = checkers;