|
22 | 22 | MAX_MESSAGE_LEN = 2000 - 6
|
23 | 23 |
|
24 | 24 | PLAYER_STR_FORMAT = '{rank:2}) {name:{name_pad}} ({points:{points_pad}}) {stars:{stars_pad}}* ({star_time})\n'
|
| 25 | +PLAYER_STR_FORMAT_NOPOINTS = '{rank:2}) {name:{name_pad}} {stars:{stars_pad}}* ({star_time})\n' |
25 | 26 | URL_STR_FORMAT = 'https://adventofcode.com/{year}/leaderboard/private/view/{leaderboard_id}.json'
|
26 | 27 |
|
27 | 28 | USER_AGENT = 'github.com/CSSUoB/advent-of-code-bot by cssoc@cs.bham.ac.uk'
|
@@ -265,4 +266,65 @@ async def daily(context, day: str = None, year: int = CURRENT_YEAR):
|
265 | 266 | await output_leaderboard(context, ranking, f'Leaderboard for {year}, day {day}:\n')
|
266 | 267 |
|
267 | 268 |
|
| 269 | +@bot.command(name='stars', help='Will give the time of completion of each star for specified day') |
| 270 | +async def stars(context, day: str = None, year: int = CURRENT_YEAR): |
| 271 | + # The default day calculation cannot be in the function default value because the default |
| 272 | + # value is evaluated when the program is started, not when the function is called |
| 273 | + if day is None: |
| 274 | + # The default day is whatever day's challenge has just come out |
| 275 | + # So at 4.59AM UTC it will still show previous day's leaderboard |
| 276 | + day = str((datetime.datetime.today() - datetime.timedelta(hours=5)).day) |
| 277 | + |
| 278 | + # Only respond if used in a channel containing CHANNEL_NAME |
| 279 | + if CHANNEL_NAME not in context.channel.name: |
| 280 | + return |
| 281 | + |
| 282 | + print("Star time leaderboard requested for day:", day) |
| 283 | + players = get_players(year) |
| 284 | + |
| 285 | + # Goes through all the players checking if they have data for that day and if they do adding to players_days |
| 286 | + players_day = [player for player in players if day in player[4]] |
| 287 | + |
| 288 | + # Players_day has all people who have finished one star for that day |
| 289 | + stars = [] |
| 290 | + |
| 291 | + # Adds all stars achieved to the stars list |
| 292 | + for player_day in players_day: |
| 293 | + if '1' in player_day[4][day]: |
| 294 | + stars.append((player_day[0], int(player_day[4][day]['1']['get_star_ts']), '1')) |
| 295 | + if '2' in player_day[4][day]: |
| 296 | + stars.append((player_day[0], int(player_day[4][day]['2']['get_star_ts']), '2')) |
| 297 | + |
| 298 | + # Sorts the list on timestamps |
| 299 | + stars.sort(key=lambda data: data[1]) |
| 300 | + |
| 301 | + final_table = [] |
| 302 | + |
| 303 | + # Adds all the stars to the final list |
| 304 | + for i, player in enumerate(stars): |
| 305 | + final_table.append((player[0], (len(stars) - i), player[1], player[2])) |
| 306 | + |
| 307 | + # Sorts the table by timestamp |
| 308 | + final_table.sort(key=lambda data: data[2]) |
| 309 | + |
| 310 | + # Outputs data |
| 311 | + if not final_table: |
| 312 | + result = "```No Scores for this day yet```" |
| 313 | + await context.send(result) |
| 314 | + else: |
| 315 | + # Get string lengths for the format string |
| 316 | + max_name_len = len(max(final_table, key=lambda t: len(t[0]))[0]) |
| 317 | + max_points_len = len(str(max(final_table, key=lambda t: t[1])[1])) |
| 318 | + max_stars_len = len(str(max(final_table, key=lambda t: t[3])[3])) |
| 319 | + leaderboard = [] |
| 320 | + for place, player in enumerate(final_table): |
| 321 | + leaderboard.append(PLAYER_STR_FORMAT_NOPOINTS.format(rank=place+1, |
| 322 | + name=player[0], name_pad=max_name_len, |
| 323 | + points=player[1], points_pad=max_points_len, |
| 324 | + stars=player[3], stars_pad=max_stars_len, |
| 325 | + star_time=time.strftime('%H:%M %d/%m', |
| 326 | + time.localtime(player[2])))) |
| 327 | + await output_leaderboard(context, leaderboard, f'Stars for day {day}, {year}:\n') |
| 328 | + |
| 329 | + |
268 | 330 | bot.run(TOKEN)
|
0 commit comments