2020-01-21 06:35:58 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
@register_contest_format("default")
|
2020-01-21 06:35:58 +00:00
|
|
|
class DefaultContestFormat(BaseContestFormat):
|
2022-05-14 17:57:27 +00:00
|
|
|
name = gettext_lazy("Default")
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def validate(cls, config):
|
|
|
|
if config is not None and (not isinstance(config, dict) or config):
|
2022-05-14 17:57:27 +00:00
|
|
|
raise ValidationError(
|
|
|
|
"default contest expects no config or empty dict as config"
|
|
|
|
)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __init__(self, contest, config):
|
|
|
|
super(DefaultContestFormat, self).__init__(contest, config)
|
|
|
|
|
|
|
|
def update_participation(self, participation):
|
|
|
|
cumtime = 0
|
|
|
|
points = 0
|
|
|
|
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
|
|
|
|
)
|
|
|
|
|
|
|
|
queryset = queryset.values("problem_id").annotate(
|
2022-05-14 17:57:27 +00:00
|
|
|
time=Max("submission__date"),
|
|
|
|
points=Max("points"),
|
2022-11-18 22:59:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
for result in queryset:
|
2022-05-14 17:57:27 +00:00
|
|
|
dt = (result["time"] - participation.start).total_seconds()
|
|
|
|
if result["points"]:
|
2020-01-21 06:35:58 +00:00
|
|
|
cumtime += dt
|
2022-05-14 17:57:27 +00:00
|
|
|
format_data[str(result["problem_id"])] = {
|
|
|
|
"time": dt,
|
|
|
|
"points": result["points"],
|
|
|
|
}
|
|
|
|
points += result["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-22 04:05:35 +00:00
|
|
|
participation.score = round(points, self.contest.points_precision)
|
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()
|
|
|
|
|
2022-12-28 20:38:32 +00:00
|
|
|
def display_user_problem(self, participation, contest_problem, show_final=False):
|
2020-01-21 06:35:58 +00:00
|
|
|
format_data = (participation.format_data or {}).get(str(contest_problem.id))
|
|
|
|
if format_data:
|
|
|
|
return format_html(
|
2022-06-01 05:28:56 +00:00
|
|
|
'<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(
|
2022-06-01 05:28:56 +00:00
|
|
|
"contest_user_submissions_ajax",
|
2022-05-14 17:57:27 +00:00
|
|
|
args=[
|
|
|
|
self.contest.key,
|
2022-11-22 04:05:35 +00:00
|
|
|
participation.id,
|
2022-05-14 17:57:27 +00:00
|
|
|
contest_problem.problem.code,
|
|
|
|
],
|
|
|
|
),
|
|
|
|
points=floatformat(
|
|
|
|
format_data["points"], -self.contest.points_precision
|
|
|
|
),
|
|
|
|
time=nice_repr(timedelta(seconds=format_data["time"]), "noday"),
|
2020-01-21 06:35:58 +00:00
|
|
|
)
|
|
|
|
else:
|
2020-10-26 20:46:42 +00:00
|
|
|
return mark_safe('<td class="problem-score-col"></td>')
|
2020-01-21 06:35:58 +00:00
|
|
|
|
2022-12-28 20:38:32 +00:00
|
|
|
def display_participation_result(self, participation, show_final=False):
|
2020-01-21 06:35:58 +00:00
|
|
|
return format_html(
|
2022-05-14 17:57:27 +00:00
|
|
|
'<td class="user-points">{points}<div class="solving-time">{cumtime}</div></td>',
|
2020-10-26 20:13:17 +00:00
|
|
|
points=floatformat(participation.score, -self.contest.points_precision),
|
2022-05-14 17:57:27 +00:00
|
|
|
cumtime=nice_repr(timedelta(seconds=participation.cumtime), "noday"),
|
2020-01-21 06:35:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def get_problem_breakdown(self, participation, contest_problems):
|
2022-05-14 17:57:27 +00:00
|
|
|
return [
|
|
|
|
(participation.format_data or {}).get(str(contest_problem.id))
|
|
|
|
for contest_problem in contest_problems
|
|
|
|
]
|
2021-05-24 20:00:36 +00:00
|
|
|
|
|
|
|
def get_contest_problem_label_script(self):
|
2022-05-14 17:57:27 +00:00
|
|
|
return """
|
2021-05-24 20:00:36 +00:00
|
|
|
function(n)
|
|
|
|
return tostring(math.floor(n + 1))
|
|
|
|
end
|
2022-05-14 17:57:27 +00:00
|
|
|
"""
|