Beispiel #1
0
 def status_detail_display(self):
     r, l = [], self.status_detail_list
     status_dictionary = dict(STATUS_CHOICE)
     count = len(l)
     re_count, last_group = 1, 0
     for index, s in enumerate(l, start=1):
         u, v = -233, '%d/%d' % (index, count
                                 )  # Magic number: display nothing
         if 'verdict' in s:
             if 'group' in s:
                 if s['group'] != last_group:
                     re_count = 1
                 last_group = s['group']
                 u = s['verdict']
                 v = '%d-%d' % (s['group'], re_count)
                 re_count += 1
             if SubmissionStatus.is_judged(s['verdict']):
                 u = s['verdict']
                 t = status_dictionary[u]
                 if s['verdict'] in (
                         SubmissionStatus.ACCEPTED,
                         SubmissionStatus.SCORED,
                 ):
                     t += ', %.3fs' % s.get('time', 0.0)
                 elif s['verdict'] == SubmissionStatus.RUNTIME_ERROR:
                     t += ', %s' % s.get('message', 'NaN')
                 v += ': ' + t
             elif 'group' in s:
                 v += ": Skipped"
         if 'point' in s:
             v += ' (%.1f)' % s['point']
         r.append((u, v))
     return r
Beispiel #2
0
 def run(self):
     for sub in self.submissions:
         if self.skip:
             submission = OldSubmission.objects.get(pk=sub)
             if SubmissionStatus.is_judged(submission.status):
                 continue
         DispatcherThread(sub).start()
Beispiel #3
0
 def is_judged(self):
     return SubmissionStatus.is_judged(self.status)
Beispiel #4
0
def calculate_participants(contest: Contest, participants: list, snapshot: timedelta=None):
    """
    :param contest
    :param participants: list of ContestParticipants
    :param snapshot: submissions in the first `snapshot` seconds will be effective
    :return
    {
        <user_id>: {
            penalty: int (seconds),
            score: int,
            is_confirmed: boolean
            detail: {
                <problem_id>: {
                    solved: boolean
                    attempt: int (submission count including the first accepted one),
                    score: int (individual score for each problem),
                    time: int (first accept solution time, in seconds),
                    partial: boolean
                    upsolve: int (positive for accepted, negative for unaccepted, score if partial)
                }
            }
        }
    }

    This will be saved to participants without writing to database (can do that outside)

    Penalty is the same for all rules: Every failed submission till the accepted one
    will add `penalty_counts` (default 1200) to it. And the accepted one will add the time (seconds) to it

    Score methods depend on the contest rule:
    1. ACM rule: individual score is all one, total score is solved problem number.
    2. OI rule: individual score is problem weight times the weight of cases passed (round to integer).
    3. CF rule: individual score is problem weight, but will only be available if the solution is by all means correct.

    How much percent one can get is a bit complicated:
    1) The total percent will decrease from contest beginning to contest end from 100% to 50%.
    2) Every failed submission will induce a 50-point loss to the score
    3) The final score, once accepted will not be lower than 30% of the total score.
    """

    user_ids = list(map(lambda p: p.user_id, participants))
    ans = {author_id: dict(detail=dict(), is_confirmed=False) for author_id in user_ids}
    contest_length = contest.length
    if contest_length is not None:
        contest_length = contest_length.total_seconds()

    for submission in get_submission_filter(contest, snapshot, author_id__in=user_ids):
        status = submission.status
        detail = ans[submission.author_id]['detail']

        author_id = submission.author_id
        ans[author_id]['is_confirmed'] = True

        detail.setdefault(submission.problem_id,
                          {'solved': False, 'attempt': 0, 'score': 0, 'time': 0,
                           'waiting': False, 'pass_time': '', 'partial': False, 'upsolve': 0})
        d = detail[submission.problem_id]
        if not SubmissionStatus.is_judged(submission.status):
            d['waiting'] = True
            continue
        if SubmissionStatus.is_scored(submission.status):
            d['partial'] = True

        if not SubmissionStatus.is_penalty(status):
            continue  # This is probably CE or SE ...
        contest_problem = contest.get_contest_problem(submission.problem_id)
        if not contest_problem:  # This problem has been probably deleted
            continue

        pass_time = str(submission.create_time.strftime('%Y-%m-%d %H:%M:%S'))
        time = int(submission.contest_time.total_seconds()) if submission.contest_time is not None else 0
        score = 0
        EPS = 1E-2
        if contest.scoring_method == 'oi' or contest.scoring_method == "subtask":
            submission.contest_problem = contest_problem
            score = submission.status_score
        elif contest.scoring_method == 'acm' and SubmissionStatus.is_accepted(status):
            score = 1
        elif contest.scoring_method == 'cf' and SubmissionStatus.is_accepted(status):
            score = int(max(contest_problem.weight * 0.3,
                            contest_problem.weight * (1 - 0.5 * time / contest_length) - d['attempt'] * 50) + EPS)
        elif contest.scoring_method == 'tcmtime' and SubmissionStatus.is_accepted(status):
            score = contest_problem.weight

        # upsolve submission
        if d['partial']:
            d['upsolve'] = max(d['upsolve'], score)
        elif d['upsolve'] <= 0:
            d['upsolve'] -= 1
            if SubmissionStatus.is_accepted(status):
                d['upsolve'] = abs(d['upsolve'])

        if contest.contest_type == 0 and submission.contest_time is None:
            d['upsolve_enable'] = True
            continue

        if contest.last_counts or not \
                (d['solved'] or (contest.scoring_method != 'oi' and d['score'] > 0 and d['score'] >= score)):
            # every submission has to be calculated in OI
            # We have to tell whether this is the best

            if not contest.last_counts:
                d['score'] = max(d['score'], score)
            else:
                d['score'] = score
            d['attempt'] += 1
            d.update(solved=SubmissionStatus.is_accepted(status), time=time, pass_time=pass_time)

    for v in ans.values():
        for p in v['detail']:
            d = v['detail'][p]
            if 'upsolve_enable' not in d:
                d['upsolve'] = 0
            else:
                d.pop('upsolve_enable', None)
        if contest.start_time is None:
            penalty = 0
        elif contest.scoring_method == 'oi':
            penalty = sum(map(lambda x: max(x['attempt'], 0) * contest.penalty_counts + x['time'],
                              v['detail'].values()))
        else:
            penalty = sum(map(lambda x: max(x['attempt'] - 1, 0) * contest.penalty_counts + x['time'],
                              filter(lambda x: x['solved'], v['detail'].values())))
        v.update(penalty=penalty, score=sum(map(lambda x: x['score'], v['detail'].values())))

    for p in participants:
        p.detail = ans[p.user_id]["detail"]
        p.score = ans[p.user_id]["score"]
        p.penalty = ans[p.user_id]["penalty"]
        p.is_confirmed = ans[p.user_id]["is_confirmed"]
    return ans
Beispiel #5
0
    def on_receive_data(data):
        judge_time = datetime.fromtimestamp(data['timestamp'])
        if submission.judge_end_time and judge_time < submission.judge_end_time:
            return True
        if data.get('status') == 'received':
            if 'message' in data:
                submission.status_message = data['message']
            else:
                submission.status_message = ''
            submission.status = process_accepted(data.get('verdict', SubmissionStatus.JUDGING))

            details = data.get('detail', [])
            if not group_config["on"]:
                # Add points to details
                score = 0
                try:
                    for index, detail in enumerate(details):
                        if 'point' not in detail:
                            if detail.get('verdict') == 0:
                                detail['point'] = point_query.get(case_list[index], 10) / total_score * 100
                        score += detail.get('point', 0)
                except:
                    pass
                submission.status_percent = score
            display_details = details + [{}] * max(0, len(case_list) - len(details))
            submission.status_detail_list = display_details
            submission.status_test = process_failed_test(display_details)
            submission.judge_server = data.get('server', 0)
            submission.save(update_fields=['status_message', 'status_detail','status',
                                           'status_percent', 'status_test', 'judge_server'])

            if SubmissionStatus.is_judged(data.get('verdict')):
                if group_config["on"] and data.get('verdict') != SubmissionStatus.COMPILE_ERROR:
                    score = 0
                    records = []
                    accept_case_counter, total_case_counter = Counter(), Counter()
                    for index, detail in enumerate(details):
                        group_id = group_config["group_list"][index]
                        if detail.get('verdict') == 0:
                            accept_case_counter[group_id] += 1
                        total_case_counter[group_id] += 1
                    for group_id in range(1, group_config["group_count"] + 1):
                        get_score = 0
                        if accept_case_counter[group_id] == total_case_counter[group_id] and \
                                total_case_counter[group_id] > 0:
                            get_score = point_query[group_id - 1]
                        score += get_score
                        records.append("Subtask #%d: " % group_id +
                                       "%d/%d cases passed. %d points." % (accept_case_counter[group_id],
                                                                           total_case_counter[group_id],
                                                                           get_score))
                    records.append("Total: %d/%d" % (score, total_score))
                    submission.status_message = "\n".join(records)
                    submission.status_percent = score / total_score * 100

                try:
                    submission.status_time = max(map(lambda d: d.get('time', 0.0), submission.status_detail_list))
                except ValueError: pass
                submission.judge_end_time = judge_time

                submission.save(update_fields=['status_time', 'judge_end_time', 'status_message', 'status_percent'])

                if submission.status == SubmissionStatus.ACCEPTED:
                    # Add reward
                    _, created = ProblemRewardStatus.objects.get_or_create(problem_id=submission.problem_id,
                                                                           user_id=submission.author_id)
                    if created:
                        if submission.contest_time is not None:
                            reward_contest_ac(submission.author, 4 * problem.level ** 2, submission.contest_id)
                        else:
                            reward_problem_ac(submission.author, problem.reward, submission.problem_id)

                invalidate_user(submission.author_id, submission.contest_id)
                invalidate_problem(submission.problem)
                if callback:
                    callback()
                return True
            return False
        else:
            submission.status = SubmissionStatus.SYSTEM_ERROR
            submission.status_message = data['message']
            submission.save(update_fields=['status', 'status_message'])
            return True