Browse Source

Add support for subtasks

pull/6/head
Pisces000221 8 years ago
parent
commit
7ebf06c326
  1. 5
      static/style.css
  2. 45
      utility.js
  3. 72
      views/judge_detail_item.ejs
  4. 9
      views/upload_testdata.ejs
  5. 1
      views/util.ejs

5
static/style.css

@ -39,7 +39,10 @@ pre {
:not(.status_detail).status.accepted, :not(.status_detail).status.accepted,
.title:hover .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; color: forestgreen;
} }

45
utility.js

@ -146,18 +146,20 @@ module.exports = {
let list = zip.getEntries().filter(e => !e.isDirectory).map(e => e.entryName); let list = zip.getEntries().filter(e => !e.isDirectory).map(e => e.entryName);
let res = []; let res = [];
if (!list.includes('data_rule.txt')) { if (!list.includes('data_rule.txt')) {
res[0] = {};
res[0].cases = [];
for (let file of list) { for (let file of list) {
let parsedName = path.parse(file); let parsedName = path.parse(file);
if (parsedName.ext === '.in') { if (parsedName.ext === '.in') {
if (list.includes(`${parsedName.name}.out`)) { if (list.includes(`${parsedName.name}.out`)) {
res.push({ res[0].cases.push({
input: file, input: file,
output: `${parsedName.name}.out` output: `${parsedName.name}.out`
}); });
} }
if (list.includes(`${parsedName.name}.ans`)) { if (list.includes(`${parsedName.name}.ans`)) {
res.push({ res[0].cases.push({
input: file, input: file,
output: `${parsedName.name}.ans` 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) { function getLastInteger(s) {
let re = /(\d+)\D*$/; let re = /(\d+)\D*$/;
let x = re.exec(s); let x = re.exec(s);
@ -176,24 +180,39 @@ module.exports = {
return getLastInteger(a.input) - getLastInteger(b.input); return getLastInteger(a.input) - getLastInteger(b.input);
}); });
} else { } 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'; if (lines.length < 3) throw 'Invalid data_rule.txt';
let numbers = lines[0].split(' ').filter(x => x); let input = lines[lines.length - 2];
let input = lines[1]; let output = lines[lines.length - 1];
let output = lines[2];
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) { for (let i of numbers) {
res[i] = {}; let testcase = {
res[i].input = input.replace('#', i); input: input.replace('#', i),
res[i].output = output.replace('#', i); output: output.replace('#', i)
};
if (!list.includes(res[i].input)) throw `Can't find file ${res[i].input}`; if (!list.includes(testcase.input)) throw `Can't find file ${testcase.input}`;
if (!list.includes(res[i].output)) throw `Can't find file ${res[i].output}`; 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'); res.spj = list.includes('spj.js');

72
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;
}
}
%>
<div class="padding"> <div class="padding">
<table class="ui very basic center aligned table" id="status_table"> <table class="ui very basic center aligned table" id="status_table">
<thead> <thead>
@ -58,38 +81,41 @@
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%- judge.result.compiler_output %></code></pre></div> <div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%- judge.result.compiler_output %></code></pre></div>
<% } else if (judge.allowedSeeResult) { %> <% } else if (judge.allowedSeeResult) { %>
<div class="ui styled fluid accordion" id="testcases_list"> <div class="ui styled fluid accordion" id="testcases_list">
<% for (let i = 0; i < judge.result.case_num; i++) { %> <% let subtask_count = 0; %>
<% <% for (let subtask_cases of (judge.result.subtasks || [])) { %>
let testcase = judge.result[i], pending = false; <% if (judge.result.subtasks.length !== 1) { %>
if (!testcase) { <div class="title">
pending = true; <div class="ui grid">
if (i == 0 || judge.result[i - 1]) { <div class="three wide column"><i class="dropdown icon"></i>子任务 #<%= ++subtask_count %></div>
testcase = { <div class="four wide column status status_detail <%= getStatusMeta(subtask_cases.status).toLowerCase().split(' ').join('_') %>">
status: 'Running' <i class="<%= icon[getStatusMeta(subtask_cases.status)] || 'remove' %> icon"></i>
}; <%= subtask_cases.status %></div>
} else { <% if (!subtask_cases.pending) { %>
testcase = { <div class="three wide column">得分:<span style="font-weight: normal; "><%= parseFloat(subtask_cases.score.toFixed(2)).toString() %></span></div>
status: 'Waiting' <% } %>
}; </div>
} </div>
} <div class="content">
%> <div class="accordion" id="testcases_list_subtask<%= subtask_count %>">
<div class="title<% if (pending) { %> pending<% } %>"<% if (pending) { %> style="cursor: auto; "<% } %>> <% } %>
<% for (let i = 0; i < subtask_cases.case_num; i++) { %>
<% let testcase = subtask_cases[i]; %>
<div class="title<% if (testcase.pending) { %> testcase.pending<% } %>"<% if (testcase.pending) { %> style="cursor: auto; "<% } %>>
<div class="ui grid"> <div class="ui grid">
<div class="three wide column"><i class="dropdown icon"></i>测试点 #<%= i + 1 %></div> <div class="three wide column"><i class="dropdown icon"></i>测试点 #<%= i + 1 %></div>
<div class="four wide column status status_detail <%= getStatusMeta(testcase.status).toLowerCase().split(' ').join('_') %>"> <div class="four wide column status status_detail <%= getStatusMeta(testcase.status).toLowerCase().split(' ').join('_') %>">
<i class="<%= icon[getStatusMeta(testcase.status)] || 'remove' %> icon"></i> <i class="<%= icon[getStatusMeta(testcase.status)] || 'remove' %> icon"></i>
<%= testcase.status %></div> <%= testcase.status %></div>
<% if (!pending) { %> <% if (!testcase.pending) { %>
<% if (!testcase.score) testcase.score = testcase.status === 'Accepted' ? 100 : 0; %> <% if (!testcase.score) testcase.score = testcase.status === 'Accepted' ? 100 : 0; %>
<div class="three wide column">得分:<span style="font-weight: normal; "><%= parseFloat((testcase.score / judge.result.case_num).toFixed(2)).toString() %></span></div> <div class="three wide column">得分:<span style="font-weight: normal; "><%= parseFloat(testcase.score.toFixed(2)).toString() %></span></div>
<div class="three wide column">用时:<span style="font-weight: normal; "><%= testcase.time_used %> ms</span></div> <div class="three wide column">用时:<span style="font-weight: normal; "><%= testcase.time_used %> ms</span></div>
<div class="three wide column">内存:<span style="font-weight: normal; "><%= testcase.memory_used %> KiB</span></div> <div class="three wide column">内存:<span style="font-weight: normal; "><%= testcase.memory_used %> KiB</span></div>
<% } %> <% } %>
</div> </div>
</div> </div>
<div class="content"> <div class="content">
<% if (!pending) { %> <% if (!testcase.pending) { %>
<p> <p>
<strong>输入文件</strong> <strong>输入文件</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.input %></code></pre></div> <div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.input %></code></pre></div>
@ -105,6 +131,10 @@
<% } %> <% } %>
</div> </div>
<% } %> <% } %>
<% if (judge.result.subtasks.length !== 1) { %>
</div></div>
<% } %>
<% } %>
</div> </div>
<% } %> <% } %>
</div> </div>
@ -146,6 +176,6 @@ function update_judge_detail() {
}); });
}, 500); }, 500);
} }
update_judge_detail(); //update_judge_detail();
<% } %> <% } %>
</script> </script>

9
views/upload_testdata.ejs

@ -23,12 +23,19 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% for (let testcase of list) { %> <% for (let subtask of list) { %>
<% if (list.length !== 1) { %>
<tr>
<td colspan='2'><strong>→ 子任务评分方式:<%= subtask.type %>,分值:<%= subtask.score %></strong></td>
</tr>
<% } %>
<% for (let testcase of subtask.cases) { %>
<tr> <tr>
<td><%= testcase.input %></td> <td><%= testcase.input %></td>
<td><%= testcase.output %></td> <td><%= testcase.output %></td>
</tr> </tr>
<% } %> <% } %>
<% } %>
</tbody> </tbody>
</table> </table>
<% } catch (e) { %> <% } catch (e) { %>

1
views/util.ejs

@ -15,6 +15,7 @@ this.isPending = (status) => {
this.icon = { this.icon = {
'Accepted': 'checkmark', 'Accepted': 'checkmark',
'Passed': 'checkmark',
'Wrong Answer': 'remove', 'Wrong Answer': 'remove',
'Runtime Error': 'bomb', 'Runtime Error': 'bomb',
'Time Limit Exceeded': 'clock', 'Time Limit Exceeded': 'clock',

Loading…
Cancel
Save