judge: replace diff binary (fix #965)

This commit is contained in:
undefined committed 2025-03-25 14:27:16 +08:00
1 parent dc9cc9eecf
commit 4421f98620
1 file changed
+54 -48
+54 -48
View File
@@ -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]:输入