counting the stars

This commit is contained in:
Stefan Harmuth 2025-01-26 10:00:58 +01:00
parent 3d03c1eec3
commit f67f9ce4b9

View File

@ -2,6 +2,8 @@
from __future__ import annotations
import argparse
import os.path
from collections import defaultdict
import requests
import sys
from datetime import datetime, timedelta, timezone
@ -41,6 +43,7 @@ class LeaderboardCache:
self.__aoc_user_agent = aoc_user_agent
self.__last_fetch_year = 2015
self.__stats = {}
self.__stars = {}
self.update_stats()
def fetch_leaderboard(self, year: int) -> dict:
@ -66,11 +69,12 @@ class LeaderboardCache:
continue
year_keys = {}
year_stats = {"year": {}, "days": {}, "member_name_len": 0}
year_stats = {"year": {}, "days": {}, "stars": {}, "member_name_len": 0}
for member_id, member_data in self.__cache[year]["members"].items():
member_key = (int(member_data["local_score"]), member_data["name"])
year_keys[member_id] = member_key
year_stats["year"][member_key] = [" "] * 25
year_stats["stars"][member_data["name"]] = member_data["stars"]
year_stats["member_name_len"] = max(year_stats["member_name_len"], len(member_data["name"]))
member_count = len(self.__cache[year]["members"])
@ -119,6 +123,13 @@ class LeaderboardCache:
self.__stats[year] = year_stats
star_stats = defaultdict(int)
for year, year_stats in self.__stats.items():
for member, stars in year_stats["stars"].items():
star_stats[member] += stars
self.__stars = star_stats
def update(self) -> dict:
now = datetime.now(timezone.utc)
if now.month == 12: # on season
@ -176,6 +187,14 @@ class LeaderboardCache:
def get_years(self) -> list[str]:
return list(sorted(self.__stats.keys()))
def get_year_stars(self, year: str):
for member, stars in sorted(self.__stats[year]["stars"].items(), key=lambda x: x[1], reverse=True):
yield member, stars
def get_all_stars(self):
for member, stars in sorted(self.__stars.items(), key=lambda x: x[1], reverse=True):
yield member, stars
def get_year_items(self, year: str) -> (str, int, str):
for (score, member_name), solve_string in sorted(self.__stats[year]["year"].items(), reverse=True):
yield member_name, score, solve_string
@ -187,6 +206,9 @@ class LeaderboardCache:
def get_year_member_name_len(self, year: str) -> int:
return self.__stats[year]["member_name_len"]
def get_all_member_name_len(self) -> int:
return max(self.__stats[x]["member_name_len"] for x in self.__stats)
class AOCBot:
def __init__(self, config_file: str = "config.json"):
@ -352,6 +374,28 @@ class AOCBot:
break
self.__irc_bot.privmsg(self.__irc_channel, format_string % (member_name, score, "".join(solve_string)))
def command_stars(self, msg_from: str, message: str):
if not self.check_spam(msg_from, "stars"):
return
if not message:
max_name_len = self.__cache.get_all_member_name_len()
star_gen = self.__cache.get_all_stars()
else:
year = message
if not self.__cache.has_year(year):
self.__irc_bot.privmsg(self.__irc_channel, "Unknown year: %s" % year)
return
max_name_len = self.__cache.get_year_member_name_len(year)
star_gen = self.__cache.get_year_stars(year)
for count, (member, stars) in enumerate(star_gen):
if stars == 0:
break
line = "%2d. %-" + str(max_name_len) + "s %4d Stars"
self.__irc_bot.privmsg(self.__irc_channel, line % (count + 1, member, stars))
def update_leaderboard(self):
new_stars = self.__cache.update()
self.__last_update = datetime.now(timezone.utc)
@ -370,6 +414,10 @@ class AOCBot:
def on_raw(self, msg_from: str, msg_type: str, msg_to: str, message: str):
print("[%s] <%s> (%s) -> <%s>: %s" % (datetime.now().strftime("%H:%M:%S"), msg_from, msg_type, msg_to, message))
def on_quit(self, msg_from: str, msg_type: str, msg_to: str, message: str):
if msg_from == self.__irc_bot.getUser().identifier:
sys.exit(0)
def flush_output(self):
sys.stdout.flush()
sys.stderr.flush()
@ -411,10 +459,12 @@ class AOCBot:
print("[AoCBot] Registering Commands")
self.__irc_bot.on(ServerMessage.RAW, self.on_raw)
self.__irc_bot.on(ServerMessage.MSG_QUIT, self.on_quit)
self.__irc_bot.register_channel_command("!info", self.__irc_channel, self.command_info)
self.__irc_bot.register_channel_command("!help", self.__irc_channel, self.command_help)
self.__irc_bot.register_channel_command("!day", self.__irc_channel, self.command_day)
self.__irc_bot.register_channel_command("!year", self.__irc_channel, self.command_year)
self.__irc_bot.register_channel_command("!stars", self.__irc_channel, self.command_stars)
print("[AoCBot] Starting Main Loop")
self.__irc_bot.run()