From 79174725f8ce2333d2a254fa30ed16b44185d948 Mon Sep 17 00:00:00 2001 From: onerandomusername Date: Sat, 8 Nov 2025 17:33:20 -0500 Subject: [PATCH] fix: sort the user into the leaderboard if in the top x values, and show the full top users even when a user is provided if a user is linked and provided, we add an additional line to allow viewing the top 10 PLUS the user if the user is in the top ten, we don't want this additional line closes #107 --- bot/exts/advent_of_code/_cog.py | 2 +- bot/exts/advent_of_code/_helpers.py | 44 +++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/bot/exts/advent_of_code/_cog.py b/bot/exts/advent_of_code/_cog.py index b601550..8527c45 100644 --- a/bot/exts/advent_of_code/_cog.py +++ b/bot/exts/advent_of_code/_cog.py @@ -398,7 +398,7 @@ async def aoc_leaderboard(self, ctx: commands.Context, *, aoc_name: str | None = number_of_participants = leaderboard["number_of_participants"] top_count = min(AocConfig.leaderboard_displayed_members, number_of_participants) - self_placement_header = " (and your personal stats compared to the top 10)" if aoc_name else "" + self_placement_header = f" (and your personal stats compared to the top {top_count})" if aoc_name else "" header = f"Here's our current top {top_count}{self_placement_header}! {Emojis.christmas_tree * 3}" table = ( "```\n" diff --git a/bot/exts/advent_of_code/_helpers.py b/bot/exts/advent_of_code/_helpers.py index 9d016ed..d99275f 100644 --- a/bot/exts/advent_of_code/_helpers.py +++ b/bot/exts/advent_of_code/_helpers.py @@ -80,6 +80,14 @@ def leaderboard_sorting_function(entry: tuple[str, dict]) -> tuple[int, int]: return result["score"], result["star_2"] + result["star_1"] +def _get_user_placement(user_name: str, leaderboard: dict[int, dict]) -> int | None: + """Get the placement of a specific user in the leaderboard.""" + for rank, data in enumerate(leaderboard.values(), start=1): + if data["name"] == user_name: + return rank + return None + + def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: """ Parse the leaderboard data received from the AoC website. @@ -160,22 +168,29 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict: def _format_leaderboard(leaderboard: dict[str, dict], self_placement_name: str | None = None) -> str: - """Format the leaderboard using the AOC_TABLE_TEMPLATE.""" + """ + Format the leaderboard using the AOC_TABLE_TEMPLATE. + + If the rank of self_placement_name is within AdventOfCode.leader_displayed_members, it is placed + in the correct position; otherwise, it is placed just below the header. + """ leaderboard_lines = [HEADER] self_placement_exists = False for rank, data in enumerate(leaderboard.values(), start=1): if self_placement_name and data["name"].lower() == self_placement_name.lower(): leaderboard_lines.insert( - 1, + # Plus one to account for the user being one rank outside of the shown users + rank if rank <= AdventOfCode.leaderboard_displayed_members + 1 else 1, AOC_TABLE_TEMPLATE.format( rank=rank, name=f"(You) {data['name']}", score=str(data["score"]), - stars=f"({data['star_1']}, {data['star_2']})" - ) + stars=f"({data['star_1']}, {data['star_2']})", + ), ) self_placement_exists = True continue + leaderboard_lines.append( AOC_TABLE_TEMPLATE.format( rank=rank, @@ -279,9 +294,16 @@ async def _upload_leaderboard(leaderboard: str) -> str: return paste.link -def _get_top_leaderboard(full_leaderboard: str) -> str: - """Get the leaderboard up to the maximum specified entries.""" - return "\n".join(full_leaderboard.splitlines()[:TOP_LEADERBOARD_LINES]) +def _get_top_leaderboard(full_leaderboard: str, *, include_self: bool = False) -> str: + """ + Get the leaderboard up to the maximum specified entries. + + Include_self specifies whether to include an extra line for the user's placement. + If the user is within the top entries, include_self should be False to avoid an additional entry. + """ + return "\n".join( + full_leaderboard.splitlines()[: TOP_LEADERBOARD_LINES + (1 if include_self else 0)] + ) # +1 if including self placement @_caches.leaderboard_cache.atomic_transaction @@ -336,8 +358,14 @@ async def fetch_leaderboard(invalidate_cache: bool = False, self_placement_name: formatted_placement_leaderboard = _parse_raw_leaderboard_data( json.loads(cached_leaderboard["placement_leaderboard"]) )["leaderboard"] + full_formatted_leaderboard = _format_leaderboard( + formatted_placement_leaderboard, self_placement_name=self_placement_name + ) + user_placement = _get_user_placement(self_placement_name, formatted_placement_leaderboard) + include_self = bool(user_placement and user_placement > AdventOfCode.leaderboard_displayed_members) cached_leaderboard["placement_leaderboard"] = _get_top_leaderboard( - _format_leaderboard(formatted_placement_leaderboard, self_placement_name=self_placement_name) + full_formatted_leaderboard, + include_self=include_self ) return cached_leaderboard