NDOJ/judge/tasks/contest.py
2023-05-20 08:53:43 +09:00

104 lines
3.7 KiB
Python

from celery import shared_task
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext as _
from moss import MOSS
from judge.models import Contest, ContestMoss, ContestParticipation, Submission
from judge.utils.celery import Progress
__all__ = ("rescore_contest", "run_moss")
@shared_task(bind=True)
def rescore_contest(self, contest_key):
contest = Contest.objects.get(key=contest_key)
participations = contest.users
rescored = 0
with Progress(
self, participations.count(), stage=_("Recalculating contest scores")
) as p:
for participation in participations.iterator():
for contest_submission in participation.submissions.iterator():
submission = contest_submission.submission
contest_problem = contest_submission.problem
contest_submission.points = round(
submission.case_points
/ submission.case_total
* contest_problem.points
if submission.case_total > 0
else 0,
3,
)
if (
not contest_problem.partial
and contest_submission.points != contest_problem.points
):
contest_submission.points = 0
contest_submission.save()
participation.recompute_results()
rescored += 1
if rescored % 10 == 0:
p.done = rescored
return rescored
@shared_task(bind=True)
def run_moss(self, contest_key):
moss_api_key = settings.MOSS_API_KEY
if moss_api_key is None:
raise ImproperlyConfigured("No MOSS API Key supplied")
contest = Contest.objects.get(key=contest_key)
ContestMoss.objects.filter(contest=contest).delete()
length = len(ContestMoss.LANG_MAPPING) * contest.problems.count()
moss_results = []
with Progress(self, length, stage=_("Running MOSS")) as p:
for problem in contest.problems.all():
for dmoj_lang, moss_lang in ContestMoss.LANG_MAPPING:
result = ContestMoss(
contest=contest, problem=problem, language=dmoj_lang
)
subs = (
Submission.objects.filter(
contest__participation__virtual__in=(
ContestParticipation.LIVE,
ContestParticipation.SPECTATE,
),
contest_object=contest,
problem=problem,
language__common_name=dmoj_lang,
)
.order_by("-points")
.values_list("user__user__username", "source__source")
)
if subs.exists():
moss_call = MOSS(
moss_api_key,
language=moss_lang,
matching_file_limit=100,
comment="%s - %s" % (contest.key, problem.code),
)
users = set()
for username, source in subs:
if username in users:
continue
users.add(username)
moss_call.add_file_from_memory(username, source.encode("utf-8"))
result.url = moss_call.process()
result.submission_count = len(users)
moss_results.append(result)
p.did(1)
ContestMoss.objects.bulk_create(moss_results)
return len(moss_results)