Skip to content

Commit

Permalink
Add in a new (custom) bonuses fmt
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Cameron <[email protected]>
  • Loading branch information
JasonLovesDoggo committed Nov 3, 2024
1 parent e262508 commit fda07dd
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
1 change: 1 addition & 0 deletions judge/contest_format/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from judge.contest_format.atcoder import AtCoderContestFormat
from judge.contest_format.bonuses import BonusesContestFormat
from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.ecoo import ECOOContestFormat
from judge.contest_format.icpc import ICPCContestFormat
Expand Down
97 changes: 97 additions & 0 deletions judge/contest_format/bonuses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from datetime import timedelta

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 as _, 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


@register_contest_format('bonuses')
class BonusesContestFormat(DefaultContestFormat):
"""
Used as a way to break ties by the sum of the last score
altering submission time on problems with a non-zero score.'
"""

name = gettext_lazy('Bonuses')

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:
cursor.execute(
"""
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
""",
(participation.id, participation.id),
)

for score, time, prob in cursor.fetchall():
time = from_database_time(time)
dt = (time - participation.start).total_seconds()

if score:
cumtime = max(cumtime, dt)

format_data[str(prob)] = {'time': dt, 'points': score}
points += score

participation.cumtime = cumtime
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):
format_data = (participation.format_data or {}).get(str(contest_problem.id))
if format_data:
return format_html(
'<td class="{state}"><a href="{url}">{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,
),
),
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'),
)
else:
return mark_safe('<td></td>')

def get_short_form_display(self):
yield _('The maximum score submission for each problem will be used.')
yield _('Ties will be broken by the last score altering submission time.')

0 comments on commit fda07dd

Please sign in to comment.