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-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
|
|
|
|
points = 0
|
|
|
|
format_data = {}
|
|
|
|
|
|
|
|
with connection.cursor() as cursor:
|
2022-05-14 17:57:27 +00:00
|
|
|
cursor.execute(
|
|
|
|
"""
|
2020-01-21 06:35:58 +00:00
|
|
|
SELECT MAX(cs.points) as `score`, (
|
|
|
|
SELECT MIN(csub.date)
|
|
|
|
FROM judge_contestsubmission ccs LEFT OUTER JOIN
|
|
|
|
judge_submission csub ON (csub.id = ccs.submission_id)
|
|
|
|
WHERE ccs.problem_id = cp.id AND ccs.participation_id = %s AND ccs.points = MAX(cs.points)
|
|
|
|
) AS `time`, cp.id AS `prob`
|
|
|
|
FROM judge_contestproblem cp INNER JOIN
|
|
|
|
judge_contestsubmission cs ON (cs.problem_id = cp.id AND cs.participation_id = %s) LEFT OUTER JOIN
|
|
|
|
judge_submission sub ON (sub.id = cs.submission_id)
|
|
|
|
GROUP BY cp.id
|
2022-05-14 17:57:27 +00:00
|
|
|
""",
|
|
|
|
(participation.id, participation.id),
|
|
|
|
)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
for score, time, prob in cursor.fetchall():
|
2022-05-14 17:57:27 +00:00
|
|
|
if self.config["cumtime"]:
|
|
|
|
dt = (
|
|
|
|
from_database_time(time) - participation.start
|
|
|
|
).total_seconds()
|
2020-01-21 06:35:58 +00:00
|
|
|
if score:
|
|
|
|
cumtime += dt
|
|
|
|
else:
|
|
|
|
dt = 0
|
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
format_data[str(prob)] = {"time": dt, "points": score}
|
2020-01-21 06:35:58 +00:00
|
|
|
points += score
|
|
|
|
|
|
|
|
participation.cumtime = max(cumtime, 0)
|
|
|
|
participation.score = points
|
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(
|
2020-12-28 03:05:22 +00:00
|
|
|
'<td class="{state} problem-score-col"><a href="{url}">{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
|
|
|
|
)
|
|
|
|
),
|
|
|
|
url=reverse(
|
|
|
|
"contest_user_submissions",
|
|
|
|
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
|
|
|
)
|