diff --git a/judge/contest_format/new_ioi.py b/judge/contest_format/new_ioi.py
index 9571c34..3661d7e 100644
--- a/judge/contest_format/new_ioi.py
+++ b/judge/contest_format/new_ioi.py
@@ -138,7 +138,7 @@ class NewIOIContestFormat(IOIContestFormat):
/ problem_data["total_points"]
* problem_data["problem_points"]
)
- if self.config["cumtime"] and points:
+ if self.config["cumtime"] and problem_data["points"]:
cumtime += penalty
score += problem_data["points"]
diff --git a/judge/views/contests.py b/judge/views/contests.py
index 743ea30..8df20b2 100644
--- a/judge/views/contests.py
+++ b/judge/views/contests.py
@@ -295,6 +295,7 @@ class ContestMixin(object):
context["meta_description"] = self.object.summary or metadata[0]
context["og_image"] = self.object.og_image or metadata[1]
context["has_moss_api_key"] = settings.MOSS_API_KEY is not None
+ context["can_use_resolver"] = self.object.format_name == "ioi16"
context["logo_override_image"] = self.object.logo_override_image
if (
not context["logo_override_image"]
diff --git a/judge/views/resolver.py b/judge/views/resolver.py
index db0c140..f53c16d 100644
--- a/judge/views/resolver.py
+++ b/judge/views/resolver.py
@@ -1,18 +1,148 @@
from django.views.generic import TemplateView
from django.utils.translation import gettext as _
from django.http import HttpResponseForbidden
+from judge.models import Contest
+from django.utils.safestring import mark_safe
+
+import json
class Resolver(TemplateView):
title = _("Resolver")
template_name = "resolver/resolver.html"
+ def get_contest_json(self):
+ problems = self.contest.contest_problems.values_list("order", "id")
+ order_to_id = {}
+ id_to_order = {}
+ for order, problem_id in problems:
+ id_to_order[str(problem_id)] = order
+
+ frozen_subtasks = self.contest.format.get_frozen_subtasks()
+ num_problems = len(problems)
+ problem_sub = [0] * num_problems
+ sub_frozen = [0] * num_problems
+ problems_json = {str(i): {} for i in range(1, num_problems + 1)}
+
+ users = {}
+ cnt_user = 0
+ total_subtask_points_map = {}
+
+ for participation in self.contest.users.filter(virtual=0):
+ cnt_user += 1
+ users[str(cnt_user)] = {
+ "username": participation.user.user.username,
+ "name": participation.user.user.first_name
+ or participation.user.user.username,
+ "school": participation.user.user.last_name,
+ "last_submission": participation.cumtime,
+ "problems": {},
+ }
+ for (
+ problem_id,
+ problem_points,
+ time,
+ subtask_points,
+ total_subtask_points,
+ subtask,
+ sub_id,
+ ) in self.contest.format.get_results_by_subtask(participation, True):
+ problem_id = str(problem_id)
+ order = id_to_order[problem_id]
+ problem_sub[order - 1] = max(problem_sub[order - 1], subtask)
+ if total_subtask_points:
+ total_subtask_points_map[(order, subtask)] = total_subtask_points
+
+ cnt_user = 0
+ for participation in self.contest.users.filter(virtual=0):
+ cnt_user += 1
+ total_points = {}
+ points_map = {}
+ frozen_points_map = {}
+ problem_points_map = {}
+ for (
+ problem_id,
+ problem_points,
+ time,
+ subtask_points,
+ total_subtask_points,
+ subtask,
+ sub_id,
+ ) in self.contest.format.get_results_by_subtask(participation, True):
+ problem_id = str(problem_id)
+ order = id_to_order[problem_id]
+ points_map[(order, subtask)] = subtask_points
+ if order not in total_points:
+ total_points[order] = 0
+ total_points[order] += total_subtask_points
+ problem_points_map[order] = problem_points
+
+ for (
+ problem_id,
+ problem_points,
+ time,
+ subtask_points,
+ total_subtask_points,
+ subtask,
+ sub_id,
+ ) in self.contest.format.get_results_by_subtask(participation, False):
+ problem_id = str(problem_id)
+ order = id_to_order[problem_id]
+ frozen_points_map[(order, subtask)] = subtask_points
+
+ for order in range(1, num_problems + 1):
+ for subtask in range(1, problem_sub[order - 1] + 1):
+ if not total_points.get(order, 0):
+ continue
+ if str(order) not in users[str(cnt_user)]["problems"]:
+ users[str(cnt_user)]["problems"][str(order)] = {
+ "points": {},
+ "frozen_points": {},
+ }
+ problems_json[str(order)][str(subtask)] = round(
+ total_subtask_points_map[(order, subtask)]
+ / total_points[order]
+ * problem_points_map[order],
+ self.contest.points_precision,
+ )
+ users[str(cnt_user)]["problems"][str(order)]["points"][
+ str(subtask)
+ ] = round(
+ points_map.get((order, subtask), 0)
+ / total_points[order]
+ * problem_points_map[order],
+ self.contest.points_precision,
+ )
+ users[str(cnt_user)]["problems"][str(order)]["frozen_points"][
+ str(subtask)
+ ] = round(
+ frozen_points_map.get((order, subtask), 0)
+ / total_points[order]
+ * problem_points_map[order],
+ self.contest.points_precision,
+ )
+
+ for i in frozen_subtasks:
+ order = id_to_order[i]
+ if frozen_subtasks[i]:
+ sub_frozen[order - 1] = min(frozen_subtasks[i])
+ else:
+ sub_frozen[order - 1] = problem_sub[order - 1] + 1
+ return {
+ "problem_sub": problem_sub,
+ "sub_frozen": sub_frozen,
+ "problems": problems_json,
+ "users": users,
+ }
+
def get_context_data(self, **kwargs):
context = super(Resolver, self).get_context_data(**kwargs)
- context["contest_json"] = "/static/contest.json"
+ context["contest_json"] = mark_safe(json.dumps(self.get_contest_json()))
return context
def get(self, request, *args, **kwargs):
if request.user.is_superuser:
- return super(Resolver, self).get(request, *args, **kwargs)
+ self.contest = Contest.objects.get(key=kwargs.get("contest"))
+ if self.contest.format_name == "ioi16":
+ return super(Resolver, self).get(request, *args, **kwargs)
return HttpResponseForbidden()
diff --git a/resources/resolver.css b/resources/resolver.css
index 6d7cee4..3b67421 100644
--- a/resources/resolver.css
+++ b/resources/resolver.css
@@ -252,7 +252,6 @@
.score {
font-weight: bold;
- width: 70px;
color: var(--theme-text-color);
}
diff --git a/resources/resolver.js b/resources/resolver.js
index 6ccbc45..53b7c07 100644
--- a/resources/resolver.js
+++ b/resources/resolver.js
@@ -10,6 +10,10 @@ function Resolver(problem_sub, sub_frozen, problems, users) {
this.delay = false;
}
+function round2(num) {
+ return Math.round(num * 100) / 100;
+}
+
Resolver.prototype.status = function (problem) {
if (problem.old_verdict == 'NA' && problem.new_verdict == 'NA') {
return 'untouched';
@@ -83,15 +87,18 @@ Resolver.prototype.calcOperations = function () {
this.rank[id].problem[problemid][j].old_point = this.users[id].problems[problemid].frozen_points[j];
this.rank[id].problem[problemid].old_point += this.rank[id].problem[problemid][j].old_point;
this.rank[id].problem[problemid][j].old_verdict = this.pointstatus(this.users[id].problems[problemid].frozen_points[j], problemid, j);
+ this.rank[id].problem[problemid].old_point = round2(this.rank[id].problem[problemid].old_point)
if (this.users[id].problems[problemid].points[j] != -1) {
this.rank[id].problem[problemid][j].new_point = this.users[id].problems[problemid].points[j];
this.rank[id].problem[problemid].new_point += this.rank[id].problem[problemid][j].new_point;
+ this.rank[id].problem[problemid].new_point = round2(this.rank[id].problem[problemid].new_point)
this.rank[id].problem[problemid][j].new_verdict = this.pointstatus(this.users[id].problems[problemid].points[j], problemid, j);
}
}
}
this.rank[id].problem[problemid].old_verdict = this.pointstatus(this.rank[id].problem[problemid].old_point);
this.rank[id].score += this.rank[id].problem[problemid].old_point;
+ this.rank[id].score = round2(this.rank[id].score)
if (this.users[id].problems[problemid].points[1] != -1) {
this.rank[id].problem[problemid].new_verdict = this.pointstatus(this.rank[id].problem[problemid].new_point);
}
@@ -162,6 +169,7 @@ Resolver.prototype.calcOperations = function () {
var tmp = this.rankarr[i];
if (tmp.problem[j].new_point > tmp.problem[j].old_point) {
tmp.score += tmp.problem[j].new_point - tmp.problem[j].old_point;
+ tmp.score = round2(tmp.score);
}
tmp.problem[j].old_point = tmp.problem[j].new_point;
tmp.problem[j].new_point = 0;
@@ -266,6 +274,7 @@ Resolver.prototype.operation = function (rankid, problemid, sub) {
this.rankarr[rankid].problem[problemid].new_point =
this.rankarr[rankid].problem[problemid].old_point + this.rankarr[rankid].problem[problemid][sub].new_point - this.rankarr[rankid].problem[problemid][sub].old_point;
this.rankarr[rankid].problem[problemid].new_verdict = this.pointstatus(this.rankarr[rankid].problem[problemid].new_point);
+ this.rankarr[rankid].problem[problemid].new_point = round2(this.rankarr[rankid].problem[problemid].new_point)
var op = {
id: this.operations.length,
type: 'sub',
@@ -299,6 +308,7 @@ Resolver.prototype.operation = function (rankid, problemid, sub) {
};
if (tmp.problem[problemid].new_point > tmp.problem[problemid].old_point) {
tmp.score += tmp.problem[problemid].new_point - tmp.problem[problemid].old_point;
+ tmp.score = round2(tmp.score)
}
tmp.problem[problemid].old_point = tmp.problem[problemid].new_point;
tmp.problem[problemid].new_point = 0;
diff --git a/templates/contest/contest-tabs.html b/templates/contest/contest-tabs.html
index 993e0dd..f6094e8 100644
--- a/templates/contest/contest-tabs.html
+++ b/templates/contest/contest-tabs.html
@@ -22,7 +22,7 @@
{{ make_tab_item('ranking', 'fa fa-bar-chart', None, _('Hidden Rankings')) }}
{% endif %}
{% endif %}
- {% if request.user.is_superuser %}
+ {% if request.user.is_superuser and can_use_resolver %}
{{ make_tab_item('resolver', 'fa fa-check', url('resolver', contest.key), _('Resolver')) }}
{% endif %}
{% if can_edit %}
diff --git a/templates/resolver/media-js.html b/templates/resolver/media-js.html
index d6fce6a..972d341 100644
--- a/templates/resolver/media-js.html
+++ b/templates/resolver/media-js.html
@@ -7,18 +7,15 @@
var speed = 700;
var autopress = false;
$(document).ready(function() {
- $.getJSON('{{ contest_json }}', function (data) {
- console.log("OK");
- var resolver = new Resolver(data.problem_sub, data.sub_frozen, data.problems, data.users);
- window.resolver = resolver;
- resolver.calcOperations();
- resolver.frozen_op = resolver.operations.length - 1;
- resetCSS();
- light_theme();
- show_rank();
- }).fail(function(){
- console.log("An error has occurred.");
- });
+ let data = {{ contest_json }};
+ console.log("OK");
+ var resolver = new Resolver(data.problem_sub, data.sub_frozen, data.problems, data.users);
+ window.resolver = resolver;
+ resolver.calcOperations();
+ resolver.frozen_op = resolver.operations.length - 1;
+ resetCSS();
+ light_theme();
+ show_rank();
});
function updateSelector() {
@@ -74,6 +71,7 @@
tmp.problem[operation.problem_index].old_verdict = operation.new_verdict;
tmp.problem[operation.problem_index].new_verdict = 'NA';
tmp.problem[operation.problem_index].old_point = operation.new_point;
+ tmp.score = round2(tmp.score);
$('#rank-' + operation.user_id + ' .p-' + operation.problem_index + ' .pro-score').removeClass('selected');
$('#rank-' + operation.user_id + ' .p-' + operation.problem_index + ' .pro-score').addClass(resolver.status(tmp.problem[operation.problem_index]));
$('#rank-' + operation.user_id + ' .score').text(tmp.score);
@@ -124,6 +122,7 @@
tmp.problem[operation.problem_index][operation.problem_sub].old_verdict = operation.new_verdict;
tmp.problem[operation.problem_index][operation.problem_sub].new_verdict = 'NA';
tmp.problem[operation.problem_index].old_point += operation.new_point - operation.old_point;
+ tmp.problem[operation.problem_index].old_point = round2(tmp.problem[operation.problem_index].old_point);
tmp.problem[operation.problem_index][operation.problem_sub].old_point = operation.new_point;
$('#rank-' + operation.user_id + ' .p-' + operation.problem_index + ' .pro-score').text(tmp.problem[operation.problem_index].old_point);
$('#rank-' + operation.user_id + ' .p-' + operation.problem_index + '.s-' + operation.problem_sub + ' .p-content').text(operation.new_point);
diff --git a/templates/resolver/resolver.html b/templates/resolver/resolver.html
index adeb516..3309425 100644
--- a/templates/resolver/resolver.html
+++ b/templates/resolver/resolver.html
@@ -8,7 +8,6 @@
-