Skip to content

Commit

Permalink
Improve season uncertainty reset
Browse files Browse the repository at this point in the history
Improve season uncertainty reset by taking into account players who have not played in a long time
  • Loading branch information
jauggy committed Dec 8, 2024
1 parent d7df6d3 commit 1960a99
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 4 deletions.
48 changes: 44 additions & 4 deletions lib/teiserver/battle/tasks/seasonal_uncertainty_reset_task.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ defmodule Teiserver.Battle.SeasonalUncertaintyResetTask do
start_time = System.system_time(:millisecond)

new_last_updated = Timex.now()
{_skill, new_uncertainty} = Openskill.rating()

ratings_count =
Account.list_ratings(limit: :infinity)
|> Enum.map(fn rating ->
reset_rating(rating, new_uncertainty, new_last_updated)
reset_rating(rating, new_last_updated)
1
end)
|> Enum.count()
Expand All @@ -25,9 +24,13 @@ defmodule Teiserver.Battle.SeasonalUncertaintyResetTask do
)
end

defp reset_rating(existing, _new_uncertainty, new_last_updated) do
defp reset_rating(existing, new_last_updated) do
# Use the greater of the existing uncertainty or the minimum value (5.0)
new_uncertainty = max(existing.uncertainty, 5.0)
current_uncertainty = existing.uncertainty
# datetime
last_updated = existing.last_updated

new_uncertainty = calculate_new_uncertainty(current_uncertainty, last_updated)

new_rating_value = BalanceLib.calculate_rating_value(existing.skill, new_uncertainty)

Expand Down Expand Up @@ -59,4 +62,41 @@ defmodule Teiserver.Battle.SeasonalUncertaintyResetTask do

{:ok, _} = Game.create_rating_log(log_params)
end

def calculate_new_uncertainty(current_uncertainty, last_update_datetime) do
days_not_played = abs(DateTime.diff(last_update_datetime, Timex.now(), :day))
target_uncertainty = calculate_target_uncertainty(days_not_played)
# The new uncertainty can increase but never decrease
max(target_uncertainty, current_uncertainty)
end

# This is the player's new target uncertainty
# If the player hasn't played for a while, their target uncertainty will be higher
def calculate_target_uncertainty(days_not_played) do
# If you haven't played for more than a year reset uncertainty to default
# If you have played within one month, then the target uncertainty equals min_uncertainty
# If it's something in between one month and a year, use linear interpolation
# Linear interpolation formula: https://www.cuemath.com/linear-interpolation-formula/
one_year = 365
one_month = one_year / 12
min_uncertainty = 5
{_skill, max_uncertainty} = Openskill.rating()

cond do
days_not_played >= one_year ->
max_uncertainty

days_not_played <= one_month ->
min_uncertainty

true ->
max_days = one_year
min_days = one_month

# linear interpolation will give a value between min_uncertainty and max_uncertainty
min_uncertainty +
(days_not_played - min_days) * (max_uncertainty - min_uncertainty) /
(max_days - min_days)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Teiserver.Battle.SeasonalUncertaintyResetTaskTest do
@moduledoc """
Can run all balance tests via
mix test --only balance_test
"""
use ExUnit.Case
@moduletag :balance_test
alias Teiserver.Battle.SeasonalUncertaintyResetTask

test "can calculate target uncertainty" do
result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(400)
assert result == 8.333333333333334

one_year = 365

one_month = one_year / 12

# If you played yesterday then it should pick the min uncertainty of 5
result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(1)
assert result == 5

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month)
assert result == 5

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month * 2)
assert result == 5.303030303030303

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month * 3)
assert result == 5.6060606060606063

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month * 6)
assert result == 6.515151515151516

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month * 9)
assert result == 7.424242424242426

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_month * 11)
assert result == 8.030303030303031

result = SeasonalUncertaintyResetTask.calculate_target_uncertainty(one_year)
assert result == 8.333333333333334

{_, end_date} = DateTime.new(~D[2016-05-24], ~T[13:26:08.003], "Etc/UTC")
{_, start_date} = DateTime.new(~D[2016-04-24], ~T[13:26:08.003], "Etc/UTC")
days = abs(DateTime.diff(start_date, end_date, :day))
assert days == 30
end
end

0 comments on commit 1960a99

Please sign in to comment.