From 4275cecc1a087c62248ee139ee38d5405892c49c Mon Sep 17 00:00:00 2001 From: Brennan Bibic Date: Mon, 23 Sep 2024 11:46:04 -0400 Subject: [PATCH] recalc elo function attempt --- change_match_game_mode.py | 12 +++++-- ranked/api/elo_constants.py | 2 +- ranked/api/lib.py | 2 +- ranked/api/urls.py | 2 ++ ranked/api/views.py | 63 +++++++++++++++++++++++++++++++++++++ recalculate_elo.py | 50 +++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 recalculate_elo.py diff --git a/change_match_game_mode.py b/change_match_game_mode.py index c5b869c..0a413f1 100644 --- a/change_match_game_mode.py +++ b/change_match_game_mode.py @@ -52,15 +52,23 @@ def change_match_game_modes(matches): print("\nReady to change game modes for matches.") print(f"Changing matches {start_match} to {end_match} to {new_mode}") confirmation = prompt("Do you want to proceed with these changes? (y/n): ").lower() - + if confirmation == 'y': results = change_match_game_modes(matches) if results: for result in results: + # Add a print statement to inspect the result + print("Result:", result) if 'error' in result: print(f"Failed to update match: {result['error']}") else: - print(f"Successfully updated match {result['match_number']} to {new_mode}") + # Modify this line + # print(f"Successfully updated match {result['match_number']} to {new_mode}") + match_number = result.get('match', {}).get('match_number') + if match_number: + print(f"Successfully updated match {match_number} to {new_mode}") + else: + print("match_number not found in the result.") else: print("Failed to change match game modes. Please check the error message above.") else: diff --git a/ranked/api/elo_constants.py b/ranked/api/elo_constants.py index 84ee6b0..f9dbce7 100644 --- a/ranked/api/elo_constants.py +++ b/ranked/api/elo_constants.py @@ -1,5 +1,5 @@ N = 256 -K = 16 +K = 18 R = 0.002 B = 10 C = 100 diff --git a/ranked/api/lib.py b/ranked/api/lib.py index d44b5f3..96a4140 100644 --- a/ranked/api/lib.py +++ b/ranked/api/lib.py @@ -132,7 +132,7 @@ def update_player_elos(match: Match, red_player_elos: List[PlayerElo], blue_play player.matches_lost += 1 # Increase the importance of the score difference - importance_factor = 1.5 + importance_factor = 3 adjusted_score_diff = importance_factor * relative_score_diff elo_change = (( diff --git a/ranked/api/urls.py b/ranked/api/urls.py index acf62d9..a172f5f 100644 --- a/ranked/api/urls.py +++ b/ranked/api/urls.py @@ -18,4 +18,6 @@ path('/match/edit/', views.edit_match_result, name='edit_match_result'), path('leaderboard//', views.get_leaderboard, name='get_leaderboard'), path('/players/', views.get_valid_players, name='get_valid_players'), + path('clear-leaderboard/', views.clear_leaderboard, name='clear_leaderboard'), + path('recalculate-elo/', views.recalculate_elo, name='recalculate_elo'), ] diff --git a/ranked/api/views.py b/ranked/api/views.py index 461892e..a0e4ccd 100644 --- a/ranked/api/views.py +++ b/ranked/api/views.py @@ -479,3 +479,66 @@ def change_match_game_modes(request: Request) -> Response: }) return Response(results) + +@api_view(['POST']) +def clear_leaderboard(request: Request) -> Response: + """ + Clears the leaderboard for a specific game mode. + """ + if request.META.get('HTTP_X_API_KEY') != API_KEY: + return Response(status=401, data={'error': 'Invalid API key.'}) + + game_mode_code = request.data.get('game_mode') + if not game_mode_code: + return Response(status=400, data={'error': 'Game mode code is required.'}) + + try: + game_mode = GameMode.objects.get(short_code=game_mode_code) + except GameMode.DoesNotExist: + return Response(status=404, data={'error': f'Game mode {game_mode_code} does not exist.'}) + + PlayerElo.objects.filter(game_mode=game_mode).delete() + return Response(status=200, data={'message': 'Leaderboard cleared successfully.'}) + + +@api_view(['POST']) +def recalculate_elo(request: Request) -> Response: + """ + Recalculates the ELO for a specific game mode. + """ + if request.META.get('HTTP_X_API_KEY') != API_KEY: + return Response(status=401, data={'error': 'Invalid API key.'}) + + game_mode_code = request.data.get('game_mode') + if not game_mode_code: + return Response(status=400, data={'error': 'Game mode code is required.'}) + + try: + game_mode = GameMode.objects.get(short_code=game_mode_code) + except GameMode.DoesNotExist: + return Response(status=404, data={'error': f'Game mode {game_mode_code} does not exist.'}) + + players = PlayerElo.objects.filter(game_mode=game_mode) + for player in players: + player.elo = 1200 # Reset ELO to a base value + player.save() + + matches = Match.objects.filter(game_mode=game_mode).order_by('time') + for match in matches: + red_players = match.red_alliance.all() + blue_players = match.blue_alliance.all() + red_player_elos = PlayerElo.objects.filter(player__in=red_players, game_mode=game_mode) + blue_player_elos = PlayerElo.objects.filter(player__in=blue_players, game_mode=game_mode) + + red_elo_changes, blue_elo_changes = update_player_elos( + match, list(red_player_elos), list(blue_player_elos)) + + for player_elo, elo_change in zip(red_player_elos, red_elo_changes): + player_elo.elo += elo_change + player_elo.save() + + for player_elo, elo_change in zip(blue_player_elos, blue_elo_changes): + player_elo.elo += elo_change + player_elo.save() + + return Response(status=200, data={'message': 'ELO recalculated successfully.'}) diff --git a/recalculate_elo.py b/recalculate_elo.py new file mode 100644 index 0000000..fa9fade --- /dev/null +++ b/recalculate_elo.py @@ -0,0 +1,50 @@ +import requests +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +API_KEY = os.getenv('SRC_API_TOKEN') +API_BASE_URL = 'https://secondrobotics.org' + +def clear_leaderboard(game_mode): + url = f"{API_BASE_URL}/api/ranked/clear-leaderboard/" + headers = { + 'Content-Type': 'application/json', + 'X-API-KEY': API_KEY + } + payload = {"game_mode": game_mode} + + response = requests.post(url, json=payload, headers=headers) + if response.status_code == 200: + print("Leaderboard cleared successfully.") + else: + print(f"Error clearing leaderboard: Status code {response.status_code}") + print(f"Response content: {response.text}") + +def recalculate_elo(game_mode): + url = f"{API_BASE_URL}/api/ranked/recalculate-elo/" + headers = { + 'Content-Type': 'application/json', + 'X-API-KEY': API_KEY + } + payload = {"game_mode": game_mode} + + response = requests.post(url, json=payload, headers=headers) + if response.status_code == 200: + print("ELO recalculated successfully.") + else: + print(f"Error recalculating ELO: Status code {response.status_code}") + print(f"Response content: {response.text}") + +if __name__ == "__main__": + game_mode = input("Enter the game mode to reset and recalculate ELO: ") + + confirmation = input(f"Are you sure you want to clear the leaderboard and recalculate ELO for game mode '{game_mode}'? (y/n): ").lower() + + if confirmation == 'y': + clear_leaderboard(game_mode) + recalculate_elo(game_mode) + else: + print("Operation cancelled.") \ No newline at end of file