Browse Source

Add support for subtasks

master
Pisces000221 8 years ago
parent
commit
7ebf06c326
  1. 5
      static/style.css
  2. 47
      utility.js
  3. 118
      views/judge_detail_item.ejs
  4. 13
      views/upload_testdata.ejs
  5. 1
      views/util.ejs

5
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;
}

47
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');

118
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">
<table class="ui very basic center aligned table" id="status_table">
<thead>
@ -58,52 +81,59 @@
<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) { %>
<div class="ui styled fluid accordion" id="testcases_list">
<% 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'
};
}
}
%>
<div class="title<% if (pending) { %> pending<% } %>"<% if (pending) { %> style="cursor: auto; "<% } %>>
<div class="ui grid">
<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('_') %>">
<i class="<%= icon[getStatusMeta(testcase.status)] || 'remove' %> icon"></i>
<%= testcase.status %></div>
<% if (!pending) { %>
<% 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; "><%= testcase.time_used %> ms</span></div>
<div class="three wide column">内存:<span style="font-weight: normal; "><%= testcase.memory_used %> KiB</span></div>
<% let subtask_count = 0; %>
<% for (let subtask_cases of (judge.result.subtasks || [])) { %>
<% if (judge.result.subtasks.length !== 1) { %>
<div class="title">
<div class="ui grid">
<div class="three wide column"><i class="dropdown icon"></i>子任务 #<%= ++subtask_count %></div>
<div class="four wide column status status_detail <%= getStatusMeta(subtask_cases.status).toLowerCase().split(' ').join('_') %>">
<i class="<%= icon[getStatusMeta(subtask_cases.status)] || 'remove' %> icon"></i>
<%= subtask_cases.status %></div>
<% if (!subtask_cases.pending) { %>
<div class="three wide column">得分:<span style="font-weight: normal; "><%= parseFloat(subtask_cases.score.toFixed(2)).toString() %></span></div>
<% } %>
</div>
</div>
<div class="content">
<div class="accordion" id="testcases_list_subtask<%= subtask_count %>">
<% } %>
<% 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="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('_') %>">
<i class="<%= icon[getStatusMeta(testcase.status)] || 'remove' %> icon"></i>
<%= testcase.status %></div>
<% if (!testcase.pending) { %>
<% if (!testcase.score) testcase.score = testcase.status === 'Accepted' ? 100 : 0; %>
<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.memory_used %> KiB</span></div>
<% } %>
</div>
</div>
<div class="content">
<% if (!testcase.pending) { %>
<p>
<strong>输入文件</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.input %></code></pre></div>
<strong>期望输出</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.answer %></code></pre></div>
<strong>你的输出</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.user_out %></code></pre></div>
<% if (testcase.spj_message) { %>
<strong>Special Judge 信息</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.spj_message %></code></pre></div>
<% } %>
</p>
<% } %>
</div>
</div>
<div class="content">
<% if (!pending) { %>
<p>
<strong>输入文件</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.input %></code></pre></div>
<strong>期望输出</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.answer %></code></pre></div>
<strong>你的输出</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.user_out %></code></pre></div>
<% if (testcase.spj_message) { %>
<strong>Special Judge 信息</strong>
<div class="ui existing segment"><pre style="margin-top: 0; margin-bottom: 0; "><code><%= testcase.spj_message %></code></pre></div>
<% } %>
</p>
<% } %>
</div>
<% if (judge.result.subtasks.length !== 1) { %>
</div></div>
<% } %>
<% } %>
</div>
<% } %>
@ -146,6 +176,6 @@ function update_judge_detail() {
});
}, 500);
}
update_judge_detail();
//update_judge_detail();
<% } %>
</script>

13
views/upload_testdata.ejs

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

1
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',

Loading…
Cancel
Save