Browse Source

Add support for ACM and IOI contest

pull/6/head
Menci 7 years ago
parent
commit
24bacde025
  1. 8
      models/contest.js
  2. 93
      models/contest_player.js
  3. 48
      models/contest_ranklist.js
  4. 17
      models/judge_state.js
  5. 36
      modules/contest.js
  6. 6
      modules/problem.js
  7. 4
      modules/submission.js
  8. 27
      views/contest.ejs
  9. 21
      views/contest_edit.ejs
  10. 106
      views/contest_ranklist.ejs
  11. 2
      views/contest_submissions.ejs
  12. 3
      views/header.ejs
  13. 58
      views/submission_content.ejs

8
models/contest.js

@ -40,6 +40,8 @@ let model = db.define('contest', {
key: 'id' key: 'id'
} }
}, },
// type: noi, ioi, acm
type: { type: Sequelize.STRING(10) },
information: { type: Sequelize.TEXT }, information: { type: Sequelize.TEXT },
problems: { type: Sequelize.TEXT }, problems: { type: Sequelize.TEXT },
@ -71,6 +73,7 @@ class Contest extends Model {
title: '', title: '',
problems: '', problems: '',
information: '', information: '',
type: 'noi',
start_time: 0, start_time: 0,
end_time: 0, end_time: 0,
holder: 0, holder: 0,
@ -88,6 +91,7 @@ class Contest extends Model {
} }
async isAllowedSeeResultBy(user) { async isAllowedSeeResultBy(user) {
if (this.type === 'acm' || this.type === 'ioi') return true;
return (user && (user.is_admin || this.holder_id === user.id)) || !(await this.isRunning()); return (user && (user.is_admin || this.holder_id === user.id)) || !(await this.isRunning());
} }
@ -111,6 +115,8 @@ class Contest extends Model {
} }
async newSubmission(judge_state) { async newSubmission(judge_state) {
if (judge_state.pending) return;
let problems = await this.getProblems(); let problems = await this.getProblems();
if (!problems.includes(judge_state.problem_id)) throw new ErrorMessage('当前比赛中无此题目。'); if (!problems.includes(judge_state.problem_id)) throw new ErrorMessage('当前比赛中无此题目。');
@ -130,7 +136,7 @@ class Contest extends Model {
await player.save(); await player.save();
await this.loadRelationships(); await this.loadRelationships();
await this.ranklist.updatePlayer(player); await this.ranklist.updatePlayer(this, player);
await this.ranklist.save(); await this.ranklist.save();
} }

93
models/contest_player.js

@ -24,7 +24,6 @@ let db = syzoj.db;
let User = syzoj.model('user'); let User = syzoj.model('user');
let Problem = syzoj.model('problem'); let Problem = syzoj.model('problem');
let Contest = syzoj.model('contest');
let model = db.define('contest_player', { let model = db.define('contest_player', {
id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, id: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
@ -64,18 +63,96 @@ class ContestPlayer extends Model {
} }
async loadRelationships() { async loadRelationships() {
let Contest = syzoj.model('contest');
this.user = await User.fromID(this.user_id); this.user = await User.fromID(this.user_id);
this.contest = await Contest.fromID(this.contest_id); this.contest = await Contest.fromID(this.contest_id);
} }
async updateScore(judge_state) { async updateScore(judge_state) {
this.score_details[judge_state.problem_id] = { await this.loadRelationships();
score: judge_state.score, if (this.contest.type === 'ioi') {
judge_id: judge_state.id if (!this.score_details[judge_state.problem_id]) {
}; this.score_details[judge_state.problem_id] = {
this.score = 0; score: judge_state.score,
for (let x in this.score_details) { judge_id: judge_state.id,
this.score += this.score_details[x].score; submissions: {}
};
}
this.score_details[judge_state.problem_id].submissions[judge_state.id] = {
judge_id: judge_state.id,
score: judge_state.score,
time: judge_state.submit_time
};
let arr = Object.values(this.score_details[judge_state.problem_id].submissions);
arr.sort((a, b) => a.time - b.time);
let maxScoreSubmission = null;
for (let x of arr) {
if (!maxScoreSubmission || x.score >= maxScoreSubmission.score && maxScoreSubmission.score < 100) {
maxScoreSubmission = x;
}
}
this.score_details[judge_state.problem_id].judge_id = maxScoreSubmission.judge_id;
this.score_details[judge_state.problem_id].score = maxScoreSubmission.score;
this.score_details[judge_state.problem_id].time = maxScoreSubmission.time;
this.score = 0;
for (let x in this.score_details) {
this.score += this.score_details[x].score;
}
} else if (this.contest.type === 'noi') {
this.score_details[judge_state.problem_id] = {
score: judge_state.score,
judge_id: judge_state.id
};
this.score = 0;
for (let x in this.score_details) {
this.score += this.score_details[x].score;
}
} else if (this.contest.type === 'acm') {
if (!this.score_details[judge_state.problem_id]) {
this.score_details[judge_state.problem_id] = {
accepted: false,
unacceptedCount: 0,
acceptedTime: 0,
judge_id: 0,
submissions: {}
};
}
this.score_details[judge_state.problem_id].submissions[judge_state.id] = {
judge_id: judge_state.id,
accepted: judge_state.status === 'Accepted',
time: judge_state.submit_time
};
let arr = Object.values(this.score_details[judge_state.problem_id].submissions);
arr.sort((a, b) => a.time - b.time);
this.score_details[judge_state.problem_id].unacceptedCount = 0;
this.score_details[judge_state.problem_id].judge_id = 0;
for (let x of arr) {
if (x.accepted) {
this.score_details[judge_state.problem_id].accepted = true;
this.score_details[judge_state.problem_id].acceptedTime = x.time;
this.score_details[judge_state.problem_id].judge_id = x.judge_id;
break;
} else {
this.score_details[judge_state.problem_id].unacceptedCount++;
}
}
if (!this.score_details[judge_state.problem_id].accepted) {
this.score_details[judge_state.problem_id].judge_id = arr[arr.length - 1].judge_id;
}
this.score = 0;
for (let x in this.score_details) {
if (this.score_details[x].accepted) this.score++;
}
} }
} }

48
models/contest_ranklist.js

@ -50,7 +50,7 @@ class ContestRanklist extends Model {
return a; return a;
} }
async updatePlayer(player) { async updatePlayer(contest, player) {
let players = await this.getPlayers(), newPlayer = true; let players = await this.getPlayers(), newPlayer = true;
for (let x of players) { for (let x of players) {
if (x.user_id === player.user_id) { if (x.user_id === player.user_id) {
@ -65,21 +65,41 @@ class ContestRanklist extends Model {
let JudgeState = syzoj.model('judge_state'); let JudgeState = syzoj.model('judge_state');
for (let player of players) { if (contest.type === 'noi' || contest.type === 'ioi') {
player.latest = 0; for (let player of players) {
for (let i in player.score_details) { player.latest = 0;
let judge_state = await JudgeState.fromID(player.score_details[i].judge_id); for (let i in player.score_details) {
player.latest = Math.max(player.latest, judge_state.submit_time); console.log(player.score_details);
let judge_state = await JudgeState.fromID(player.score_details[i].judge_id);
player.latest = Math.max(player.latest, judge_state.submit_time);
}
}
players.sort((a, b) => {
if (a.score > b.score) return -1;
if (b.score > a.score) return 1;
if (a.latest < b.latest) return -1;
if (a.latest > b.latest) return 1;
return 0;
});
} else {
for (let player of players) {
player.timeSum = 0;
for (let i in player.score_details) {
if (player.score_details[i].accepted) {
player.timeSum += (player.score_details[i].acceptedTime - contest.start_time) + (player.score_details[i].unacceptedCount * 20 * 60);
}
}
} }
}
players.sort((a, b) => { players.sort((a, b) => {
if (a.score > b.score) return -1; if (a.score > b.score) return -1;
if (b.score > a.score) return 1; if (b.score > a.score) return 1;
if (a.latest < b.latest) return -1; if (a.timeSum < b.timeSum) return -1;
if (a.latest > b.latest) return 1; if (a.timeSum > b.timeSum) return 1;
return 0; return 0;
}); });
}
this.ranklist = { player_num: players.length }; this.ranklist = { player_num: players.length };
for (let i = 0; i < players.length; i++) this.ranklist[i + 1] = players[i].id; for (let i = 0; i < players.length; i++) this.ranklist[i + 1] = players[i].id;

17
models/judge_state.js

@ -107,7 +107,7 @@ class JudgeState extends Model {
else if (this.type === 1) { else if (this.type === 1) {
let contest = await Contest.fromID(this.type_info); let contest = await Contest.fromID(this.type_info);
if (await contest.isRunning()) { if (await contest.isRunning()) {
return false; return contest.type === 'acm' || contest.type === 'ioi';
} else { } else {
return true; return true;
} }
@ -129,6 +129,21 @@ class JudgeState extends Model {
} else if (this.type === 2) return false; } else if (this.type === 2) return false;
} }
async isAllowedSeeDataBy(user) {
await this.loadRelationships();
if (user && (await user.hasPrivilege('manage_problem') || user.id === this.problem.user_id)) return true;
else if (this.type === 0) return this.problem.is_public;
else if (this.type === 1) {
let contest = await Contest.fromID(this.type_info);
if (await contest.isRunning()) {
return false;
} else {
return true;
}
} else if (this.type === 2) return true;
}
async updateResult(result) { async updateResult(result) {
this.score = result.score; this.score = result.score;
this.pending = result.pending; this.pending = result.pending;

36
modules/contest.js

@ -91,6 +91,8 @@ app.post('/contest/:id/edit', async (req, res) => {
contest.title = req.body.title; contest.title = req.body.title;
if (!Array.isArray(req.body.problems)) req.body.problems = [req.body.problems]; if (!Array.isArray(req.body.problems)) req.body.problems = [req.body.problems];
contest.problems = req.body.problems.join('|'); contest.problems = req.body.problems.join('|');
if (!['noi', 'ioi', 'acm'].includes(req.body.type)) throw new ErrorMessage('无效的赛制。');
contest.type = req.body.type;
contest.information = req.body.information; contest.information = req.body.information;
contest.start_time = syzoj.utils.parseDate(req.body.start_time); contest.start_time = syzoj.utils.parseDate(req.body.start_time);
contest.end_time = syzoj.utils.parseDate(req.body.end_time); contest.end_time = syzoj.utils.parseDate(req.body.end_time);
@ -132,17 +134,35 @@ app.get('/contest/:id', async (req, res) => {
problems = problems.map(x => ({ problem: x, status: null, judge_id: null })); problems = problems.map(x => ({ problem: x, status: null, judge_id: null }));
if (player) { if (player) {
for (let problem of problems) { for (let problem of problems) {
if (player.score_details[problem.problem.id]) { if (contest.type === 'noi') {
if (await contest.isRunning()) { if (player.score_details[problem.problem.id]) {
problem.status = true; if (await contest.isRunning()) {
problem.status = true;
} else {
let judge_state = await JudgeState.fromID(player.score_details[problem.problem.id].judge_id);
problem.status = judge_state.status;
}
problem.judge_id = player.score_details[problem.problem.id].judge_id;
} else { } else {
if (contest.isRunning()) {
problem.status = false;
}
}
} else if (contest.type === 'ioi') {
if (player.score_details[problem.problem.id]) {
let judge_state = await JudgeState.fromID(player.score_details[problem.problem.id].judge_id); let judge_state = await JudgeState.fromID(player.score_details[problem.problem.id].judge_id);
problem.status = judge_state.status; problem.status = judge_state.status;
problem.judge_id = player.score_details[problem.problem.id].judge_id;
} }
problem.judge_id = player.score_details[problem.problem.id].judge_id; } else if (contest.type === 'acm') {
} else { if (player.score_details[problem.problem.id]) {
if (contest.isRunning()) { problem.status = {
problem.status = false; accepted: player.score_details[problem.problem.id].accepted,
unacceptedCount: player.score_details[problem.problem.id].unacceptedCount
};
problem.judge_id = player.score_details[problem.problem.id].judge_id;
} else {
problem.status = null;
} }
} }
} }
@ -221,7 +241,7 @@ app.get('/contest/:id/submissions', async (req, res) => {
where.type = 1; where.type = 1;
where.type_info = contest_id; where.type_info = contest_id;
if (contest.ended || (res.locals.user && res.locals.user.is_admin)) { if (contest.ended || contest.type !== 'noi' || (res.locals.user && res.locals.user.is_admin)) {
let minScore = parseInt(req.query.min_score); let minScore = parseInt(req.query.min_score);
if (isNaN(minScore)) minScore = 0; if (isNaN(minScore)) minScore = 0;
let maxScore = parseInt(req.query.max_score); let maxScore = parseInt(req.query.max_score);

6
modules/problem.js

@ -489,7 +489,7 @@ app.post('/problem/:id/submit', async (req, res) => {
problem_id: req.params.id problem_id: req.params.id
}); });
let contest_id = parseInt(req.query.contest_id); let contest_id = parseInt(req.query.contest_id), redirectToContest = false;
if (contest_id) { if (contest_id) {
let contest = await Contest.fromID(contest_id); let contest = await Contest.fromID(contest_id);
if (!contest) throw new ErrorMessage('无此比赛。'); if (!contest) throw new ErrorMessage('无此比赛。');
@ -500,6 +500,8 @@ app.post('/problem/:id/submit', async (req, res) => {
judge_state.type_info = contest_id; judge_state.type_info = contest_id;
await judge_state.save(); await judge_state.save();
if (contest.type === 'noi') redirectToContest = true;
} else { } else {
if (!await problem.isAllowedUseBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。'); if (!await problem.isAllowedUseBy(res.locals.user)) throw new ErrorMessage('您没有权限进行此操作。');
judge_state.type = problem.is_public ? 0 : 2; judge_state.type = problem.is_public ? 0 : 2;
@ -513,7 +515,7 @@ app.post('/problem/:id/submit', async (req, res) => {
await waiting_judge.save(); await waiting_judge.save();
if (contest_id) { if (redirectToContest) {
res.redirect(syzoj.utils.makeUrl(['contest', contest_id])); res.redirect(syzoj.utils.makeUrl(['contest', contest_id]));
} else { } else {
res.redirect(syzoj.utils.makeUrl(['submission', judge_state.id])); res.redirect(syzoj.utils.makeUrl(['submission', judge_state.id]));

4
modules/submission.js

@ -54,6 +54,7 @@ app.get('/submissions', async (req, res) => {
await judge_state.forEachAsync(async obj => obj.loadRelationships()); await judge_state.forEachAsync(async obj => obj.loadRelationships());
await judge_state.forEachAsync(async obj => obj.hidden = !(await obj.isAllowedSeeResultBy(res.locals.user))); await judge_state.forEachAsync(async obj => obj.hidden = !(await obj.isAllowedSeeResultBy(res.locals.user)));
await judge_state.forEachAsync(async obj => obj.allowedSeeCode = await obj.isAllowedSeeCodeBy(res.locals.user)); await judge_state.forEachAsync(async obj => obj.allowedSeeCode = await obj.isAllowedSeeCodeBy(res.locals.user));
await judge_state.forEachAsync(async obj => obj.allowedSeeData = await obj.isAllowedSeeDataBy(res.locals.user));
res.render('submissions', { res.render('submissions', {
judge_state: judge_state, judge_state: judge_state,
@ -77,6 +78,7 @@ app.get('/submissions/:id/ajax', async (req, res) => {
judge_state.hidden = !(await judge_state.isAllowedSeeResultBy(res.locals.user)); judge_state.hidden = !(await judge_state.isAllowedSeeResultBy(res.locals.user));
judge_state.allowedSeeCode = await judge_state.isAllowedSeeCodeBy(res.locals.user); judge_state.allowedSeeCode = await judge_state.isAllowedSeeCodeBy(res.locals.user);
judge_state.allowedSeeData = await judge_state.isAllowedSeeDataBy(res.locals.user);
res.render('submissions_item', { res.render('submissions_item', {
judge: judge_state judge: judge_state
@ -103,6 +105,7 @@ app.get('/submission/:id', async (req, res) => {
judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight); judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight);
judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user); judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user);
judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user); judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user);
judge.allowedSeeData = await judge.isAllowedSeeDataBy(res.locals.user);
judge.allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user); judge.allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
if (contest) { if (contest) {
@ -137,6 +140,7 @@ app.get('/submission/:id/ajax', async (req, res) => {
judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight); judge.code = await syzoj.utils.highlight(judge.code, syzoj.config.languages[judge.language].highlight);
judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user); judge.allowedSeeResult = await judge.isAllowedSeeResultBy(res.locals.user);
judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user); judge.allowedSeeCode = await judge.isAllowedSeeCodeBy(res.locals.user);
judge.allowedSeeData = await judge.isAllowedSeeDataBy(res.locals.user);
judge.allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user); judge.allowedRejudge = await judge.problem.isAllowedEditBy(res.locals.user);
if (contest) { if (contest) {

27
views/contest.ejs

@ -4,6 +4,7 @@
.ui.label.pointing.below.right::before { left: 88%; } .ui.label.pointing.below.right::before { left: 88%; }
.ui.label.pointing.below.left { margin-bottom: 0; } .ui.label.pointing.below.left { margin-bottom: 0; }
.ui.label.pointing.below.right { margin-bottom: 0; float: right; } .ui.label.pointing.below.right { margin-bottom: 0; float: right; }
#back_to_contest { display: none; }
</style> </style>
<% include header %> <% include header %>
<div class="padding"> <div class="padding">
@ -20,7 +21,7 @@
<div class="bar" style="width: <%= timePercentage %>%;"></div> <div class="bar" style="width: <%= timePercentage %>%;"></div>
</div> </div>
<div class="ui grid"> <div class="ui grid">
<% if (contest.allowedEdit || (unveiled && !contest.running)) { %> <% if (contest.allowedEdit || (unveiled && (!contest.running || contest.type !== 'noi'))) { %>
<div class="row"> <div class="row">
<div class="column"> <div class="column">
<div class="ui buttons"> <div class="ui buttons">
@ -49,7 +50,6 @@
<tr> <tr>
<th class="one wide" style="text-align: center">状态</th> <th class="one wide" style="text-align: center">状态</th>
<th class="fourteen wide">题目</th> <th class="fourteen wide">题目</th>
<th class="one wide" style="text-align: center">代码</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -64,20 +64,31 @@
<a href="<%= syzoj.utils.makeUrl(['submission', problem.judge_id]) %>"> <a href="<%= syzoj.utils.makeUrl(['submission', problem.judge_id]) %>">
<% if (problem.status === true) { %> <% if (problem.status === true) { %>
<i class="black checkmark icon"></i> <i class="black checkmark icon"></i>
<% } else if (problem.status !== false) { %> <% } else if (typeof problem.status === 'string') { %>
<span class="status <%= problem.status.toLowerCase().split(' ').join('_') %>"> <span class="status <%= problem.status.toLowerCase().split(' ').join('_') %>">
<i class="<%= icon[getStatusMeta(problem.status)] || 'remove' %> icon"></i> <i class="<%= icon[getStatusMeta(problem.status)] || 'remove' %> icon"></i>
<%= problem.status %> <%= problem.status %>
</span> </span>
<% } else if (typeof problem.status === 'object') { %>
<% if (problem.status.accepted) { %>
<span class="score score_10">
<% if (problem.status.unacceptedCount === 0) { %>
+
<% } else { %>
+<%= problem.status.unacceptedCount %>
<% } %>
</span>
<% } else { %>
<span class="score score_0">
<% if (problem.status.unacceptedCount !== 0) { %>
-<%= problem.status.unacceptedCount %>
<% } %>
</span>
<% } %>
<% } %> <% } %>
<% } %> <% } %>
</td> </td>
<td><a href="<%= syzoj.utils.makeUrl(['contest', contest.id, i]) %>"><%= syzoj.utils.removeTitleTag(problem.problem.title) %></a></td> <td><a href="<%= syzoj.utils.makeUrl(['contest', contest.id, i]) %>"><%= syzoj.utils.removeTitleTag(problem.problem.title) %></a></td>
<td class="center aligned">
<% if (problem.judge_id) { %>
<a href="<%= syzoj.utils.makeUrl(['submission', problem.judge_id]) %>"><i style="color: #000;" class="code icon"></i></a>
<% } %>
</td>
</tr> </tr>
<% } %> <% } %>
</tbody> </tbody>

21
views/contest_edit.ejs

@ -14,6 +14,27 @@
<% } %> <% } %>
</select> </select>
</div> </div>
<div class="inline fields">
<label>赛制</label>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="type" id="type-noi" value="noi"<% if (contest.type === 'noi') { %> checked="checked"<% } %>>
<label for="type-noi">NOI</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="type" id="type-ioi" value="ioi"<% if (contest.type === 'ioi') { %> checked="checked"<% } %>>
<label for="type-ioi">IOI</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="type" id="type-acm" value="acm"<% if (contest.type === 'acm') { %> checked="checked"<% } %>>
<label for="type-acm">ACM</label>
</div>
</div>
</div>
<div class="field"> <div class="field">
<label>比赛介绍</label> <label>比赛介绍</label>
<textarea class="" rows="5" id="doc-ta-1" name="information" class="font-content"><%= contest.information %></textarea> <textarea class="" rows="5" id="doc-ta-1" name="information" class="font-content"><%= contest.information %></textarea>

106
views/contest_ranklist.ejs

@ -4,6 +4,7 @@
.submit_time { .submit_time {
font-size: 0.8em; font-size: 0.8em;
margin-top: 5px; margin-top: 5px;
color: #000;
} }
</style> </style>
<div class="padding"> <div class="padding">
@ -12,12 +13,20 @@
<tr> <tr>
<th>#</th> <th>#</th>
<th>用户名</th> <th>用户名</th>
<% for (let problem of problems) { %> <% if (contest.type === 'acm') { %>
<th><a href="<%= syzoj.utils.makeUrl(['problem', problem.id]) %>"> <th>通过数量</th>
<%= syzoj.utils.removeTitleTag(problem.title) %> <th>罚时</th>
</a></th> <% } %>
<% for (let i = 0; i < problems.length; i++) { %>
<th>
<a href="<%= syzoj.utils.makeUrl(['contest', contest.id, i + 1]) %>">
<%= syzoj.utils.removeTitleTag(problems[i].title) %>
</a>
</th>
<% } %>
<% if (contest.type === 'noi' || contest.type === 'ioi') { %>
<th>总分</th>
<% } %> <% } %>
<th>总分</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -25,7 +34,7 @@
let i = 0; let i = 0;
for (let item of ranklist) { for (let item of ranklist) {
i++ i++
let latest = contest.start_time; let latest = contest.start_time, timeSum = 0, unacceptedCount = 0;
%> %>
<tr> <tr>
<td> <td>
@ -42,30 +51,73 @@
</div> </div>
</td> </td>
<td><a href="<%= syzoj.utils.makeUrl(['user', item.user.id]) %>"><%= item.user.username %></a><% if (item.user.nameplate) { %><%- item.user.nameplate %><% } %></td> <td><a href="<%= syzoj.utils.makeUrl(['user', item.user.id]) %>"><%= item.user.username %></a><% if (item.user.nameplate) { %><%- item.user.nameplate %><% } %></td>
<%
if (contest.type === 'acm') {
for (let problem of problems) {
if (item.player.score_details[problem.id] && item.player.score_details[problem.id].accepted) {
timeSum += (item.player.score_details[problem.id].acceptedTime - contest.start_time) + (item.player.score_details[problem.id].unacceptedCount * 20 * 60);
unacceptedCount += item.player.score_details[problem.id].unacceptedCount;
}
}
%>
<td>
<span class="score score_<%= parseInt((item.player.score / ranklist[0].player.score * 10) || 0) %>">
<%= item.player.score %>
</span>
</td>
<td>
<%= syzoj.utils.formatTime(timeSum) %>
</td>
<% } %>
<% for (let problem of problems) { %> <% for (let problem of problems) { %>
<% if (item.player.score_details[problem.id]) { %> <% if (!item.player.score_details[problem.id]) { %>
<td><a href="<%= syzoj.utils.makeUrl(['submission', item.player.score_details[problem.id].judge_id]) %>"> <td></td>
<span class="score score_<%= parseInt((item.player.score_details[problem.id].score / 10) || 0) %>"> <% } else if (contest.type === 'acm') { %>
<%= item.player.score_details[problem.id].score %> <td>
</span> <a href="<%= syzoj.utils.makeUrl(['submission', item.player.score_details[problem.id].judge_id]) %>">
</a> <% if (item.player.score_details[problem.id].accepted) { %>
<div class="submit_time"> <span class="score score_10">
<%= syzoj.utils.formatTime(item.player.score_details[problem.id].judge_state.submit_time - contest.start_time) %> <% if (item.player.score_details[problem.id].unacceptedCount) { %>
<% latest = Math.max(latest, item.player.score_details[problem.id].judge_state.submit_time) %> +<%= item.player.score_details[problem.id].unacceptedCount %>
</div> <% } else { %>
</td> +
<% } else { %> <% } %>
<td></td> </span>
<div class="submit_time">
<%= syzoj.utils.formatTime(item.player.score_details[problem.id].acceptedTime - contest.start_time) %>
</div>
<% } else { %>
<span class="score score_0">
-<%= item.player.score_details[problem.id].unacceptedCount %>
</span>
<% } %>
</a>
</td>
<% } else if (contest.type === 'noi' || contest.type === 'ioi') { %>
<td>
<a href="<%= syzoj.utils.makeUrl(['submission', item.player.score_details[problem.id].judge_id]) %>">
<span class="score score_<%= parseInt((item.player.score_details[problem.id].score / 10) || 0) %>">
<%= item.player.score_details[problem.id].score %>
</span>
</a>
<div class="submit_time">
<%= syzoj.utils.formatTime(item.player.score_details[problem.id].judge_state.submit_time - contest.start_time) %>
<% latest = Math.max(latest, item.player.score_details[problem.id].judge_state.submit_time) %>
</div>
</td>
<% } %>
<% } %> <% } %>
<% if (contest.type === 'noi' || contest.type === 'ioi') { %>
<td>
<span class="score score_<%= parseInt((item.player.score / ranklist[0].player.score * 10) || 0) %>">
<%= item.player.score %>
</span>
<div class="submit_time">
<%= syzoj.utils.formatTime(latest - contest.start_time) %>
</div>
</td>
<% } %> <% } %>
<td>
<span class="score score_<%= parseInt((item.player.score / ranklist[0].player.score * 10) || 0) %>">
<%= item.player.score %>
</span>
<div class="submit_time">
<%= syzoj.utils.formatTime(latest - contest.start_time) %>
</div>
</td>
</tr> </tr>
<% } %> <% } %>
</tbody> </tbody>

2
views/contest_submissions.ejs

@ -7,7 +7,7 @@
<div class="field"><input name="problem_id" style="width: 50px; " type="text" value="<%= form.problem_id %>"></div> <div class="field"><input name="problem_id" style="width: 50px; " type="text" value="<%= form.problem_id %>"></div>
<label style="font-size: 1.2em; margin-right: 3px; ">提交者:</label> <label style="font-size: 1.2em; margin-right: 3px; ">提交者:</label>
<div class="field"><input name="submitter" style="width: 100px; " type="text" value="<%= form.submitter %>"></div> <div class="field"><input name="submitter" style="width: 100px; " type="text" value="<%= form.submitter %>"></div>
<% if (contest.ended || (user && user.is_admin)) { %> <% if (contest.ended || contest.type !== 'noi' || (user && user.is_admin)) { %>
<label style="font-size: 1.2em; margin-right: 3px; ">分数:</label> <label style="font-size: 1.2em; margin-right: 3px; ">分数:</label>
<div class="field" style="padding-right: 6px; "><input name="min_score" style="width: 45px; " type="text" value="<%= form.min_score || 0 %>"></div> <div class="field" style="padding-right: 6px; "><input name="min_score" style="width: 45px; " type="text" value="<%= form.min_score || 0 %>"></div>
<label style="font-size: 1.2em; margin-right: 7px; ">~</label> <label style="font-size: 1.2em; margin-right: 7px; ">~</label>

3
views/header.ejs

@ -24,6 +24,9 @@
<a class="item<% if (active.startsWith('ranklist')) { %> active<% } %>" href="/ranklist"><i class="signal icon"></i> 排名</a> <a class="item<% if (active.startsWith('ranklist')) { %> active<% } %>" href="/ranklist"><i class="signal icon"></i> 排名</a>
<a class="item<% if (active.startsWith('discussion') || active.startsWith('article')) { %> active<% } %>" href="/discussion"><i class="comments icon"></i> 讨论</a> <a class="item<% if (active.startsWith('discussion') || active.startsWith('article')) { %> active<% } %>" href="/discussion"><i class="comments icon"></i> 讨论</a>
<a class="item<% if (active.startsWith('help')) { %> active<% } %>" href="/help"><i class="help circle icon"></i> 帮助</a> <a class="item<% if (active.startsWith('help')) { %> active<% } %>" href="/help"><i class="help circle icon"></i> 帮助</a>
<% if (typeof contest !== 'undefined' && contest && contest.id) { %>
<a id="back_to_contest" class="item" href="<%= syzoj.utils.makeUrl(['contest', contest.id]) %>"><i class="arrow left icon"></i> 返回比赛</a>
<% } %>
<div class="right menu"> <div class="right menu">
<% if (user) { %> <% if (user) { %>
<a href="<%= syzoj.utils.makeUrl(['user', user.id]) %>" style="color: inherit; "> <a href="<%= syzoj.utils.makeUrl(['user', user.id]) %>" style="color: inherit; ">

58
views/submission_content.ejs

@ -126,37 +126,37 @@ else problemUrl = syzoj.utils.makeUrl(['problem', judge.problem_id]);
<div class="accordion" style="margin-top: 0; "> <div class="accordion" style="margin-top: 0; ">
<% } %> <% } %>
<% for (let i = 0; i < subtask_cases.case_num; i++) { %> <% for (let i = 0; i < subtask_cases.case_num; i++) { %>
<% let testcase = subtask_cases[i]; %> <% let testcase = subtask_cases[i]; %>
<div class="title<% if (testcase.pending) { %> pending<% } %> auto_update"<% if (testcase.pending) { %> style="cursor: auto; "<% } %>> <div class="title<% if (testcase.pending || !judge.allowedSeeData) { %> pending<% } %> auto_update"<% if (testcase.pending || !judge.allowedSeeData) { %> 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 (!testcase.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.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 class="content auto_update">
<% if (!testcase.pending && judge.allowedSeeData) { %>
<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>
<div class="content auto_update">
<% 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>
<% } %> <% } %>
<% if (judge.result.subtasks.length !== 1) { %> <% if (judge.result.subtasks.length !== 1) { %>
</div></div> </div></div>

Loading…
Cancel
Save