aboutsummaryrefslogtreecommitdiffstats
path: root/bot
diff options
context:
space:
mode:
authorGravatar Sebastiaan Zeeff <[email protected]>2020-12-02 08:46:26 +0100
committerGravatar Sebastiaan Zeeff <[email protected]>2020-12-02 08:46:26 +0100
commit02c5c7e2b120c055b7db07d2ca9568d1ae25c399 (patch)
tree19f1ff53d6767be25d2a583fc59dfae8ceac737a /bot
parentFix daily stats by converting day, star to str (diff)
Fix leaderboard glitch caused by duplicate names
We noticed that some entries on our leaderboard had an incorrect star count attached to their name. After a bit of digging, @HassanAbouelela discovered that this was caused by the use of the member's name as the key for the leaderboard dictionary: If different accounts used the same display name for the leaderboard, they'd be combined into one glitched score dict. The fix @HassanAbouelela wrote is to use the member id instead of the name as the key for the leaderboard. I've changed a few names here and there, but nothing major. This commit closes #536
Diffstat (limited to 'bot')
-rw-r--r--bot/exts/christmas/advent_of_code/_helpers.py30
1 files changed, 17 insertions, 13 deletions
diff --git a/bot/exts/christmas/advent_of_code/_helpers.py b/bot/exts/christmas/advent_of_code/_helpers.py
index f4a20955..e7eeedb2 100644
--- a/bot/exts/christmas/advent_of_code/_helpers.py
+++ b/bot/exts/christmas/advent_of_code/_helpers.py
@@ -50,7 +50,7 @@ EST = pytz.timezone("EST")
# Create namedtuple that combines a participant's name and their completion
# time for a specific star. We're going to use this later to order the results
# for each star to compute the rank score.
-_StarResult = collections.namedtuple("StarResult", "name completion_time")
+StarResult = collections.namedtuple("StarResult", "member_id completion_time")
def leaderboard_sorting_function(entry: typing.Tuple[str, dict]) -> typing.Tuple[int, int]:
@@ -61,7 +61,7 @@ def leaderboard_sorting_function(entry: typing.Tuple[str, dict]) -> typing.Tuple
secondary on the number of stars someone has completed.
"""
result = entry[1]
- return result["score"], result["star_2_count"] + result["star_1_count"]
+ return result["score"], result["star_2"] + result["star_1"]
def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict:
@@ -90,30 +90,34 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict:
# star view. We need that per star view to compute rank scores per star.
for member in raw_leaderboard_data.values():
name = member["name"] if member["name"] else f"Anonymous #{member['id']}"
- leaderboard[name] = {"score": 0, "star_1_count": 0, "star_2_count": 0}
+ member_id = member['id']
+ leaderboard[member_id] = {"name": name, "score": 0, "star_1": 0, "star_2": 0}
# Iterate over all days for this participant
for day, stars in member["completion_day_level"].items():
# Iterate over the complete stars for this day for this participant
for star, data in stars.items():
# Record completion of this star for this individual
- leaderboard[name][f"star_{star}_count"] += 1
+ leaderboard[member_id][f"star_{star}"] += 1
# Record completion datetime for this participant for this day/star
completion_time = datetime.datetime.fromtimestamp(int(data['get_star_ts']))
star_results[(day, star)].append(
- _StarResult(name=name, completion_time=completion_time)
+ StarResult(member_id=member_id, completion_time=completion_time)
)
# Now that we have a transposed dataset that holds the completion time of all
# participants per star, we can compute the rank-based scores each participant
# should get for that star.
max_score = len(leaderboard)
- for(day, _star), results in star_results.items():
+ for (day, _star), results in star_results.items():
+ # If this day should not count in the ranking, skip it.
if day in AdventOfCode.ignored_days:
continue
- for rank, star_result in enumerate(sorted(results, key=operator.itemgetter(1))):
- leaderboard[star_result.name]["score"] += max_score - rank
+
+ sorted_result = sorted(results, key=operator.attrgetter('completion_time'))
+ for rank, star_result in enumerate(sorted_result):
+ leaderboard[star_result.member_id]["score"] += max_score - rank
# Since dictionaries now retain insertion order, let's use that
sorted_leaderboard = dict(
@@ -133,16 +137,16 @@ def _parse_raw_leaderboard_data(raw_leaderboard_data: dict) -> dict:
return {"daily_stats": daily_stats, "leaderboard": sorted_leaderboard}
-def _format_leaderboard(leaderboard: typing.Dict[str, int]) -> str:
+def _format_leaderboard(leaderboard: typing.Dict[str, dict]) -> str:
"""Format the leaderboard using the AOC_TABLE_TEMPLATE."""
leaderboard_lines = [HEADER]
- for rank, (name, results) in enumerate(leaderboard.items(), start=1):
+ for rank, data in enumerate(leaderboard.values(), start=1):
leaderboard_lines.append(
AOC_TABLE_TEMPLATE.format(
rank=rank,
- name=name,
- score=str(results["score"]),
- stars=f"({results['star_1_count']}, {results['star_2_count']})"
+ name=data["name"],
+ score=str(data["score"]),
+ stars=f"({data['star_1']}, {data['star_2']})"
)
)