Skip to content

Commit

Permalink
Add new rating system setup task
Browse files Browse the repository at this point in the history
  • Loading branch information
jauggy committed Dec 31, 2024
1 parent f4e1556 commit 4ed4f5c
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 7 deletions.
23 changes: 19 additions & 4 deletions lib/teiserver/battle/libs/balance_lib.ex
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,8 @@ defmodule Teiserver.Battle.BalanceLib do
captain.member_id
end

@spec default_rating :: List.t()
@spec default_rating(non_neg_integer()) :: List.t()
@spec default_rating :: any()
@spec default_rating(non_neg_integer()) :: any()
def default_rating(rating_type_id \\ nil) do
{skill, uncertainty} = Openskill.rating()
rating_value = calculate_rating_value(skill, uncertainty)
Expand All @@ -595,7 +595,8 @@ defmodule Teiserver.Battle.BalanceLib do
skill: skill,
uncertainty: uncertainty,
rating_value: rating_value,
leaderboard_rating: leaderboard_rating
leaderboard_rating: leaderboard_rating,
num_matches: 0
}
end

Expand Down Expand Up @@ -704,7 +705,21 @@ defmodule Teiserver.Battle.BalanceLib do

@spec calculate_rating_value(float(), float()) :: float()
def calculate_rating_value(skill, uncertainty) do
max(skill - uncertainty, 0)
calculate_rating_value(skill, uncertainty, 0)
end

@spec calculate_rating_value(float(), float(), integer()) :: float()
def calculate_rating_value(skill, uncertainty, num_matches) do
if Config.get_site_config("profile.Rating method") == "start at zero; converge to skill" do
num_matches_target = get_num_matches_for_rating_to_equal_skill()
min(1, num_matches / num_matches_target) * skill
else
max(skill - uncertainty, 0)
end
end

def get_num_matches_for_rating_to_equal_skill() do
Config.get_site_config("profile.Num matches for rating to equal skill")
end

@doc """
Expand Down
5 changes: 4 additions & 1 deletion lib/teiserver/game/libs/match_rating_lib.ex
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,10 @@ defmodule Teiserver.Game.MatchRatingLib do

rating_type_id = user_rating.rating_type_id
{new_skill, new_uncertainty} = rating_update
new_rating_value = BalanceLib.calculate_rating_value(new_skill, new_uncertainty)

new_rating_value =
BalanceLib.calculate_rating_value(new_skill, new_uncertainty, new_num_matches)

new_leaderboard_rating = BalanceLib.calculate_leaderboard_rating(new_skill, new_uncertainty)

Account.update_rating(user_rating, %{
Expand Down
23 changes: 23 additions & 0 deletions lib/teiserver/libs/teiserver_configs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule Teiserver.TeiserverConfigs do
lobby_configs()
debugging_configs()
profile_configs()
hidden_configs()
end

@spec site_configs :: any
Expand Down Expand Up @@ -578,6 +579,15 @@ defmodule Teiserver.TeiserverConfigs do
opts: [choices: ["Leaderboard rating", "Rating value", "Playtime", "Role"]]
})

add_site_config_type(%{
key: "profile.Num matches for rating to equal skill",
section: "Profiles",
type: "integer",
default: 30,
permissions: ["Admin"],
description: "The minimum number of matches required for match rating to equal skill"
})

add_site_config_type(%{
key: "user.Enable one time links",
section: "User permissions",
Expand Down Expand Up @@ -633,4 +643,17 @@ defmodule Teiserver.TeiserverConfigs do
value_label: "Light mode as default"
})
end

@spec hidden_configs() :: :ok
defp hidden_configs() do
add_site_config_type(%{
key: "hidden.Rating method",
section: "Hidden",
type: "select",
default: "skill minus uncertainty",
permissions: ["Admin"],
description: "The rating system. Use Mix.Tasks.Teiserver.ProvisionalRatingSetup to change.",
opts: [choices: ["skill minus uncertainty", "start at zero; converge to skill"]]
})
end
end
105 changes: 105 additions & 0 deletions lib/teiserver/mix_tasks/provisional_rating_setup.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
defmodule Mix.Tasks.Teiserver.ProvisionalRatingSetup do
@moduledoc """
mix teiserver.provisional_rating_setup
To rollback use:
mix teiserver.provisional_rating_setup -rollback
"""

use Mix.Task
require Logger
alias Teiserver.Config
alias Teiserver.Battle.BalanceLib

def run(args) do
Application.ensure_all_started(:teiserver)

rollback? = Enum.member?(args, "-rollback")
target_matches = BalanceLib.get_num_matches_for_rating_to_equal_skill()

sql_transaction_result =
Ecto.Multi.new()
|> Ecto.Multi.run(:create_temp_table, fn repo, _ ->
{query, params} =
case rollback? do
false ->
{"""
CREATE temp table temp_table as
SELECT
*,
least(1, cast(num_matches as decimal) / $1) * skill as new_rating
FROM
teiserver_account_ratings tar;
""", [target_matches]}

true ->
{"""
CREATE temp table temp_table as
SELECT
*,
greatest(0,skill-uncertainty ) as new_rating
FROM
teiserver_account_ratings tar;
""", []}
end

Ecto.Adapters.SQL.query(repo, query, params)
end)
|> Ecto.Multi.run(:add_logs, fn repo, _ ->
query = """
INSERT INTO teiserver_game_rating_logs (inserted_at, rating_type_id, user_id, value)
SELECT
now(),
rating_type_id,
user_id,
JSON_BUILD_OBJECT(
'skill', skill,
'reason', 'New rating system',
'uncertainty', uncertainty,
'rating_value', new_rating,
'skill_change', 0.0,
'uncertainty_change', 0.0,
'rating_value_change', t.new_rating - t.rating_value,
'num_matches', num_matches
)
FROM temp_table t;
"""

Ecto.Adapters.SQL.query(repo, query, [])
end)
|> Ecto.Multi.run(:update_ratings, fn repo, _ ->
query = """
UPDATE teiserver_account_ratings tar
SET
rating_value = t.new_rating,
last_updated = now()
FROM temp_table t
WHERE t.user_id = tar.user_id
and t.rating_type_id = tar.rating_type_id;
"""

Ecto.Adapters.SQL.query(repo, query, [])
end)
|> Teiserver.Repo.transaction()

with {:ok, _result} <- sql_transaction_result do
case rollback? do
true ->
Logger.info("Rollback to old rating system complete")

# This config is not viewable in the admin page as we don't want someone to manually change it.
# To change it use this mix task
Config.update_site_config("hidden.Rating method", "skill minus uncertainty")

false ->
Logger.info("New rating system change complete")
Config.update_site_config("hidden.Rating method", "start at zero; converge to skill")
end
else
_ ->
Logger.error("Task failed.")
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ defmodule TeiserverWeb.Admin.SiteConfigController do

@spec index(Plug.Conn.t(), any) :: Plug.Conn.t()
def index(conn, _params) do
site_configs = Config.get_grouped_site_configs()
site_configs =
Config.get_grouped_site_configs()
|> Enum.filter(fn x ->
case x do
{"Hidden", _} -> false
_ -> true
end
end)

conn
|> assign(:site_configs, site_configs)
Expand Down
8 changes: 7 additions & 1 deletion lib/teiserver_web/controllers/admin/user_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,13 @@ defmodule TeiserverWeb.Admin.UserController do
user_rating = existing_rating || BalanceLib.default_rating()
new_skill = changes["skill"] |> float_parse
new_uncertainty = changes["uncertainty"] |> float_parse
new_rating_value = BalanceLib.calculate_rating_value(new_skill, new_uncertainty)

new_rating_value =
BalanceLib.calculate_rating_value(
new_skill,
new_uncertainty,
user_rating.num_matches
)

new_leaderboard_rating =
BalanceLib.calculate_leaderboard_rating(new_skill, new_uncertainty)
Expand Down

0 comments on commit 4ed4f5c

Please sign in to comment.