diff --git a/judge/admin/contest.py b/judge/admin/contest.py index 1fc2201..906fcee 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -110,7 +110,7 @@ class ContestAdmin(VersionAdmin): fieldsets = ( (None, {'fields': ('key', 'name', 'organizers')}), (_('Settings'), {'fields': ('is_visible', 'use_clarifications', 'hide_problem_tags', 'hide_scoreboard', - 'run_pretests_only')}), + 'run_pretests_only', 'points_precision')}), (_('Scheduling'), {'fields': ('start_time', 'end_time', 'time_limit')}), (_('Details'), {'fields': ('description', 'og_image', 'logo_override_image', 'tags', 'summary')}), (_('Format'), {'fields': ('format_name', 'format_config')}), diff --git a/judge/contest_format/default.py b/judge/contest_format/default.py index d3cde2d..afa5a37 100644 --- a/judge/contest_format/default.py +++ b/judge/contest_format/default.py @@ -53,7 +53,7 @@ class DefaultContestFormat(BaseContestFormat): 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']), + points=floatformat(format_data['points'], -self.contest.points_precision), time=nice_repr(timedelta(seconds=format_data['time']), 'noday'), ) else: @@ -62,7 +62,7 @@ class DefaultContestFormat(BaseContestFormat): def display_participation_result(self, participation): return format_html( u'{points}
{cumtime}
', - points=floatformat(participation.score), + points=floatformat(participation.score, -self.contest.points_precision), cumtime=nice_repr(timedelta(seconds=participation.cumtime), 'noday'), ) diff --git a/judge/migrations/0111_contest_decimal_points.py b/judge/migrations/0111_contest_decimal_points.py new file mode 100644 index 0000000..4dc3968 --- /dev/null +++ b/judge/migrations/0111_contest_decimal_points.py @@ -0,0 +1,24 @@ +# Generated by Django 2.2.12 on 2020-10-26 19:51 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('judge', '0110_notification_author'), + ] + + operations = [ + migrations.AddField( + model_name='contest', + name='points_precision', + field=models.IntegerField(default=2, help_text='Number of digits to round points to.', validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10)], verbose_name='precision points'), + ), + migrations.AlterField( + model_name='contestparticipation', + name='score', + field=models.FloatField(db_index=True, default=0, verbose_name='score'), + ), + ] diff --git a/judge/models/contest.py b/judge/models/contest.py index 39f52b1..8b5c182 100644 --- a/judge/models/contest.py +++ b/judge/models/contest.py @@ -1,5 +1,5 @@ from django.core.exceptions import ValidationError -from django.core.validators import MinValueValidator, RegexValidator +from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.db import models, transaction from django.db.models import CASCADE from django.urls import reverse @@ -113,7 +113,10 @@ class Contest(models.Model): help_text=_('A JSON object to serve as the configuration for the chosen contest format ' 'module. Leave empty to use None. Exact format depends on the contest format ' 'selected.')) - + points_precision = models.IntegerField(verbose_name=_('precision points'), default=2, + validators=[MinValueValidator(0), MaxValueValidator(10)], + help_text=_('Number of digits to round points to.')) + @cached_property def format_class(self): return contest_format.formats[self.format_name] @@ -256,7 +259,7 @@ class ContestParticipation(models.Model): contest = models.ForeignKey(Contest, verbose_name=_('associated contest'), related_name='users', on_delete=CASCADE) user = models.ForeignKey(Profile, verbose_name=_('user'), related_name='contest_history', on_delete=CASCADE) real_start = models.DateTimeField(verbose_name=_('start time'), default=timezone.now, db_column='start') - score = models.IntegerField(verbose_name=_('score'), default=0, db_index=True) + score = models.FloatField(verbose_name=_('score'), default=0, db_index=True) cumtime = models.PositiveIntegerField(verbose_name=_('cumulative time'), default=0) is_disqualified = models.BooleanField(verbose_name=_('is disqualified'), default=False, help_text=_('Whether this participation is disqualified.'))