196 lines
6.9 KiB
Python
196 lines
6.9 KiB
Python
from pathlib import Path
|
|
from typing import Dict, List
|
|
|
|
import jinja2
|
|
import datetime
|
|
import psycopg2.extras
|
|
|
|
import constants
|
|
import utils
|
|
import ratings
|
|
from dataclasses import dataclass
|
|
|
|
from database import conn_manager
|
|
|
|
|
|
@dataclass
|
|
class PlayerEntry:
|
|
player_name: str
|
|
user_accounts: str
|
|
score: int
|
|
|
|
|
|
@dataclass
|
|
class Leader:
|
|
title: str
|
|
entry: PlayerEntry
|
|
|
|
|
|
@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]]
|
|
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)))
|
|
|
|
return leaderboard
|
|
|
|
|
|
def get_leaders(rating_lists: Dict, streak_lists: Dict) -> Dict[int, Dict[str, Leader]]:
|
|
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)
|
|
}
|
|
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)
|
|
return leaders
|
|
|
|
|
|
def get_streak_lists():
|
|
cur = conn_manager.get_connection().cursor(cursor_factory=psycopg2.extras.DictCursor)
|
|
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
|
|
|
|
|
|
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()
|
|
]
|
|
|
|
|
|
def get_total_games():
|
|
cur = conn_manager.get_new_cursor()
|
|
cur.execute("SELECT COUNT(league_id) FROM games")
|
|
(num_games,) = cur.fetchone()
|
|
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
|
|
|
|
|
|
def render_leaderboard():
|
|
rating_lists = get_rating_lists()
|
|
streak_lists = get_streak_lists()
|
|
leaders = get_leaders(rating_lists, streak_lists)
|
|
|
|
leaderboards = {
|
|
'Player Rating': rating_lists,
|
|
'Maximum Streak': streak_lists
|
|
}
|
|
|
|
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(
|
|
leaders=leaders,
|
|
leaderboards=leaderboards,
|
|
total_games_played=get_total_games(),
|
|
total_players=get_num_players(),
|
|
latest_run=datetime.datetime.now().isoformat(),
|
|
variants=get_variant_ratings()
|
|
# variants=variants,
|
|
)
|
|
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:
|
|
f.write(rendered_html)
|
|
|
|
|
|
render_leaderboard()
|