Skip to content

Commit

Permalink
Implement contest settings short display; #695
Browse files Browse the repository at this point in the history
  • Loading branch information
Ninjaclasher committed Jun 19, 2021
1 parent d3e9298 commit fe9643a
Show file tree
Hide file tree
Showing 13 changed files with 248 additions and 14 deletions.
2 changes: 1 addition & 1 deletion judge/admin/contest.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class ContestAdmin(NoBatchDeleteMixin, VersionAdmin):
fieldsets = (
(None, {'fields': ('key', 'name', 'authors', 'curators', 'testers')}),
(_('Settings'), {'fields': ('is_visible', 'use_clarifications', 'hide_problem_tags', 'hide_problem_authors',
'run_pretests_only', 'locked_after', 'scoreboard_visibility',
'show_short_display', 'run_pretests_only', 'locked_after', 'scoreboard_visibility',
'points_precision')}),
(_('Scheduling'), {'fields': ('start_time', 'end_time', 'time_limit')}),
(_('Details'), {'fields': ('description', 'og_image', 'logo_override_image', 'tags', 'summary')}),
Expand Down
15 changes: 14 additions & 1 deletion judge/contest_format/atcoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 django.utils.translation import gettext as _, gettext_lazy, ungettext

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -112,3 +112,16 @@ def display_user_problem(self, participation, contest_problem):
)
else:
return mark_safe('<td></td>')

def get_short_form_display(self):
yield _('The maximum score submission for each problem will be used.')

penalty = self.config['penalty']
if penalty:
yield ungettext(
'Each submission before the first maximum score submission with incur a **penalty of %d minute**.',
'Each submission before the first maximum score submission with incur a **penalty of %d minutes**.',
penalty,
) % penalty

yield _('Ties will be broken by the last score altering submission time.')
9 changes: 9 additions & 0 deletions judge/contest_format/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ def get_label_for_problem(self, index):
"""
raise NotImplementedError()

@abstractmethod
def get_short_form_display(self):
"""
Returns a generator of markdown strings to display the contest format's settings in short form.
:return A generator, where each item is an individual line.
"""
raise NotImplementedError()

@classmethod
def best_solution_state(cls, points, total):
if not points:
Expand Down
6 changes: 5 additions & 1 deletion judge/contest_format/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 django.utils.translation import gettext as _, gettext_lazy

from judge.contest_format.base import BaseContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -74,3 +74,7 @@ def get_problem_breakdown(self, participation, contest_problems):

def get_label_for_problem(self, index):
return str(index + 1)

def get_short_form_display(self):
yield _('The maximum score submission for each problem will be used.')
yield _('Ties will be broken by the sum of the last submission time on problems with a non-zero score.')
24 changes: 23 additions & 1 deletion judge/contest_format/ecoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 django.utils.translation import gettext as _, gettext_lazy, ungettext

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -125,3 +125,25 @@ def display_participation_result(self, participation):
points=floatformat(participation.score, -self.contest.points_precision),
cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday') if self.config['cumtime'] else '',
)

def get_short_form_display(self):
yield _('The score on your **last** non-CE submission for each problem will be used.')

first_ac_bonus = self.config['first_ac_bonus']
if first_ac_bonus:
yield _(
'There is a **%d bonus** for fully solving on your first non-CE submission.'
) % first_ac_bonus

time_bonus = self.config['time_bonus']
if time_bonus:
yield ungettext(
'For every **1 minute** you submit before the end of your window, there will be a **1** point bonus.',
'For every **%d minutes** you submit before the end of your window, there will be a **1** point bonus.',
time_bonus,
) % time_bonus

if self.config['cumtime']:
yield _('Ties will be broken by the sum of the last submission time on **all** problems.')
else:
yield _('Ties by score will **not** be broken.')
16 changes: 15 additions & 1 deletion judge/contest_format/icpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 django.utils.translation import gettext as _, gettext_lazy, ungettext

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -122,3 +122,17 @@ def get_label_for_problem(self, index):
ret += chr((index - 1) % 26 + 65)
index = (index - 1) // 26
return ret[::-1]

def get_short_form_display(self):
yield _('The maximum score submission for each problem will be used.')

penalty = self.config['penalty']
if penalty:
yield ungettext(
'Each submission before the first maximum score submission with incur a **penalty of %d minute**.',
'Each submission before the first maximum score submission with incur a **penalty of %d minutes**.',
penalty,
) % penalty

yield _('Ties will be broken by the sum of the last score altering submission time on problems with a non-zero '
'score, followed by the time of the last score altering submission.')
13 changes: 11 additions & 2 deletions judge/contest_format/ioi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.db import connection
from django.utils.translation import gettext_lazy
from django.utils.translation import gettext as _, gettext_lazy

from judge.contest_format.legacy_ioi import LegacyIOIContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -79,7 +79,7 @@ def update_participation(self, participation):
format_data[problem_id]['points'] += subtask_points
format_data[problem_id]['time'] = max(dt, format_data[problem_id]['time'])

for _, problem_data in format_data.items():
for problem_data in format_data.values():
penalty = problem_data['time']
points = problem_data['points']
if self.config['cumtime'] and points:
Expand All @@ -91,3 +91,12 @@ def update_participation(self, participation):
participation.tiebreaker = 0
participation.format_data = format_data
participation.save()

def get_short_form_display(self):
yield _('The maximum score for each problem batch will be used.')

if self.config['cumtime']:
yield _('Ties will be broken by the sum of the last score altering submission time on problems with a '
'non-zero score.')
else:
yield _('Ties by score will **not** be broken.')
11 changes: 10 additions & 1 deletion judge/contest_format/legacy_ioi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 django.utils.translation import gettext as _, gettext_lazy

from judge.contest_format.default import DefaultContestFormat
from judge.contest_format.registry import register_contest_format
Expand Down Expand Up @@ -92,3 +92,12 @@ def display_participation_result(self, participation):
points=floatformat(participation.score, -self.contest.points_precision),
cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday') if self.config['cumtime'] else '',
)

def get_short_form_display(self):
yield _('The maximum score submission for each problem will be used.')

if self.config['cumtime']:
yield _('Ties will be broken by the sum of the last score altering submission time on problems with a '
'non-zero score.')
else:
yield _('Ties by score will **not** be broken.')
18 changes: 18 additions & 0 deletions judge/migrations/0122_contest_show_short_display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.24 on 2021-06-19 01:53

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('judge', '0121_per_problem_sub_access_control'),
]

operations = [
migrations.AddField(
model_name='contest',
name='show_short_display',
field=models.BooleanField(default=False, help_text='Whether to show a section containing contest settings on the contest page or not.', verbose_name='show short form settings display'),
),
]
4 changes: 4 additions & 0 deletions judge/models/contest.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ class Contest(models.Model):
'testcases. Commonly set during a contest, then unset '
'prior to rejudging user submissions when the contest ends.'),
default=False)
show_short_display = models.BooleanField(verbose_name=_('show short form settings display'),
help_text=_('Whether to show a section containing contest settings '
'on the contest page or not.'),
default=False)
is_organization_private = models.BooleanField(verbose_name=_('private to organizations'), default=False)
organizations = models.ManyToManyField(Organization, blank=True, verbose_name=_('organizations'),
help_text=_('If private, only these organizations may see the contest'))
Expand Down
19 changes: 17 additions & 2 deletions judge/views/contests.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,23 @@ def get_context_data(self, **kwargs):
.annotate(has_public_editorial=Sum(Case(When(solution__is_public=True, then=1),
default=0, output_field=IntegerField()))) \
.add_i18n_name(self.request.LANGUAGE_CODE)
context['contest_has_public_editorials'] = any(
problem.is_public and problem.has_public_editorial for problem in context['contest_problems']
context['metadata'] = {
'has_public_editorials': any(
problem.is_public and problem.has_public_editorial for problem in context['contest_problems']
),
}
context['metadata'].update(
**self.object.contest_problems
.annotate(
partials_enabled=F('partial').bitand(F('problem__partial')),
pretests_enabled=F('is_pretested').bitand(F('contest__run_pretests_only')),
)
.aggregate(
has_partials=Sum('partials_enabled'),
has_pretests=Sum('pretests_enabled'),
has_submission_cap=Sum('max_submissions'),
problem_count=Count('id'),
),
)
return context

Expand Down
12 changes: 10 additions & 2 deletions resources/contest.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
#banner {
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
padding-bottom: 1em;
color: rgb(85, 85, 85);
font-size: $base_font_size;

a.date {
display: block;
Expand All @@ -114,8 +116,14 @@
#time {
text-align: center;
display: block;
color: rgb(85, 85, 85);
font-size: $base_font_size;
}

div#details ul {
margin-bottom: 0;
list-style: none;
p {
margin: 0;
}
}
}

Expand Down
Loading

0 comments on commit fe9643a

Please # to comment.