NDOJ/judge/contest_format/ioi.py

130 lines
4.7 KiB
Python
Raw Normal View History

2020-01-21 06:35:58 +00:00
from datetime import timedelta
from django.core.exceptions import ValidationError
from django.db import connection
from django.template.defaultfilters import floatformat
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
from judge.timezone import from_database_time
from judge.utils.timedelta import nice_repr
2022-11-18 22:59:58 +00:00
from django.db.models import Min, OuterRef, Subquery
2020-01-21 06:35:58 +00:00
2022-05-14 17:57:27 +00:00
@register_contest_format("ioi")
2020-01-21 06:35:58 +00:00
class IOIContestFormat(DefaultContestFormat):
2022-05-14 17:57:27 +00:00
name = gettext_lazy("IOI")
config_defaults = {"cumtime": False}
"""
2020-01-21 06:35:58 +00:00
cumtime: Specify True if time penalties are to be computed. Defaults to False.
2022-05-14 17:57:27 +00:00
"""
2020-01-21 06:35:58 +00:00
@classmethod
def validate(cls, config):
if config is None:
return
if not isinstance(config, dict):
2022-05-14 17:57:27 +00:00
raise ValidationError(
"IOI-styled contest expects no config or dict as config"
)
2020-01-21 06:35:58 +00:00
for key, value in config.items():
if key not in cls.config_defaults:
raise ValidationError('unknown config key "%s"' % key)
if not isinstance(value, type(cls.config_defaults[key])):
raise ValidationError('invalid type for config key "%s"' % key)
def __init__(self, contest, config):
self.config = self.config_defaults.copy()
self.config.update(config or {})
self.contest = contest
def update_participation(self, participation):
cumtime = 0
2022-11-18 22:59:58 +00:00
score = 0
2020-01-21 06:35:58 +00:00
format_data = {}
2022-11-18 22:59:58 +00:00
queryset = participation.submissions
if self.contest.freeze_after:
queryset = queryset.filter(
submission__date__lt=participation.start + self.contest.freeze_after
2022-05-14 17:57:27 +00:00
)
2020-01-21 06:35:58 +00:00
2022-11-18 22:59:58 +00:00
queryset = (
queryset.values("problem_id")
.filter(
points=Subquery(
queryset.filter(problem_id=OuterRef("problem_id"))
.order_by("-points")
.values("points")[:1]
)
)
.annotate(time=Min("submission__date"))
.values_list("problem_id", "time", "points")
)
for problem_id, time, points in queryset:
if self.config["cumtime"]:
dt = (time - participation.start).total_seconds()
if points:
cumtime += dt
else:
dt = 0
2020-01-21 06:35:58 +00:00
2022-11-18 22:59:58 +00:00
format_data[str(problem_id)] = {"points": points, "time": dt}
score += points
2020-01-21 06:35:58 +00:00
2022-11-18 22:59:58 +00:00
self.handle_frozen_state(participation, format_data)
2020-01-21 06:35:58 +00:00
participation.cumtime = max(cumtime, 0)
2022-11-18 22:59:58 +00:00
participation.score = score
2021-05-24 20:18:39 +00:00
participation.tiebreaker = 0
2020-01-21 06:35:58 +00:00
participation.format_data = format_data
participation.save()
def display_user_problem(self, participation, contest_problem):
format_data = (participation.format_data or {}).get(str(contest_problem.id))
if format_data:
return format_html(
'<td class="{state} problem-score-col"><a data-featherlight="{url}" href="#">{points}<div class="solving-time">{time}</div></a></td>',
2022-05-14 17:57:27 +00:00
state=(
(
"pretest-"
if self.contest.run_pretests_only
and contest_problem.is_pretested
else ""
)
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
2022-11-18 22:59:58 +00:00
+ (" frozen" if format_data.get("frozen") else "")
2022-05-14 17:57:27 +00:00
),
url=reverse(
"contest_user_submissions_ajax",
2022-05-14 17:57:27 +00:00
args=[
self.contest.key,
participation.user.user.username,
contest_problem.problem.code,
],
),
points=floatformat(format_data["points"]),
time=nice_repr(timedelta(seconds=format_data["time"]), "noday")
if self.config["cumtime"]
else "",
2020-01-21 06:35:58 +00:00
)
else:
2020-12-28 03:05:22 +00:00
return mark_safe('<td class="problem-score-col"></td>')
2020-01-21 06:35:58 +00:00
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),
2022-05-14 17:57:27 +00:00
cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday")
if self.config["cumtime"]
else "",
2020-01-21 06:35:58 +00:00
)