diff --git a/src/daemon/judge/index.ts b/src/daemon/judge/index.ts index 7ded701..68dc924 100644 --- a/src/daemon/judge/index.ts +++ b/src/daemon/judge/index.ts @@ -32,6 +32,7 @@ export async function judge( } let judger: JudgerBase; + console.log("Task typ: " + task.type); if (task.type === ProblemType.Standard) { judger = new StandardJudger(testData, task.param as StandardJudgeParameter, task.priority); } else if (task.type === ProblemType.AnswerSubmission) { diff --git a/src/daemon/judge/interaction.ts b/src/daemon/judge/interaction.ts index 4ba14b1..627b4d3 100644 --- a/src/daemon/judge/interaction.ts +++ b/src/daemon/judge/interaction.ts @@ -26,7 +26,7 @@ export class InteractionJudger extends JudgerBase { async preprocessTestData(): Promise { if (this.testData.interactor != null) { - winston.verbose("Compiling special judge."); + winston.verbose("Compiling interactor."); const [interactorExecutableName, interactorResult] = await compile(this.testData.interactor.sourceCode, this.testData.interactor.language, null, this.priority); if (interactorResult.status !== TaskStatus.Done) { @@ -69,9 +69,9 @@ export class InteractionJudger extends JudgerBase { // We do not have to create a InteractionRunResult const [inputContent, outputContent, runResult]: [string, string, StandardRunResult] = await Promise.all([ - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input), Cfg.dataDisplayLimit), - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output), Cfg.dataDisplayLimit), - runTask({ type: RPCTaskType.RunStandard, task: task }, this.priority, started) + readFileLength(curCase.input ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input) : null, Cfg.dataDisplayLimit), + readFileLength(curCase.output ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output) : null, Cfg.dataDisplayLimit), + runTask({ type: RPCTaskType.RunInteraction, task: task }, this.priority, started) ]) as any; return { diff --git a/src/daemon/judge/standard.ts b/src/daemon/judge/standard.ts index a48dd52..9db7646 100644 --- a/src/daemon/judge/standard.ts +++ b/src/daemon/judge/standard.ts @@ -70,8 +70,8 @@ export class StandardJudger extends JudgerBase { }; const [inputContent, outputContent, runResult]: [string, string, StandardRunResult] = await Promise.all([ - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input), Cfg.dataDisplayLimit), - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output), Cfg.dataDisplayLimit), + readFileLength(curCase.input ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input) : null, Cfg.dataDisplayLimit), + readFileLength(curCase.output ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output) : null, Cfg.dataDisplayLimit), runTask({ type: RPCTaskType.RunStandard, task: task }, this.priority, started) ]) as any; diff --git a/src/daemon/judge/submit-answer.ts b/src/daemon/judge/submit-answer.ts index 4f65f34..986347f 100644 --- a/src/daemon/judge/submit-answer.ts +++ b/src/daemon/judge/submit-answer.ts @@ -77,8 +77,8 @@ export class AnswerSubmissionJudger extends JudgerBase { } const [inputContent, outputContent, runResult]: [string, string, AnswerSubmissionRunResult] = await Promise.all([ - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input), Cfg.dataDisplayLimit), - readFileLength(pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output), Cfg.dataDisplayLimit), + readFileLength(curCase.input ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.input) : null, Cfg.dataDisplayLimit), + readFileLength(curCase.output ? pathLib.join(Cfg.testDataDirectory, this.testData.name, curCase.output) : null, Cfg.dataDisplayLimit), runTask({ type: RPCTaskType.RunSubmitAnswer, task: task }, this.priority, started) ]) as any; diff --git a/src/runner/judge.ts b/src/runner/judge.ts index 840dbaa..1a06c71 100644 --- a/src/runner/judge.ts +++ b/src/runner/judge.ts @@ -1,8 +1,9 @@ import pathLib = require('path'); import randomString = require('randomstring'); +import util = require('util'); import fse = require('fs-extra'); import winston = require('winston'); -import syspipe = require('syspipe'); +const syspipe = require('syspipe'); import { SandboxStatus } from 'simple-sandbox/lib/interfaces'; import { TestcaseResultType, StandardRunTask, StandardRunResult, InteractionRunTask, AnswerSubmissionRunTask, AnswerSubmissionRunResult } from '../interfaces'; @@ -285,7 +286,7 @@ export async function judgeInteraction(task: InteractionRunTask) winston.debug("Fetching user binary..."); const [userBinaryDirectory, userLanguage, userCode] = await fetchBinary(task.userExecutableName); winston.debug("Fetching interactor binary..."); - const [interactorBinaryDirectory, interactorLanguage] = await fetchBinary(task.userExecutableName); + const [interactorBinaryDirectory, interactorLanguage] = await fetchBinary(task.interactorExecutableName); pipe1 = syspipe.pipe(), pipe2 = syspipe.pipe(); @@ -311,8 +312,6 @@ export async function judgeInteraction(task: InteractionRunTask) const [interactorResult, runResult] = await Promise.all([interactorTaskPromise .then((result) => { stopUser(); return result; }, (err) => { stopUser(); return Promise.reject(err); }), userProgramTaskPromise]); - const userError = await readFileLength(pathLib.join(workingDir, tempErrFile), Cfg.stderrDisplayLimit); - const time = Math.round(runResult.result.time / 1e6), memory = runResult.result.memory / 1024; @@ -327,6 +326,7 @@ export async function judgeInteraction(task: InteractionRunTask) message = `Killed: ${signals[runResult.result.code]}`; status = TestcaseResultType.RuntimeError; } else if (runResult.result.status !== SandboxStatus.OK) { + message = "Warning: corrupt sandbox result " + util.inspect(runResult.result); status = TestcaseResultType.RuntimeError; } else { message = `Exited with return code ${runResult.result.code}`; @@ -344,7 +344,7 @@ export async function judgeInteraction(task: InteractionRunTask) time: time, memory: time, userOutput: null, - userError: userError, + userError: await readFileLength(pathLib.join(workingDir, tempErrFile), Cfg.stderrDisplayLimit), spjMessage: await readFileLength(pathLib.join(spjWorkingDir, tempErrFile), Cfg.stderrDisplayLimit) }; @@ -352,21 +352,23 @@ export async function judgeInteraction(task: InteractionRunTask) let score = 0; if (status == null) { const scoreString = await tryReadFile(spjWorkingDir + '/score.txt'); - let score = Number(scoreString); - if ((!scoreString) || isNaN(score)) { + const rawScore = Number(scoreString); + if ((!scoreString) || isNaN(rawScore)) { + score = null; status = TestcaseResultType.JudgementFailed; message = `Interactor returned a non-number score ${scoreString}`; } else if (score === -1) { - score = 0; status = TestcaseResultType.InvalidInteraction; } else { - score = score; - status = getStatusByScore(score); + score = rawScore; + status = getStatusByScore(rawScore); } } + winston.debug(`Interaction problem judge succeeded, score = ${score}`); return Object.assign(partialResult, { result: status, - scoringRate: score / spjFullScore + scoringRate: score / spjFullScore, + systemMessage: message }); } finally { const closePipe = async (p) => {