mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
judge: replace diff binary (fix #965)
This commit is contained in:
1 file changed
+54
-48
@@ -23,18 +23,15 @@ type Checker = (config: CheckConfig) => Promise<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
function parseDiffMsg(msg: string) {
|
function parseDiffMsg(msg: string) {
|
||||||
|
msg = msg.trim();
|
||||||
try {
|
try {
|
||||||
// Note: we only handle first diff
|
if (!msg) return '';
|
||||||
const desc = msg.split('\n')[0];
|
if (!msg.startsWith('L=')) throw new Error();
|
||||||
if (desc.includes('d')) return 'User output longer than standard answer.';
|
const [meta, u, t] = msg.split('\n');
|
||||||
if (desc.includes('a')) return 'Standard answer longer than user output.';
|
const lineNum = +meta.split('L=')[1];
|
||||||
const pt = msg.split('---');
|
|
||||||
// Get the first different line
|
|
||||||
const u = pt[0].split('\n')[1];
|
|
||||||
const t = pt[1].split('\n')[1];
|
|
||||||
// Split by token
|
// Split by token
|
||||||
const usr = u.substring(2).trim().split(' ');
|
const usr = u.trim().split(' ');
|
||||||
const std = t.substring(2).trim().split(' ');
|
const std = t.trim().split(' ');
|
||||||
if (std.every((x) => !Number.isNaN(+x))) {
|
if (std.every((x) => !Number.isNaN(+x))) {
|
||||||
// Number mode, report length not match
|
// Number mode, report length not match
|
||||||
if (usr.length > std.length) return 'User output longer than standard answer.';
|
if (usr.length > std.length) return 'User output longer than standard answer.';
|
||||||
@@ -44,7 +41,7 @@ function parseDiffMsg(msg: string) {
|
|||||||
if (usr[i] === std[i]) continue;
|
if (usr[i] === std[i]) continue;
|
||||||
const usrString = usr[i].length > 20 ? `${usr[i].substring(0, 16)}...` : usr[i];
|
const usrString = usr[i].length > 20 ? `${usr[i].substring(0, 16)}...` : usr[i];
|
||||||
const stdString = std[i].length > 20 ? `${std[i].substring(0, 16)}...` : std[i];
|
const stdString = std[i].length > 20 ? `${std[i].substring(0, 16)}...` : std[i];
|
||||||
return { message: 'Read {0}, expect {1}.', params: [usrString, stdString] };
|
return { message: 'On line {0}: Read {1}, expect {2}.', params: [lineNum, usrString, stdString] };
|
||||||
}
|
}
|
||||||
throw new Error();
|
throw new Error();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -52,44 +49,53 @@ function parseDiffMsg(msg: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkers: Record<string, Checker> = new Proxy({
|
const compareSh = `#!/bin/bash
|
||||||
async default(config) {
|
set -e
|
||||||
const { stdout } = await runQueued('/usr/bin/diff -BZ usrout answer', {
|
usrout=usrout
|
||||||
copyIn: {
|
answer=answer
|
||||||
usrout: config.user_stdout,
|
if [ "$1" = "BZ" ]; then
|
||||||
answer: config.output,
|
cat $usrout | awk '{sub(/[ \\t]+$/, ""); print $0;}' | awk '/^$/{n=n RS}; /./{printf "%s",n; n=""; print}' >usrout.processed
|
||||||
...config.copyIn,
|
usrout=usrout.processed
|
||||||
},
|
cat $answer | awk '{sub(/[ \\t]+$/, ""); print $0;}' | awk '/^$/{n=n RS}; /./{printf "%s",n; n=""; print}' >answer.processed
|
||||||
});
|
answer=answer.processed
|
||||||
let status: number;
|
fi
|
||||||
let message: any = '';
|
linenum=$(cmp $usrout $answer | awk '{print $NF}')
|
||||||
if (stdout) {
|
if [ -n "$linenum" ]; then
|
||||||
status = STATUS.STATUS_WRONG_ANSWER;
|
echo "L=$linenum"
|
||||||
if (config.detail) message = parseDiffMsg(stdout);
|
awk "NR==$linenum" $usrout
|
||||||
} else status = STATUS.STATUS_ACCEPTED;
|
awk "NR==$linenum" $answer
|
||||||
if (message.length > 1024000) message = '';
|
fi
|
||||||
return {
|
`;
|
||||||
score: status === STATUS.STATUS_ACCEPTED ? config.score : 0,
|
|
||||||
status,
|
|
||||||
message,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async strict(config) {
|
const getDefaultChecker = (strict: boolean) => async (config) => {
|
||||||
const { stdout } = await runQueued('/usr/bin/diff usrout answer', {
|
const { code, stdout } = await runQueued(`/bin/bash compare.sh${strict ? '' : ' BZ'}`, {
|
||||||
copyIn: {
|
copyIn: {
|
||||||
usrout: config.user_stdout,
|
usrout: config.user_stdout,
|
||||||
answer: config.output,
|
answer: config.output,
|
||||||
...config.copyIn,
|
...config.copyIn,
|
||||||
},
|
'compare.sh': { content: compareSh },
|
||||||
});
|
},
|
||||||
const status = stdout ? STATUS.STATUS_WRONG_ANSWER : STATUS.STATUS_ACCEPTED;
|
});
|
||||||
return {
|
let status: number;
|
||||||
score: status === STATUS.STATUS_ACCEPTED ? config.score : 0,
|
let message: any = '';
|
||||||
status,
|
if (code) {
|
||||||
message: '',
|
status = STATUS.STATUS_SYSTEM_ERROR;
|
||||||
};
|
message = `Checker returned with status ${code}`;
|
||||||
},
|
} else if (stdout) {
|
||||||
|
status = STATUS.STATUS_WRONG_ANSWER;
|
||||||
|
if (config.detail && !strict) message = parseDiffMsg(stdout);
|
||||||
|
} else status = STATUS.STATUS_ACCEPTED;
|
||||||
|
if (message.length > 1024000) message = '';
|
||||||
|
return {
|
||||||
|
score: status === STATUS.STATUS_ACCEPTED ? config.score : 0,
|
||||||
|
status,
|
||||||
|
message,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkers: Record<string, Checker> = new Proxy({
|
||||||
|
default: getDefaultChecker(false),
|
||||||
|
strict: getDefaultChecker(true),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* argv[1]:输入
|
* argv[1]:输入
|
||||||
|
|||||||
Reference in new issue
Block a user