def schedule_ai_games(exam_id): time = timezone.now() exam = Exam.objects.get(pk=exam_id) comps = exam.competitors.all() for p in exam.problems.all(): subs = [] for c in comps: lastsub = c.submissions.filter( problem=p, submit_time__lte=time).order_by("-submit_time").first() if lastsub is not None: subs.append(lastsub) n = len(subs) ai_prob = p.aiproblem.first() np = ai_prob.numplayers if n < max(np, 2): log(not_enough_players=n, problem=p.problem_name) continue # not enough people to play matches against random.shuffle(subs) if np == 0: g = AIGame(status=-1, time=time, numplayers=n, aiproblem=ai_prob, miniround=-1) g.save() for i in range(n): s = AISubmission(game=g, seat=i + 1, competitor=subs[i].competitor, submission=subs[i]) s.save() g.status = 0 # add to queue after submissions are made g.save() else: roundup = np * ((n + np - 1) // np) for i in range(roundup - n): subs.append(subs[i]) for i in range(roundup // np): g = AIGame(status=-1, time=time, numplayers=np, aiproblem=ai_prob, miniround=-1) g.save() for j in range(np): idx = np * i + j s = AISubmission(game=g, seat=j + 1, competitor=subs[idx].competitor, submission=subs[idx]) s.save() g.status = 0 # add to queue after submissions are made g.save()
def check_finished_games_real(): from website.models import MatchResult # log(check_finished_games_real='started') games = AIGame.objects.defer("history").filter(status=2) for g in games: g.status = -1 g.save() for g in games: try: prob = g.aiproblem.problem exam = prob.exam subs = [] ratings = [] scores = [] aisubs = [] for aisub in g.aisubmissions.all(): sub = aisub.submission subs.append(sub) ratings.append((sub.rating, )) scores.append(-aisub.score) aisubs.append(aisub) new_ratings = trueskill.rate(ratings, ranks=scores) for i in range(len(subs)): s = subs[i] prev_rating = s.public_rating s.mu = new_ratings[i][0].mu s.sigma = new_ratings[i][0].sigma s.save() s.update_score_from_rating() score = Score.objects.get(problem=prob, competitor=s.competitor) mr = MatchResult(score=score, aisubmission=aisubs[i], time_played=g.time, prev_rating=prev_rating, new_rating=s.public_rating) mr.save() g.status = 4 g.save() except Exception as e: log(error=str(e), at='check_finished_games_real', game_id=g.id)
def contest_leaderboard(request, contest_id): try: user = request.user contest = get_object_or_404(Contest, pk=contest_id) teams = contest.teams.all() exams = list(contest.exams.all()) max_scores = [0] * len(exams) for i in range(len(exams)): for t in teams: try: c = Competitor.objects.get(exam=exams[i], team=t, mathlete=None) max_scores[i] = max(max_scores[i], c.total_score) except Exception as e: log(error=str(e), during='contest_leaderboard view', team=t.team_name, exam=exams[i].name) rows = [] for t in teams: scores = [] for i in range(len(exams)): try: c = Competitor.objects.get(exam=exams[i], team=t, mathlete=None) if max_scores[i] > 0: norm_score = c.total_score / max_scores[i] * 300 else: norm_score = 0 scores.append(norm_score) except: log(error='Competitor not found', exam=exams[i].name, team=t.team_name, contest=contest.name) rows.append({ 'scores': scores, 'name': t.team_name, 'total': sum(scores) }) rows = sorted(rows, key=lambda d: d['total'], reverse=True) rows[0]['rank'] = 1 for i in range(1, len(rows)): if rows[i]['total'] == rows[i - 1]['total']: rows[i]['rank'] = rows[i - 1]['rank'] else: rows[i]['rank'] = i + 1 context = { 'contest': contest, 'exams': exams, 'rows': rows, } return render(request, 'contest_leaderboard.html', context) except Exception as e: log(error=str(e), during='contest_leaderboard view')
def schedule_burst(submission): p = submission.problem exam = p.exam if exam.is_ai: # schedule a burst of matches time = timezone.now() comps = exam.competitors.all() subs = [] othersubs = [] for c in comps: lastsub = c.submissions.filter( problem=p, submit_time__lte=time).order_by("-submit_time").first() if lastsub is not None: subs.append(lastsub) if c != submission.competitor: othersubs.append(lastsub) n = len(subs) ai_prob = p.aiproblem.first() np = ai_prob.numplayers if n < max(np, 2): log(not_enough_players=n, problem=p.problem_name) return # not enough people to play matches against if np == 0: for _ in range(ai_prob.burst_matches): random.shuffle(subs) g = AIGame(status=-1, time=time, numplayers=n, aiproblem=ai_prob, miniround=-1) g.save() for i in range(n): s = AISubmission(game=g, seat=i + 1, competitor=subs[i].competitor, submission=subs[i]) s.save() g.status = 0 # add to queue after submissions are made g.save() else: seats = [i + 1 for i in range(np)] for i in range(ai_prob.burst_matches): random.shuffle(othersubs) subs = [submission] + othersubs random.shuffle(seats) g = AIGame(status=-1, time=time, numplayers=np, aiproblem=ai_prob, miniround=-1) g.save() for j in range(np): s = AISubmission(game=g, seat=seats[j], competitor=subs[j].competitor, submission=subs[j]) s.save() g.status = 0 # add to queue after submissions are made g.save()
def final_ai_grading(exam): log(grade_ai_final='started') try: comps = exam.competitors.all() time = timezone.now() for p in exam.problems.all(): log(problem=p.name) subs = [] for c in comps: lastsub = c.submissions.filter( problem=p, submit_time__lte=time).order_by("-submit_time").first() if lastsub is not None: subs.append(lastsub) n = len(subs) ai_prob = p.aiproblem.first() np = ai_prob.numplayers if n < max(np, 2): log(not_enough_players=n, problem=p.problem_name) continue # not enough people to play matches against # reset all ratings for sub in subs: sub.mu = None sub.sigma = None sub.save() if np == 2: # 1 iteration = n games in total c = 12 * (n - 1) # 12 round robins random.shuffle(subs) for i in range(c): shift = i % (n - 1) + 1 for j1 in range(n): j2 = (j1 + shift) % n g = AIGame(status=-1, time=time, numplayers=np, aiproblem=ai_prob, miniround=i) g.save() s1 = AISubmission(game=g, seat=1, competitor=subs[j1].competitor, submission=subs[j1]) s1.save() s2 = AISubmission(game=g, seat=2, competitor=subs[j2].competitor, submission=subs[j2]) s2.save() g.status = 0 # add to queue after submissions are made g.save() elif ai_prob.numplayers == 3: # 1 iteration = n games in total c = 334 random.shuffle(subs) for i in range(c): x = i % (n - 2) + 1 y = n - 1 - i % (n - 1) if x >= y: x += 1 # guaranteed that 1 <= x,y <= n and x =/= y # loops over grid diagonally from top-left to bottom-right (x shifted by 1) # this ensures that you don't get matched with the same opponent # at most twice in one iteration (unless n is small or c is large) for j1 in range(n): j2 = (j1 + x) % n j3 = (j1 + y) % n g = AIGame(status=-1, time=time, numplayers=np, aiproblem=ai_prob, miniround=i) g.save() s1 = AISubmission(game=g, seat=1, competitor=subs[j1].competitor, submission=subs[j1]) s1.save() s2 = AISubmission(game=g, seat=2, competitor=subs[j2].competitor, submission=subs[j2]) s2.save() s3 = AISubmission(game=g, seat=3, competitor=subs[j3].competitor, submission=subs[j3]) s3.save() g.status = 0 # add to queue after submissions are made g.save() elif ai_prob.numplayers == 0: c = 1000 for i in range(c): random.shuffle(subs) g = AIGame(status=-1, time=time, numplayers=n, aiproblem=ai_prob, miniround=i) g.save() for j in range(n): s = AISubmission(game=g, seat=j + 1, competitor=subs[j].competitor, submission=subs[j]) s.save() g.status = 0 # add to queue after submissions are made g.save() log(grade_ai_final='ended') except Exception as e: log(error=str(e))
def contest_list(request): if request.method == 'POST': if 'update_contest' in request.POST: contest = Contest.objects.get(pk=request.POST['update_contest']) update_contest(contest) elif 'reset_contest' in request.POST: contest = Contest.objects.get(pk=request.POST['reset_contest']) reset_contest(contest) elif 'reset_exam' in request.POST: exam = Exam.objects.get(pk=request.POST['reset_exam']) reset_exam(exam) elif 'reset_problem' in request.POST: problem = Problem.objects.get(pk=request.POST['reset_problem']) reset_problem(problem) elif 'init_all_tasks' in request.POST: init_all_tasks() elif 'regrade_games' in request.POST: regrade_games() elif 'recheck_games' in request.POST: recheck_games() elif 'score_file' in request.FILES: text = request.FILES['score_file'].read().decode('utf-8') scores_from_csv(text) elif 'recompute_leaderboard' in request.POST: exam = Exam.objects.get(pk=request.POST['recompute_leaderboard']) recompute_leaderboard(exam) elif 'final_ai_grading' in request.POST: exam = Exam.objects.get(pk=request.POST['final_ai_grading']) final_ai_grading(exam) elif 'check_finished_games' in request.POST: check_finished_games_real() elif 'delete_team' in request.POST: team = Team.objects.get(pk=request.POST['delete_team']) log(deleting_team=team.team_name) team.delete() log(deleted_team='') user = request.user all_contests = Contest.objects.all() if not user.is_tester: all_contests = all_contests.filter( is_private=False) # hide private contests tuples = [] for contest in all_contests: if user.is_mathlete: if user.has_team(contest): team = user.mathlete.get_team(contest) tuples.append({ 'contest': contest, 'has_team': True, 'team': team, 'exams': contest.reg_exams(user.mathlete), 'canjoin': contest.started }) else: tuples.append({ 'contest': contest, 'has_team': False, 'team': None, 'exams': contest.reg_exams(user.mathlete), 'canjoin': False }) else: tuples.append({ 'contest': contest, 'has_team': user.has_team(contest), 'team': None, 'exams': contest.exams.all(), 'canjoin': contest.started }) # Categorize the contests in the tuples ongoing_contests = [] for t in tuples: if t['contest'].ongoing: ongoing_contests.append(t) upcoming_contests = [] for t in tuples: if not t['contest'].started: upcoming_contests.append(t) past_contests = [] for t in tuples: if t['contest'].ended: past_contests.append(t) # Get all exams all_exams = Exam.objects.all() all_emails = [] prog_emails = [] small_teams = [] member_count = [0] * 10 member_count2 = [0] * 10 if user.is_staff: # Temporary email list (only visible to staff) all_users = User.objects.all() for user in all_users: all_emails.append(user.email) c = Contest.objects.get(pk=1) # programming contest teams = Team.objects.filter(contest=c) for team in teams: member_count[min(team.mathletes.all().count(), 9)] += 1 for m in team.mathletes.all(): prog_emails.append(m.user.email) if team.coach: prog_emails.append(team.coach.email) if team.mathletes.all().count() < 3: for m in team.mathletes.all(): small_teams.append(m.user.email) c = Contest.objects.get(pk=2) # programming contest teams = Team.objects.filter(contest=c) for team in teams: member_count2[min(team.mathletes.all().count(), 9)] += 1 context = { 'exams': all_exams, 'ongoing': ongoing_contests, 'upcoming': upcoming_contests, 'past': past_contests, # staff only 'emaillist': ', '.join(all_emails), 'prog_emails': ', '.join(prog_emails), 'small_teams': ', '.join(small_teams), 'member_count': member_count, 'member_count2': member_count2, } return render(request, 'contest_list.html', context)
def all_problems_math(request, user, exam): try: problems = exam.problem_list if user.is_mathlete: competitor = Competitor.objects.getCompetitor(exam, user.mathlete) if request.method == "POST": if not user.can_submit(exam): raise PermissionDenied( "You are not allowed to submit to this problem") if 'save' in request.POST: num = request.POST['save'] p = problems.get(problem_number=num) latex = request.POST[f'input-{num}'] ''' print('latex: ', latex) expr = parse_latex(latex) print('sympy expr: ', expr) print('ans latex: ', p.answer) ans_expr = parse_latex(p.answer) print('ans expr: ', ans_expr) ''' ''' signal.signal(signal.SIGALRM, handler) signal.alarm(5) try: print(expr.equals(ans_expr)) except: print("timeout!") signal.alarm(0) ''' sub = Submission(problem=p, competitor=competitor, text=latex) sub.save() score = Score.objects.get(problem=p, competitor=competitor) score.latest_sub = sub score.save() return redirect('all_problems', exam_id=exam.id) elif 'password' in request.POST: competitor.password = request.POST['password'] competitor.save() return redirect('all_problems', exam_id=exam.id) prob_info = [] for p in problems: score = Score.objects.get(problem=p, competitor=competitor) if score.latest_sub: text = score.latest_sub.text else: text = None prob_info.append({ 'p': p, 'n': p.problem_number, 'latest_sub': text, }) context = { 'exam': exam, 'prob_info': prob_info, 'can_submit': user.is_mathlete and competitor.password == exam.password, 'can_enter_password': user.is_mathlete and exam.password != '' and competitor.password != exam.password, } return render(request, 'exam/all_problems_math.html', context) except Exception as e: log(ERROR=str(e), during='all_problems_math')