stats: implement total number of moves

This commit is contained in:
Maximilian Keßler 2023-11-23 21:33:32 +01:00
parent cabec71e4f
commit 16105d1965
Signed by: max
GPG key ID: BCC5A619923C0BA5
2 changed files with 48 additions and 8 deletions

View file

@ -340,13 +340,13 @@ CREATE TABLE user_statistics (
user_id INTEGER NOT NULL REFERENCES users (id),
/** We track stats separately for each variant type */
variant_type SMALLINT NOT NULL,
current_streak INTEGER NOT NULL,
games_played INTEGER NOT NULL,
games_won INTEGER NOT NULL,
total_bdr INTEGER NOT NULL,
current_streak INTEGER,
games_played INTEGER,
games_won INTEGER,
total_bdr INTEGER,
/** Number of critical cards that were either discarded or misplayed */
total_crits_lots INTEGER NOT NULL,
total_game_moves INTEGER NOT NULL,
total_crits_lots INTEGER,
total_game_moves INTEGER,
PRIMARY KEY (user_id, variant_type)
);

View file

@ -2,7 +2,7 @@ import enum
from typing import List, Tuple
from hanabi import hanab_game
import utils
from database import conn_manager
@ -63,10 +63,50 @@ def analyze_game(instance: hanab_game.HanabiInstance, actions: List[hanab_game.A
return GameAnalysisResult(outcomes, bdrs)
def update_user_statistics(user_ids: List[int]):
def update_user_statistics():
"""
Update the cumulative user statistics for this user, assuming that the corresponding game statistics have
been computed already.
@param user_ids:
@return:
"""
# Note that some of these statistics could be computed by updating them on each new game insertion.
# However, it would be tedious to ensure that *every* new game triggers an update of these statistics.
# Also, this would be error-prone, since doing a mistake once means that values will be off forever
# (unless the DB is reset).
# Since it is cheap to accumulate some values over the whole DB, we therefore recreate the statistics as a whole,
# reusing only the individual results (that never change and therefore can only be missing, but never wrong)
cur = conn_manager.get_new_cursor()
# Update total number of moves
for clue_starved in [True, False]:
# We insert 0 here to ensure that we have an entry for each player
# Note that this will immediately be changed by the next query in case it is nonzero,
# so the zero value never shows up in the database if it was nonzero before.
cur.execute(
"INSERT INTO user_statistics (user_id, variant_type, total_game_moves)"
" ("
" SELECT id, %s, %s FROM users"
" )"
"ON CONFLICT (user_id, variant_type) DO UPDATE "
"SET total_game_moves = EXCLUDED.total_game_moves",
(utils.get_rating_type(clue_starved), 0)
)
cur.execute(
"INSERT INTO user_statistics (user_id, variant_type, total_game_moves)"
" ("
" SELECT users.id, %s, SUM(games.num_turns) FROM users "
" LEFT OUTER JOIN game_participants "
" ON game_participants.user_id = users.id "
" LEFT OUTER JOIN games "
" ON game_participants.game_id = games.id "
" LEFT OUTER JOIN variants"
" ON variants.id = games.variant_id "
" WHERE variants.clue_starved = %s OR variants.clue_starved IS NULL"
" GROUP BY users.id "
" ) "
"ON CONFLICT (user_id, variant_type) DO UPDATE "
"SET total_game_moves = EXCLUDED.total_game_moves",
(utils.get_rating_type(clue_starved), clue_starved)
)
conn_manager.get_connection().commit()