forked from Hanabi/hanabi-league
Move leader cards to separate page. add current streaks
This commit is contained in:
parent
ee40c27bc7
commit
0b67cea089
5 changed files with 63 additions and 48 deletions
|
@ -11,6 +11,11 @@
|
|||
font-weight: bold;
|
||||
color: #17a2b8; /* Bootstrap's teal color */
|
||||
}
|
||||
.current-streak {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #676767; /* Bootstrap's teal color */
|
||||
}
|
||||
.table td, .table th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,11 @@ class PlayerEntry:
|
|||
score: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlayerStreakEntry(PlayerEntry):
|
||||
current_streak: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class Leader:
|
||||
title: str
|
||||
|
@ -59,6 +64,7 @@ class VariantStats:
|
|||
return 0
|
||||
return round(float(self.total_moves) / self.games_played, 3)
|
||||
|
||||
|
||||
@dataclass
|
||||
class VariantRow:
|
||||
variant_id: int
|
||||
|
@ -117,7 +123,7 @@ def get_leaders(rating_lists: Dict, streak_lists: Dict) -> Dict[int, Dict[str, L
|
|||
return leaders
|
||||
|
||||
|
||||
def get_stat_lists(stat_type: str, order_type: str = 'DESC', precision: int = 0, default: float | int = 0, percents: bool = False):
|
||||
def get_streak_list():
|
||||
cur = conn_manager.get_connection().cursor(cursor_factory=psycopg2.extras.DictCursor)
|
||||
rating_types = [utils.get_rating_type(x) for x in [False, True]]
|
||||
leaderboard = {
|
||||
|
@ -128,27 +134,23 @@ def get_stat_lists(stat_type: str, order_type: str = 'DESC', precision: int = 0,
|
|||
cur.execute(
|
||||
"SELECT * FROM ("
|
||||
" SELECT "
|
||||
" player_name,"
|
||||
" string_agg(user_accounts.username, %s ORDER BY user_accounts.username) AS user_accounts,"
|
||||
f" COALESCE({stat_type}, %s) AS value"
|
||||
" 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 "
|
||||
f" GROUP BY (user_accounts.user_id, player_name, {stat_type}) "
|
||||
" player_name,"
|
||||
" STRING_AGG(user_accounts.username, %s ORDER BY user_accounts.username) AS user_accounts,"
|
||||
" COALESCE(maximum_streak, 0) AS maximum_streak,"
|
||||
" COALESCE(current_streak, 0) AS current_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, current_streak) "
|
||||
" ) AS streaks "
|
||||
# As a tiebreak, just sort by player name for now for determinancy
|
||||
f"ORDER BY value {order_type}, player_name",
|
||||
(", ", default, rating_type)
|
||||
"ORDER BY maximum_streak, player_name",
|
||||
(", ", rating_type)
|
||||
)
|
||||
for (player_name, user_accounts, value) in cur.fetchall():
|
||||
if percents:
|
||||
value = round(100 * value, precision)
|
||||
value = str(value) + ' %'
|
||||
else:
|
||||
value = round(value, precision)
|
||||
leaderboard[rating_type].append(PlayerEntry(player_name, user_accounts, value))
|
||||
for (player_name, user_accounts, max_streak, current_streak) in cur.fetchall():
|
||||
leaderboard[rating_type].append(PlayerStreakEntry(player_name, user_accounts, max_streak, current_streak))
|
||||
return leaderboard
|
||||
|
||||
|
||||
|
@ -228,7 +230,7 @@ def build_variant_stats_per_variant(variant_rows: List[VariantRow]):
|
|||
|
||||
def render_leaderboard():
|
||||
rating_lists = get_rating_lists()
|
||||
streak_lists = get_stat_lists("maximum_streak")
|
||||
streak_lists = get_streak_list()
|
||||
leaders = get_leaders(rating_lists, streak_lists)
|
||||
|
||||
variant_rows: List[VariantRow] = get_variant_rows()
|
||||
|
@ -237,9 +239,6 @@ def render_leaderboard():
|
|||
leaderboards = {
|
||||
'Player Rating': rating_lists,
|
||||
'Maximum Streak': streak_lists,
|
||||
'Current Streak': get_stat_lists("current_streak", order_type="DESC"),
|
||||
'Average Bottom Deck Risk': get_stat_lists("average_bdr", 'ASC', precision=2, default=float("inf")),
|
||||
'Winrate': get_stat_lists('winrate', order_type='DESC', precision=1, percents=True)
|
||||
}
|
||||
|
||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'))
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<div class="tab-content" id="myTabContent">
|
||||
{% for rating_type, leaders in leaders.items() %}
|
||||
<div class="tab-pane fade{{' active show' if rating_type == 0 else ''}}" id="leaderboards-{{rating_type}}">
|
||||
<div class="container my-5">
|
||||
<!-- Leader Cards -->
|
||||
<div class="card-deck mb-5">
|
||||
{% for category, data in leaders.items() %}
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-4">{{ data.title }}</h5>
|
||||
<p class="mb-0 player-name">{{ data.entry.player_name }}</p>
|
||||
<p class="mt-1 alt-name">{{ data.entry.user_accounts }}</p>
|
||||
<p class="score-large">{{ data.entry.score }}</p>
|
||||
</div>
|
||||
<div class="tab-pane fade active show" id="summary">
|
||||
<!-- Leader Cards -->
|
||||
<div class="card-deck mb-5">
|
||||
{% for rating_type, leaders in leaders.items() %}
|
||||
{% for category, data in leaders.items() %}
|
||||
<div class="card text-center">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-4">{{ data.title }}</h5>
|
||||
<p class="mb-0 player-name">{{ data.entry.player_name }}</p>
|
||||
<p class="mt-1 alt-name">{{ data.entry.user_accounts }}</p>
|
||||
<p class="score-large">{{ data.entry.score }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for rating_type, leaders in leaders.items() %}
|
||||
<div class="tab-pane fade" id="leaderboards-{{rating_type}}">
|
||||
<div class="container my-5">
|
||||
|
||||
<!-- Leaderboards -->
|
||||
<div id="leaderboards-{{rating_type}}-data" class="accordion">
|
||||
|
@ -37,6 +42,9 @@
|
|||
<div class="alt-name">{{ entry.user_accounts }}</div>
|
||||
</td>
|
||||
<td class="score">{{ entry.score }}</td>
|
||||
{% if entry.current_streak is defined %}
|
||||
<td class="current-streak">({{ entry.current_streak }})</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="leaderboards-0-tab" data-toggle="tab" href="#leaderboards-0">No Variant</a>
|
||||
<a class="nav-link active" id="summary-tab" data-toggle="tab" href="#summary">Summary</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="leaderboards-0-tab" data-toggle="tab" href="#leaderboards-0">No Variant</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="leaderboards-1-tab" data-toggle="tab" href="#leaderboards-1">Clue Starved</a>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#">The Hanabi Pro Hunting League<small class="text-muted"> - Variant Statistics for {{variant_name}}</small></a>
|
||||
<a class="navbar-brand" href="/">The Hanabi Pro Hunting League</a><a class="navbar-brand" href="#"><small class="text-muted">- Variant Statistics for {{variant_name}}</small></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<div class="tab-pane fade" id="stats-{{num_players}}p">
|
||||
<div class="container my-5">
|
||||
<h3>
|
||||
League statistics for {{variant_name}} ({{num_players}} players)
|
||||
League Statistics for {{variant_name}} - {{num_players}} Players
|
||||
</h3>
|
||||
<div class="history-bullets">
|
||||
<ul>
|
||||
|
@ -45,25 +45,25 @@
|
|||
{{stats.rating}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Total perfect scores:</span>
|
||||
<span class="stat-description">Total Perfect Scores:</span>
|
||||
{{stats.games_won}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Total bottom deck risk:</span>
|
||||
<span class="stat-description">Total Bottom Deck Risk:</span>
|
||||
{{stats.total_bdr}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Total crits lost:</span>
|
||||
<span class="stat-description">Total Crits Lost:</span>
|
||||
{{stats.total_crits_lost}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Total turns taken:</span>
|
||||
<span class="stat-description">Total Turns Taken:</span>
|
||||
{{stats.total_moves}}
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="stat-description">Total games played:</span>
|
||||
<span class="stat-description">Total Games Played:</span>
|
||||
{{stats.games_played}}
|
||||
</li>
|
||||
<li>
|
||||
|
@ -71,15 +71,15 @@
|
|||
{{stats.winrate}}%
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Average bottom deck risk:</span>
|
||||
<span class="stat-description">Average Bottom Deck Risk:</span>
|
||||
{{stats.average_bdr}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Average crits lost:</span>
|
||||
<span class="stat-description">Average Crits Lost:</span>
|
||||
{{stats.average_crits_lost}}
|
||||
</li>
|
||||
<li>
|
||||
<span class="stat-description">Average turns taken:</span>
|
||||
<span class="stat-description">Average Turns Taken:</span>
|
||||
{{stats.average_moves}}
|
||||
</li>
|
||||
</ul>
|
||||
|
|
Loading…
Reference in a new issue