hanabi-league/src/render_site.py

197 lines
6.9 KiB
Python
Raw Normal View History

2023-12-04 00:40:29 +01:00
from pathlib import Path
from typing import Dict, List
2023-12-04 00:40:29 +01:00
2023-12-03 21:19:36 +01:00
import jinja2
import datetime
2023-12-03 21:19:36 +01:00
import psycopg2.extras
import constants
import utils
import ratings
2023-12-04 00:40:29 +01:00
from dataclasses import dataclass
2023-12-03 21:19:36 +01:00
from database import conn_manager
2023-12-04 00:40:29 +01:00
@dataclass
class PlayerEntry:
2023-12-04 00:40:29 +01:00
player_name: str
user_accounts: str
score: int
@dataclass
class Leader:
title: str
entry: PlayerEntry
2023-12-04 00:40:29 +01:00
2023-12-04 11:11:02 +01:00
@dataclass
class VariantStats:
name: str
num_players: int
rating: int
games_played: int
games_won: int
def get_rating_lists() -> Dict[int, List[PlayerEntry]]:
cur = conn_manager.get_connection().cursor()
rating_types = [utils.get_rating_type(x) for x in [False, True]]
2023-12-04 00:40:29 +01:00
leaderboard = {
utils.get_rating_type(x): []
for x in [True, False]
}
for rating_type in rating_types:
cur.execute(
"SELECT * FROM ("
" SELECT DISTINCT ON (user_accounts.user_id)"
" player_name,"
" string_agg(user_accounts.username, %s ORDER BY user_accounts.username) AS user_accounts,"
" COALESCE(value_after, rating) AS current_rating"
" FROM users "
" LEFT OUTER JOIN user_ratings "
" ON user_ratings.user_id = users.id AND user_ratings.type = %s "
" LEFT OUTER JOIN user_accounts "
" ON users.id = user_accounts.user_id "
" INNER JOIN user_base_ratings "
" ON users.id = user_base_ratings.user_id AND user_base_ratings.type = %s"
" GROUP BY (user_accounts.user_id, player_name, value_after, league_id, rating) "
" ORDER BY user_accounts.user_id, league_id DESC"
" ) AS ratings "
"ORDER BY current_rating DESC",
(", ", rating_type, rating_type)
)
for (player_name, user_accounts, current_rating) in cur.fetchall():
leaderboard[rating_type].append(PlayerEntry(player_name, user_accounts, round(current_rating)))
2023-12-03 21:19:36 +01:00
2023-12-04 00:40:29 +01:00
return leaderboard
2023-12-04 03:02:26 +01:00
def get_leaders(rating_lists: Dict, streak_lists: Dict) -> Dict[int, Dict[str, Leader]]:
2023-12-04 00:40:29 +01:00
leaders = {}
for rating_type, rating_list in rating_lists.items():
if len(rating_list) != 0:
leader = rating_list[0]
leaders[rating_type] = {
'Player Rating': Leader('Highest Rating', leader)
2023-12-04 00:40:29 +01:00
}
2023-12-04 03:02:26 +01:00
for rating_type, streak_list in streak_lists.items():
if len(streak_list) != 0:
leader = streak_list[0]
if rating_type not in leaders.keys():
leaders[rating_type] = {}
leaders[rating_type]['Top Streak'] = Leader('Longest Win Streak', leader)
2023-12-04 00:40:29 +01:00
return leaders
2023-12-03 21:19:36 +01:00
2023-12-04 03:02:26 +01:00
def get_streak_lists():
2023-12-03 21:19:36 +01:00
cur = conn_manager.get_connection().cursor(cursor_factory=psycopg2.extras.DictCursor)
2023-12-04 03:02:26 +01:00
rating_types = [utils.get_rating_type(x) for x in [False, True]]
leaderboard = {
utils.get_rating_type(x): []
for x in [True, False]
}
for rating_type in rating_types:
cur.execute(
"SELECT * FROM ("
" SELECT "
" player_name,"
" string_agg(user_accounts.username, %s ORDER BY user_accounts.username) AS user_accounts,"
" COALESCE(maximum_streak, %s) AS maximum_streak"
" FROM users "
" LEFT OUTER JOIN user_statistics"
" ON users.id = user_statistics.user_id AND variant_type = %s"
" LEFT OUTER JOIN user_accounts "
" ON users.id = user_accounts.user_id "
" GROUP BY (user_accounts.user_id, player_name, maximum_streak) "
" ) AS streaks "
"ORDER BY maximum_streak DESC",
(", ", 0, rating_type)
)
for (player_name, user_accounts, maximum_streak) in cur.fetchall():
leaderboard[rating_type].append(PlayerEntry(player_name, user_accounts, maximum_streak))
return leaderboard
2023-12-03 21:19:36 +01:00
2023-12-04 11:11:02 +01:00
def get_variant_ratings():
cur = conn_manager.get_new_cursor()
cur.execute(
"SELECT"
" ratings.name,"
" ratings.num_players,"
" current_rating,"
" COUNT(games.id) AS games_played,"
" COUNT(games.id) FILTER (WHERE ratings.num_suits * 5 = games.score) AS games_won "
"FROM "
" ("
" SELECT DISTINCT ON (variants.id, variant_base_ratings.num_players)"
" variants.id,"
" variants.num_suits,"
" name,"
" variant_base_ratings.num_players,"
" COALESCE(variant_ratings.value_after, variant_base_ratings.rating) AS current_rating "
" FROM variants "
" LEFT OUTER JOIN variant_base_ratings"
" ON variants.id = variant_base_ratings.variant_id "
" LEFT OUTER JOIN variant_ratings "
" ON variant_ratings.variant_id = variant_base_ratings.variant_id AND variant_ratings.num_players = variant_base_ratings.num_players "
" GROUP BY (variants.id, name, variant_base_ratings.num_players, variant_base_ratings.rating, variant_ratings.league_id, variant_ratings.value_after) "
" ORDER BY variants.id, variant_base_ratings.num_players, league_id DESC"
" ) AS ratings "
"LEFT OUTER JOIN games "
" ON games.variant_id = ratings.id AND games.num_players = ratings.num_players "
"GROUP BY (ratings.id, ratings.name, ratings.num_players, ratings.current_rating)"
"ORDER BY (ratings.id, ratings.num_players)"
""
)
return [
VariantStats(variant_name, num_players, rating, games_played, games_won)
for (variant_name, num_players, rating, games_played, games_won) in cur.fetchall()
]
2023-12-03 21:19:36 +01:00
def get_total_games():
cur = conn_manager.get_new_cursor()
cur.execute("SELECT COUNT(league_id) FROM games")
2023-12-04 00:40:29 +01:00
(num_games,) = cur.fetchone()
2023-12-03 21:19:36 +01:00
return num_games
def get_num_players():
cur = conn_manager.get_new_cursor()
cur.execute("SELECT COUNT(id) FROM users")
(num_users,) = cur.fetchone()
return num_users
2023-12-03 21:19:36 +01:00
def render_leaderboard():
2023-12-04 00:40:29 +01:00
rating_lists = get_rating_lists()
2023-12-04 03:02:26 +01:00
streak_lists = get_streak_lists()
leaders = get_leaders(rating_lists, streak_lists)
2023-12-04 00:40:29 +01:00
leaderboards = {
2023-12-04 03:02:26 +01:00
'Player Rating': rating_lists,
'Maximum Streak': streak_lists
2023-12-04 00:40:29 +01:00
}
2023-12-03 21:19:36 +01:00
env = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'))
template = env.get_template('content.html')
# rendered_html = template.render(leaders=leaders, leaderboards=leaderboards, variants=variants)
rendered_html = template.render(
2023-12-04 00:40:29 +01:00
leaders=leaders,
leaderboards=leaderboards,
total_games_played=get_total_games(),
total_players=get_num_players(),
2023-12-04 11:11:02 +01:00
latest_run=datetime.datetime.now().isoformat(),
variants=get_variant_ratings()
2023-12-04 00:40:29 +01:00
# variants=variants,
2023-12-03 21:19:36 +01:00
)
2023-12-04 00:40:29 +01:00
output_file = Path(constants.WEBSITE_OUTPUT_DIRECTORY) / 'index.html'
output_file.parent.mkdir(exist_ok=True, parents=True)
with open(output_file, 'w') as f:
2023-12-03 21:19:36 +01:00
f.write(rendered_html)
2023-12-04 11:11:02 +01:00
2023-12-04 00:40:29 +01:00
render_leaderboard()