NDOJ/judge/contest_format/default.py
2023-05-20 08:52:37 +09:00

115 lines
4.2 KiB
Python
Executable file

from datetime import timedelta
from django.core.exceptions import ValidationError
from django.db.models import Max
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.base import BaseContestFormat
from judge.contest_format.registry import register_contest_format
from judge.utils.timedelta import nice_repr
@register_contest_format("default")
class DefaultContestFormat(BaseContestFormat):
name = gettext_lazy("Default")
@classmethod
def validate(cls, config):
if config is not None and (not isinstance(config, dict) or config):
raise ValidationError(
"default contest expects no config or empty dict as config"
)
def __init__(self, contest, config):
super(DefaultContestFormat, self).__init__(contest, config)
def update_participation(self, participation):
cumtime = 0
points = 0
format_data = {}
queryset = participation.submissions
if self.contest.freeze_after:
queryset = queryset.filter(
submission__date__lt=participation.start + self.contest.freeze_after
)
queryset = queryset.values("problem_id").annotate(
time=Max("submission__date"),
points=Max("points"),
)
for result in queryset:
dt = (result["time"] - participation.start).total_seconds()
if result["points"]:
cumtime += dt
format_data[str(result["problem_id"])] = {
"time": dt,
"points": result["points"],
}
points += result["points"]
self.handle_frozen_state(participation, format_data)
participation.cumtime = max(cumtime, 0)
participation.score = round(points, self.contest.points_precision)
participation.tiebreaker = 0
participation.format_data = format_data
participation.save()
def display_user_problem(self, participation, contest_problem, show_final=False):
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>',
state=(
(
"pretest-"
if self.contest.run_pretests_only
and contest_problem.is_pretested
else ""
)
+ self.best_solution_state(
format_data["points"], contest_problem.points
)
+ (" frozen" if format_data.get("frozen") else "")
),
url=reverse(
"contest_user_submissions_ajax",
args=[
self.contest.key,
participation.id,
contest_problem.problem.code,
],
),
points=floatformat(
format_data["points"], -self.contest.points_precision
),
time=nice_repr(timedelta(seconds=format_data["time"]), "noday"),
)
else:
return mark_safe('<td class="problem-score-col"></td>')
def display_participation_result(self, participation, show_final=False):
return format_html(
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
points=floatformat(participation.score, -self.contest.points_precision),
cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday"),
)
def get_problem_breakdown(self, participation, contest_problems):
return [
(participation.format_data or {}).get(str(contest_problem.id))
for contest_problem in contest_problems
]
def get_contest_problem_label_script(self):
return """
function(n)
return tostring(math.floor(n + 1))
end
"""