From 7ebf06c326bdfba38ffa06524fc39c2bbde37c3d Mon Sep 17 00:00:00 2001 From: Pisces000221 <1786762946@qq.com> Date: Fri, 17 Feb 2017 14:08:10 +0800 Subject: [PATCH] Add support for subtasks --- static/style.css | 5 +- utility.js | 47 +++++++++----- views/judge_detail_item.ejs | 118 ++++++++++++++++++++++-------------- views/upload_testdata.ejs | 13 +++- views/util.ejs | 1 + 5 files changed, 122 insertions(+), 62 deletions(-) diff --git a/static/style.css b/static/style.css index 38d21c2..7c47612 100644 --- a/static/style.css +++ b/static/style.css @@ -39,7 +39,10 @@ pre { :not(.status_detail).status.accepted, .title:hover .status_detail.status.accepted, -.title.active .status_detail.status.accepted { +.title.active .status_detail.status.accepted, +:not(.status_detail).status.passed, +.title:hover .status_detail.status.passed, +.title.active .status_detail.status.passed { color: forestgreen; } diff --git a/utility.js b/utility.js index 19e2b1c..6c2b75d 100644 --- a/utility.js +++ b/utility.js @@ -146,18 +146,20 @@ module.exports = { let list = zip.getEntries().filter(e => !e.isDirectory).map(e => e.entryName); let res = []; if (!list.includes('data_rule.txt')) { + res[0] = {}; + res[0].cases = []; for (let file of list) { let parsedName = path.parse(file); if (parsedName.ext === '.in') { if (list.includes(`${parsedName.name}.out`)) { - res.push({ + res[0].cases.push({ input: file, output: `${parsedName.name}.out` }); } if (list.includes(`${parsedName.name}.ans`)) { - res.push({ + res[0].cases.push({ input: file, output: `${parsedName.name}.ans` }); @@ -165,7 +167,9 @@ module.exports = { } } - res.sort((a, b) => { + res[0].type = 'sum'; + res[0].score = 100; + res[0].cases.sort((a, b) => { function getLastInteger(s) { let re = /(\d+)\D*$/; let x = re.exec(s); @@ -176,24 +180,39 @@ module.exports = { return getLastInteger(a.input) - getLastInteger(b.input); }); } else { - let lines = zip.readAsText('data_rule.txt').split('\r').join('').split('\n'); + let lines = zip.readAsText('data_rule.txt').split('\r').join('').split('\n').filter(x => x.length !== 0); if (lines.length < 3) throw 'Invalid data_rule.txt'; - let numbers = lines[0].split(' ').filter(x => x); - let input = lines[1]; - let output = lines[2]; + let input = lines[lines.length - 2]; + let output = lines[lines.length - 1]; - for (let i of numbers) { - res[i] = {}; - res[i].input = input.replace('#', i); - res[i].output = output.replace('#', i); + for (let s = 0; s < lines.length - 2; ++s) { + res[s] = {}; + res[s].cases = []; + let numbers = lines[s].split(' ').filter(x => x); + if (numbers[0].includes(':')) { + let tokens = numbers[0].split(':'); + res[s].type = tokens[0] || 'sum'; + res[s].score = parseInt(tokens[1]); + numbers.shift(); + } else { + res[s].type = 'sum'; + res[s].score = 100; + } + for (let i of numbers) { + let testcase = { + input: input.replace('#', i), + output: output.replace('#', i) + }; - if (!list.includes(res[i].input)) throw `Can't find file ${res[i].input}`; - if (!list.includes(res[i].output)) throw `Can't find file ${res[i].output}`; + if (!list.includes(testcase.input)) throw `Can't find file ${testcase.input}`; + if (!list.includes(testcase.output)) throw `Can't find file ${testcase.output}`; + res[s].cases.push(testcase); + } } - res = res.filter(x => x); + res = res.filter(x => x.cases && x.cases.length !== 0); } res.spj = list.includes('spj.js'); diff --git a/views/judge_detail_item.ejs b/views/judge_detail_item.ejs index 0b6c414..a033a29 100644 --- a/views/judge_detail_item.ejs +++ b/views/judge_detail_item.ejs @@ -1,3 +1,26 @@ +<% +// Sanitize judge results for backward compatibility and clarity +if (!judge.result.subtasks) { + judge.result.subtasks = [ + { case_num: judge.result.case_num, status: judge.result.status, score: judge.result.score } + ]; + for (let i = 0; i < judge.result.case_num; ++i) { + judge.result.subtasks[0][i] = judge.result[i]; + } +} +let runningFound = false; +for (let s of judge.result.subtasks) { + s.pending = (s.status === 'Waiting' || s.status.startsWith('Running')); + for (let i = 0; i < s.case_num; ++i) if (!s[i]) { + s[i] = { + pending: true, + status: runningFound ? 'Waiting' : 'Running' + }; + runningFound = true; + } +} +%> +
@@ -58,52 +81,59 @@
<%- judge.result.compiler_output %>
<% } else if (judge.allowedSeeResult) { %>
- <% for (let i = 0; i < judge.result.case_num; i++) { %> - <% - let testcase = judge.result[i], pending = false; - if (!testcase) { - pending = true; - if (i == 0 || judge.result[i - 1]) { - testcase = { - status: 'Running' - }; - } else { - testcase = { - status: 'Waiting' - }; - } - } - %> -
style="cursor: auto; "<% } %>> -
-
测试点 #<%= i + 1 %>
-
- - <%= testcase.status %>
- <% if (!pending) { %> - <% if (!testcase.score) testcase.score = testcase.status === 'Accepted' ? 100 : 0; %> -
得分:<%= parseFloat((testcase.score / judge.result.case_num).toFixed(2)).toString() %>
-
用时:<%= testcase.time_used %> ms
-
内存:<%= testcase.memory_used %> KiB
+ <% let subtask_count = 0; %> + <% for (let subtask_cases of (judge.result.subtasks || [])) { %> + <% if (judge.result.subtasks.length !== 1) { %> +
+
+
子任务 #<%= ++subtask_count %>
+
+ + <%= subtask_cases.status %>
+ <% if (!subtask_cases.pending) { %> +
得分:<%= parseFloat(subtask_cases.score.toFixed(2)).toString() %>
+ <% } %> +
+
+
+
+ <% } %> + <% for (let i = 0; i < subtask_cases.case_num; i++) { %> + <% let testcase = subtask_cases[i]; %> +
style="cursor: auto; "<% } %>> +
+
测试点 #<%= i + 1 %>
+
+ + <%= testcase.status %>
+ <% if (!testcase.pending) { %> + <% if (!testcase.score) testcase.score = testcase.status === 'Accepted' ? 100 : 0; %> +
得分:<%= parseFloat(testcase.score.toFixed(2)).toString() %>
+
用时:<%= testcase.time_used %> ms
+
内存:<%= testcase.memory_used %> KiB
+ <% } %> +
+
+
+ <% if (!testcase.pending) { %> +

+ 输入文件 +

<%= testcase.input %>
+ 期望输出 +
<%= testcase.answer %>
+ 你的输出 +
<%= testcase.user_out %>
+ <% if (testcase.spj_message) { %> + Special Judge 信息 +
<%= testcase.spj_message %>
+ <% } %> +

<% } %>
-
-
- <% if (!pending) { %> -

- 输入文件 -

<%= testcase.input %>
- 期望输出 -
<%= testcase.answer %>
- 你的输出 -
<%= testcase.user_out %>
- <% if (testcase.spj_message) { %> - Special Judge 信息 -
<%= testcase.spj_message %>
- <% } %> -

<% } %> -
+ <% if (judge.result.subtasks.length !== 1) { %> +
+ <% } %> <% } %>
<% } %> @@ -146,6 +176,6 @@ function update_judge_detail() { }); }, 500); } -update_judge_detail(); +//update_judge_detail(); <% } %> diff --git a/views/upload_testdata.ejs b/views/upload_testdata.ejs index 2fbfb64..58bec6a 100644 --- a/views/upload_testdata.ejs +++ b/views/upload_testdata.ejs @@ -23,11 +23,18 @@
- <% for (let testcase of list) { %> + <% for (let subtask of list) { %> + <% if (list.length !== 1) { %> - - + + <% } %> + <% for (let testcase of subtask.cases) { %> + + + + + <% } %> <% } %>
<%= testcase.input %><%= testcase.output %>→ 子任务评分方式:<%= subtask.type %>,分值:<%= subtask.score %>
<%= testcase.input %><%= testcase.output %>
diff --git a/views/util.ejs b/views/util.ejs index 932b7b9..745a369 100644 --- a/views/util.ejs +++ b/views/util.ejs @@ -15,6 +15,7 @@ this.isPending = (status) => { this.icon = { 'Accepted': 'checkmark', + 'Passed': 'checkmark', 'Wrong Answer': 'remove', 'Runtime Error': 'bomb', 'Time Limit Exceeded': 'clock',