Variant ratings: Constant sum of rating
Whenever a variants gains/loses points now, we ensure that the sum of all variant ratings of that type stays constant by adjusting all other variants in the opposite direction.
This commit is contained in:
parent
707c1814ef
commit
4b760e5f84
3 changed files with 45 additions and 6 deletions
|
@ -265,12 +265,12 @@ CREATE TABLE variant_ratings (
|
||||||
/** This should reference the game that triggered the elo update */
|
/** This should reference the game that triggered the elo update */
|
||||||
league_id INTEGER NOT NULL REFERENCES games (league_id),
|
league_id INTEGER NOT NULL REFERENCES games (league_id),
|
||||||
variant_id SMALLINT NOT NULL REFERENCES variants (id),
|
variant_id SMALLINT NOT NULL REFERENCES variants (id),
|
||||||
|
|
||||||
num_players SMALLINT NOT NULL,
|
num_players SMALLINT NOT NULL,
|
||||||
|
|
||||||
change REAL NOT NULL,
|
change REAL NOT NULL,
|
||||||
value_after REAL NOT NULL,
|
value_after REAL NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (league_id, variant_id)
|
PRIMARY KEY (league_id, variant_id, num_players)
|
||||||
);
|
);
|
||||||
|
|
||||||
DROP TABLE IF EXISTS user_base_ratings CASCADE;
|
DROP TABLE IF EXISTS user_base_ratings CASCADE;
|
||||||
|
|
|
@ -43,7 +43,7 @@ FORBIDDEN_GAME_OPTIONS = [
|
||||||
|
|
||||||
# Cache time (in seconds) for history requests of players
|
# Cache time (in seconds) for history requests of players
|
||||||
# In case of frequent reruns (especially during development), we do not want to stress the server too much.
|
# In case of frequent reruns (especially during development), we do not want to stress the server too much.
|
||||||
USER_HISTORY_CACHE_TIME = 5 * 60
|
USER_HISTORY_CACHE_TIME = 60 * 60
|
||||||
|
|
||||||
# Fraction of seeds which is assumed to be unwinnable
|
# Fraction of seeds which is assumed to be unwinnable
|
||||||
UNWINNABLE_SEED_FRACTION = 0.02
|
UNWINNABLE_SEED_FRACTION = 0.02
|
||||||
|
|
|
@ -196,13 +196,52 @@ def process_rating_of_next_game() -> bool:
|
||||||
# Calculate changes in rating
|
# Calculate changes in rating
|
||||||
user_changes, variant_change = compute_rating_changes(user_ratings, games_played, variant_rating, score == 5 * num_suits)
|
user_changes, variant_change = compute_rating_changes(user_ratings, games_played, variant_rating, score == 5 * num_suits)
|
||||||
|
|
||||||
# Update database for variants
|
# Update database for the played variant
|
||||||
cur.execute("INSERT INTO variant_ratings (league_id, variant_id, num_players, change, value_after) "
|
cur.execute("INSERT INTO variant_ratings (league_id, variant_id, num_players, change, value_after) "
|
||||||
"VALUES (%s, %s, %s, %s, %s)",
|
"VALUES (%s, %s, %s, %s, %s)",
|
||||||
(league_id, variant_id, num_players, variant_change, variant_rating + variant_change)
|
(league_id, variant_id, num_players, variant_change, variant_rating + variant_change)
|
||||||
)
|
)
|
||||||
# Note: We do not commit here, only after players have been processed as well
|
# Note: We do not commit here, only after players have been processed as well
|
||||||
|
|
||||||
|
# Now, we get a list of all other variants of the same rating type, we will also need to update these.
|
||||||
|
cur.execute(
|
||||||
|
"SELECT DISTINCT ON (variants.id, variant_base_ratings.num_players)"
|
||||||
|
" variants.id,"
|
||||||
|
" 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 "
|
||||||
|
"WHERE"
|
||||||
|
" variants.rating_type = %s"
|
||||||
|
" AND NOT"
|
||||||
|
" (variants.id = %s AND variant_base_ratings.num_players = %s)"
|
||||||
|
"GROUP BY ("
|
||||||
|
" variants.id, variant_base_ratings.num_players, variant_base_ratings.rating,"
|
||||||
|
" variant_ratings.league_id, variant_ratings.value_after, variant_base_ratings.num_players"
|
||||||
|
" ) "
|
||||||
|
"ORDER BY variants.id, variant_base_ratings.num_players, league_id DESC",
|
||||||
|
(rating_type, variant_id, num_players)
|
||||||
|
)
|
||||||
|
|
||||||
|
# This ensures that the sum of ratings of variants of the same type stays constant (up to rounding).
|
||||||
|
variants_of_same_rating_type = cur.fetchall()
|
||||||
|
other_variant_change = -variant_change / len(variants_of_same_rating_type)
|
||||||
|
other_variant_vals = []
|
||||||
|
for (other_variant_id, other_num_players, current_rating) in variants_of_same_rating_type:
|
||||||
|
other_variant_vals.append((league_id, other_variant_id, other_num_players, other_variant_change, current_rating + other_variant_change))
|
||||||
|
|
||||||
|
# This updates the variants now
|
||||||
|
psycopg2.extras.execute_values(
|
||||||
|
cur,
|
||||||
|
"INSERT INTO variant_ratings (league_id, variant_id, num_players, change, value_after) "
|
||||||
|
"VALUES %s",
|
||||||
|
other_variant_vals
|
||||||
|
)
|
||||||
|
|
||||||
user_ratings_vals = []
|
user_ratings_vals = []
|
||||||
for user_id, change in user_changes.items():
|
for user_id, change in user_changes.items():
|
||||||
user_ratings_vals.append((league_id, user_id, rating_type, change, user_ratings[user_id] + change))
|
user_ratings_vals.append((league_id, user_id, rating_type, change, user_ratings[user_id] + change))
|
||||||
|
|
Loading…
Reference in a new issue