Add frozen subtasks

This commit is contained in:
cuom1999 2022-12-20 02:24:24 -06:00
parent bdd30f94b7
commit 6bd5bb290f
13 changed files with 117 additions and 34 deletions

View file

@ -1099,7 +1099,7 @@ urlpatterns = [
]
),
),
url(r"^resolver/(?P<contest>\w+)",resolver.Resolver.as_view(), name="resolver")
url(r"^resolver/(?P<contest>\w+)", resolver.Resolver.as_view(), name="resolver"),
] + url_static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# if hasattr(settings, "INTERNAL_IPS"):

View file

@ -3,7 +3,7 @@ from django.contrib import admin
from django.core.exceptions import PermissionDenied
from django.db import connection, transaction
from django.db.models import Q, TextField
from django.forms import ModelForm, ModelMultipleChoiceField
from django.forms import ModelForm, ModelMultipleChoiceField, TextInput
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
@ -66,7 +66,13 @@ class ContestTagAdmin(admin.ModelAdmin):
class ContestProblemInlineForm(ModelForm):
class Meta:
widgets = {"problem": AdminHeavySelect2Widget(data_view="problem_select2")}
widgets = {
"problem": AdminHeavySelect2Widget(data_view="problem_select2"),
"frozen_subtasks": TextInput(attrs={"size": "3"}),
"points": TextInput(attrs={"size": "1"}),
"order": TextInput(attrs={"size": "1"}),
"output_prefix_override": TextInput(attrs={"size": "1"}),
}
class ContestProblemInline(admin.TabularInline):
@ -79,6 +85,7 @@ class ContestProblemInline(admin.TabularInline):
"partial",
"is_pretested",
"max_submissions",
"frozen_subtasks",
"output_prefix_override",
"order",
"rejudge_column",

View file

@ -8,4 +8,3 @@ def finished_submission(sub):
keys += ["contest_complete:%d" % participation.id]
keys += ["contest_attempted:%d" % participation.id]
cache.delete_many(keys)

View file

@ -98,15 +98,22 @@ class BaseContestFormat(metaclass=ABCMeta):
return "partial-score"
def handle_frozen_state(self, participation, format_data):
if not self.contest.freeze_after:
return
frozen_subtasks = {}
if hasattr(self, "get_frozen_subtasks"):
frozen_subtasks = self.get_frozen_subtasks()
queryset = participation.submissions.values("problem_id").annotate(
time=Max("submission__date")
)
for result in queryset:
problem = str(result["problem_id"])
if format_data.get(problem):
if result["time"] >= self.contest.freeze_after + participation.start:
is_after_freeze = (
self.contest.freeze_after
and result["time"]
>= self.contest.freeze_after + participation.start
)
if is_after_freeze or frozen_subtasks.get(problem):
format_data[problem]["frozen"] = True
else:
format_data[problem] = {"time": 0, "points": 0, "frozen": True}

View file

@ -111,7 +111,9 @@ class IOIContestFormat(DefaultContestFormat):
contest_problem.problem.code,
],
),
points=floatformat(format_data["points"]),
points=floatformat(
format_data["points"], -self.contest.points_precision
),
time=nice_repr(timedelta(seconds=format_data["time"]), "noday")
if self.config["cumtime"]
else "",
@ -122,7 +124,7 @@ class IOIContestFormat(DefaultContestFormat):
def display_participation_result(self, participation):
return format_html(
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
points=floatformat(participation.score),
points=floatformat(participation.score, -self.contest.points_precision),
cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday")
if self.config["cumtime"]
else "",

View file

@ -14,6 +14,21 @@ class NewIOIContestFormat(IOIContestFormat):
cumtime: Specify True if time penalties are to be computed. Defaults to False.
"""
def get_frozen_subtasks(self):
queryset = self.contest.contest_problems.values_list("id", "frozen_subtasks")
res = {}
for problem_id, frozen_subtasks in queryset:
subtasks = set()
if frozen_subtasks:
frozen_subtasks = frozen_subtasks.split(",")
for i in frozen_subtasks:
try:
subtasks.add(int(i))
except Exception as e:
pass
res[str(problem_id)] = subtasks
return res
def get_results_by_subtask(self, participation, include_frozen=False):
frozen_time = self.contest.end_time
if self.contest.freeze_after and not include_frozen:
@ -65,6 +80,7 @@ class NewIOIContestFormat(IOIContestFormat):
ON (sub.id = cs.submission_id AND sub.status = 'D')
INNER JOIN judge_submissiontestcase tc
ON sub.id = tc.submission_id
WHERE sub.date < %s
GROUP BY cp.id, tc.batch, sub.id
) r
GROUP BY prob, batch
@ -73,7 +89,12 @@ class NewIOIContestFormat(IOIContestFormat):
WHERE p.max_batch_points = q.batch_points
GROUP BY q.prob, q.batch
""",
(participation.id, to_database_time(frozen_time), participation.id),
(
participation.id,
to_database_time(frozen_time),
participation.id,
to_database_time(frozen_time),
),
)
return cursor.fetchall()
@ -82,6 +103,7 @@ class NewIOIContestFormat(IOIContestFormat):
cumtime = 0
score = 0
format_data = {}
frozen_subtasks = self.get_frozen_subtasks()
for (
problem_id,
@ -101,10 +123,11 @@ class NewIOIContestFormat(IOIContestFormat):
if format_data.get(problem_id) is None:
format_data[problem_id] = {"points": 0, "time": 0, "total_points": 0}
format_data[problem_id]["points"] += subtask_points
if subtask not in frozen_subtasks.get(problem_id, set()):
format_data[problem_id]["points"] += subtask_points
format_data[problem_id]["total_points"] += total_subtask_points
format_data[problem_id]["time"] = max(dt, format_data[problem_id]["time"])
format_data[problem_id]["problem_points"] = problem_points
format_data[problem_id]["total_points"] += total_subtask_points
for problem_data in format_data.values():
if not problem_data["total_points"]:

View file

@ -81,4 +81,4 @@ class DarkModeMiddleware(object):
return HttpResponseRedirect(
reverse("toggle_darkmode") + "?next=" + urlquote(request.path)
)
return self.get_response(request)
return self.get_response(request)

View file

@ -0,0 +1,24 @@
# Generated by Django 3.2.16 on 2022-12-20 06:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("judge", "0140_alter_contest_format_name"),
]
operations = [
migrations.AddField(
model_name="contestproblem",
name="frozen_subtasks",
field=models.CharField(
blank=True,
help_text="Only for format new IOI. Separated by commas, e.g: 2, 3",
max_length=20,
null=True,
verbose_name="frozen subtasks",
),
),
]

View file

@ -774,6 +774,13 @@ class ContestProblem(models.Model):
MinValueValidator(0, _("Why include a problem you " "can't submit to?"))
],
)
frozen_subtasks = models.CharField(
help_text=_("Only for format new IOI. Separated by commas, e.g: 2, 3"),
verbose_name=_("frozen subtasks"),
null=True,
blank=True,
max_length=20,
)
@property
def clarifications(self):

View file

@ -2,6 +2,7 @@ from django.views.generic import TemplateView
from django.utils.translation import gettext as _
from django.http import HttpResponseForbidden
class Resolver(TemplateView):
title = _("Resolver")
template_name = "resolver/resolver.html"
@ -15,5 +16,3 @@ class Resolver(TemplateView):
if request.user.is_superuser:
return super(Resolver, self).get(request, *args, **kwargs)
return HttpResponseForbidden()

View file

@ -842,6 +842,7 @@ class UserContestSubmissionsAjax(UserContestSubmissions):
total_points = 0
problem_points = 0
achieved_points = 0
frozen_subtasks = self.contest.format.get_frozen_subtasks()
for (
problem_id,
@ -860,25 +861,38 @@ class UserContestSubmissionsAjax(UserContestSubmissions):
subtask = 0
problem_points = pp
submission = Submission.objects.get(id=sub_id)
best_subtasks[subtask] = {
"submission": submission,
"contest_time": nice_repr(self.contest_time(submission), "noday"),
"points": subtask_points,
"total": total_subtask_points,
}
if subtask in frozen_subtasks.get(str(problem_id), set()):
best_subtasks[subtask] = {
"submission": submission,
"contest_time": nice_repr(
self.contest_time(submission), "noday"
),
"points": "???",
"total": total_subtask_points,
}
else:
best_subtasks[subtask] = {
"submission": submission,
"contest_time": nice_repr(
self.contest_time(submission), "noday"
),
"points": subtask_points,
"total": total_subtask_points,
}
achieved_points += subtask_points
total_points += total_subtask_points
achieved_points += subtask_points
for subtask in best_subtasks.values():
subtask["points"] = floatformat(
subtask["points"] / total_points * problem_points,
-self.contest.points_precision,
)
if subtask["points"] != "???":
subtask["points"] = floatformat(
subtask["points"] / total_points * problem_points,
-self.contest.points_precision,
)
subtask["total"] = floatformat(
subtask["total"] / total_points * problem_points,
-self.contest.points_precision,
)
achieved_points = achieved_points / total_points * problem_points
if best_subtasks:
if total_points > 0 and best_subtasks:
achieved_points = achieved_points / total_points * problem_points
return best_subtasks, achieved_points, problem_points
return None
@ -914,9 +928,10 @@ class UserContestSubmissionsAjax(UserContestSubmissions):
context["points"],
context["total"],
) = best_subtasks
context["points"] = floatformat(
context["points"], -self.contest.points_precision
)
if context["points"] != "???":
context["points"] = floatformat(
context["points"], -self.contest.points_precision
)
context["total"] = floatformat(
context["total"], -self.contest.points_precision
)

View file

@ -630,4 +630,4 @@ def toggle_darkmode(request):
if not path:
return HttpResponseBadRequest()
request.session["darkmode"] = not request.session.get("darkmode", False)
return HttpResponseRedirect(path)
return HttpResponseRedirect(path)

View file

@ -10,7 +10,7 @@
<td class="lightbox-submissions-time">
<b>{{_('Subtask')}} {{subtask}}:</b>
</td>
<td class="lightbox-submissions-time case-{{'AC' if cur_subtask.points == cur_subtask.total else 'WA'}}">
<td class="lightbox-submissions-time case-{{'AC' if cur_subtask.points == cur_subtask.total else ('TLE' if cur_subtask.points == '???' else 'WA')}}">
{{ cur_subtask.points }} / {{ cur_subtask.total }}
</td>
<td>
@ -28,7 +28,7 @@
<td class="lightbox-submissions-time">
<b>{{_('Total')}}:</b>
</td>
<td style="border-top: 1px black solid" class="case-{{'AC' if points == total else 'WA'}}">
<td style="border-top: 1px solid" class="case-{{'AC' if points == total else 'WA'}}">
{{ points }} / {{ total }}
</td>
</tr>