From e3889459f83fc1e715cf43df5c867133e72cb86b Mon Sep 17 00:00:00 2001 From: Brennan Bibic Date: Wed, 14 Aug 2024 12:50:45 -0400 Subject: [PATCH] Percentile sorting for combined leaderboards --- .../highscores/combined_leaderboard.html | 18 +++++---- highscores/views.py | 37 ++++++++++++++----- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/highscores/templates/highscores/combined_leaderboard.html b/highscores/templates/highscores/combined_leaderboard.html index 0031817..a08a7ce 100644 --- a/highscores/templates/highscores/combined_leaderboard.html +++ b/highscores/templates/highscores/combined_leaderboard.html @@ -1,8 +1,10 @@ -{% extends 'home/base.html' %} {% block content %} +{% extends 'home/base.html' %} + +{% block content %}

- {{game_name}} Combined Leaderboard + {{ game_name }} Combined Leaderboard

@@ -13,19 +15,19 @@

Player Name Score Last Submitted + Average Percentile {% for item in ls %} - {{item.0}} + {{ item.0 }} - {{item.1.player}} + {{ item.1.player.username }} - {{item.1.score}} - {{item.1.time_set}} + {{ item.1.score }} + {{ item.1.time_set }} + {{ item.1.average_percentile|floatformat:2 }}% {% endfor %} diff --git a/highscores/views.py b/highscores/views.py index fdfd4eb..eaaf627 100644 --- a/highscores/views.py +++ b/highscores/views.py @@ -8,6 +8,7 @@ from django.utils.timezone import make_aware from datetime import datetime from collections import Counter +from django.db.models import Avg, F from .lib import extract_form_data, game_slug_to_submit_func from .models import Leaderboard, Score @@ -101,18 +102,34 @@ def leaderboard_combined(request: HttpRequest, game_slug: str) -> HttpResponse: game_name = Leaderboard.objects.filter(game_slug=game_slug)[0].game - scores = Score.objects.filter(leaderboard__game_slug=game_slug, approved=True).values( - 'player').annotate(time_set=Max('time_set')).annotate(score=Sum('score')) - sorted_board = scores.order_by('-score', 'time_set') - - i = 1 + leaderboards = Leaderboard.objects.filter(game_slug=game_slug) + + player_percentiles = {} + + for leaderboard in leaderboards: + scores = Score.objects.filter(leaderboard=leaderboard, approved=True).order_by('-score', 'time_set') + if not scores.exists(): + continue + highest_score = scores.first().score + + for score in scores: + percentile = (score.score / highest_score) * 100 + if score.player.id not in player_percentiles: + player_percentiles[score.player.id] = [] + player_percentiles[score.player.id].append(percentile) + + average_percentiles = {player_id: sum(percentiles)/len(percentiles) for player_id, percentiles in player_percentiles.items()} + sorted_average_percentiles = sorted(average_percentiles.items(), key=lambda x: x[1], reverse=True) + context = [] - # Create ranking numbers and append them to sorted values - for item in sorted_board: - item['player'] = User.objects.filter(id=item['player'])[0] - context.append([i, item]) + i = 1 + for player_id, avg_percentile in sorted_average_percentiles: + player = User.objects.get(id=player_id) + total_score = Score.objects.filter(player=player, leaderboard__game_slug=game_slug, approved=True).aggregate(total_score=Sum('score'))['total_score'] + last_time_set = Score.objects.filter(player=player, leaderboard__game_slug=game_slug, approved=True).aggregate(last_time_set=Max('time_set'))['last_time_set'] + context.append([i, {'player': player, 'average_percentile': avg_percentile, 'score': total_score, 'time_set': last_time_set}]) i += 1 - + return render(request, COMBINED_LEADERBOARD_PAGE, {"ls": context, "game_name": game_name})