1
0
mirror of https://github.com/avitex/elixir-glicko synced 2024-11-24 20:19:57 +00:00

Use tuples exclusively to represent players and results

This commit is contained in:
avitex 2017-11-17 11:08:25 +11:00
parent 61175818ad
commit faf5218189
6 changed files with 163 additions and 182 deletions

View File

@ -6,9 +6,6 @@ defmodule Glicko do
## Usage ## Usage
Players can be represented by either the convenience `Glicko.Player` module or a tuple (see `player_t`).
Results can be represented by either the convenience `Glicko.Result` module or a tuple (see `result_t`).
Get a player's new rating after a series of matches in a rating period. Get a player's new rating after a series of matches in a rating period.
iex> results = [Result.new(Player.new_v1([rating: 1400, rating_deviation: 30]), :win), iex> results = [Result.new(Player.new_v1([rating: 1400, rating_deviation: 30]), :win),
@ -16,13 +13,13 @@ defmodule Glicko do
...> Result.new(Player.new_v1([rating: 1700, rating_deviation: 300]), :loss)] ...> Result.new(Player.new_v1([rating: 1700, rating_deviation: 300]), :loss)]
iex> player = Player.new_v1([rating: 1500, rating_deviation: 200]) iex> player = Player.new_v1([rating: 1500, rating_deviation: 200])
iex> Glicko.new_rating(player, results, [system_constant: 0.5]) iex> Glicko.new_rating(player, results, [system_constant: 0.5])
%Glicko.Player{version: :v1, rating: 1464.0506705393013, rating_deviation: 151.51652412385727, volatility: nil} {1464.0506705393013, 151.51652412385727}
Get a player's new rating when they haven't played within a rating period. Get a player's new rating when they haven't played within a rating period.
iex> player = Player.new_v1([rating: 1500, rating_deviation: 200]) iex> player = Player.new_v1([rating: 1500, rating_deviation: 200])
iex> Glicko.new_rating(player, [], [system_constant: 0.5]) iex> Glicko.new_rating(player, [], [system_constant: 0.5])
%Glicko.Player{version: :v1, rating: 1.5e3, rating_deviation: 200.27141669877065, volatility: nil} {1.5e3, 200.27141669877065}
""" """
@ -34,18 +31,6 @@ defmodule Glicko do
@default_system_constant 0.8 @default_system_constant 0.8
@default_convergence_tolerance 1.0e-7 @default_convergence_tolerance 1.0e-7
@type version_t :: :v1 | :v2
@type rating_t :: float
@type rating_deviation_t :: float
@type volatility_t :: float
@type score_t :: float
@type player_t :: player_v1_t | player_v2_t
@type player_v1_t :: {rating :: rating_t, rating_deviation :: rating_deviation_t}
@type player_v2_t :: {rating :: rating_t, rating_deviation :: rating_deviation_t, volatility :: volatility_t}
@type result_t :: {opponent :: player_t, score :: score_t}
@type new_rating_opts_t :: [system_constant: float, convergence_tolerance: float] @type new_rating_opts_t :: [system_constant: float, convergence_tolerance: float]
@doc """ @doc """
@ -53,11 +38,16 @@ defmodule Glicko do
Returns the updated player with the same version given to the function. Returns the updated player with the same version given to the function.
""" """
@spec new_rating(player :: player_t | Player.t, results :: list(result_t | Result.t), opts :: new_rating_opts_t) :: player_t | Player.t @spec new_rating(player :: Player.t, results :: list(Result.t), opts :: new_rating_opts_t) :: Player.t
def new_rating(player, results, opts \\ []) do def new_rating(player, results, opts \\ [])
{cast_from, internal_player} = cast_player_to_internal(player) def new_rating(player, results, opts) when tuple_size(player) == 3 do
internal_player = do_new_rating(internal_player, results, opts) do_new_rating(player, results, opts)
cast_internal_to_player({cast_from, internal_player}) end
def new_rating(player, results, opts) when tuple_size(player) == 2 do
player
|> Player.to_v2
|> do_new_rating(results, opts)
|> Player.to_v1
end end
defp do_new_rating({player_rating, player_rating_deviation, player_volatility}, [], _) do defp do_new_rating({player_rating, player_rating_deviation, player_volatility}, [], _) do
@ -111,21 +101,16 @@ defmodule Glicko do
{ctx.new_player_rating, ctx.new_player_rating_deviation, ctx.new_player_volatility} {ctx.new_player_rating, ctx.new_player_rating_deviation, ctx.new_player_volatility}
end end
defp build_internal_result(ctx, {opponent, score}) do defp build_internal_result(ctx, result) do
{_, {opponent_rating, opponent_rating_deviation, _}} = cast_player_to_internal(opponent)
result = result =
Map.new Map.new
|> Map.put(:score, score) |> Map.put(:score, Result.score(result))
|> Map.put(:opponent_rating, opponent_rating) |> Map.put(:opponent_rating, Result.opponent_rating(result))
|> Map.put(:opponent_rating_deviation, opponent_rating_deviation) |> Map.put(:opponent_rating_deviation, Result.opponent_rating_deviation(result))
|> Map.put(:opponent_rating_deviation_g, calc_g(opponent_rating_deviation)) |> Map.put(:opponent_rating_deviation_g, calc_g(Result.opponent_rating_deviation(result)))
Map.put(result, :e, calc_e(ctx.player_rating, result)) Map.put(result, :e, calc_e(ctx.player_rating, result))
end end
defp build_internal_result(ctx, %Result{score: score, opponent: opponent}) do
build_internal_result(ctx, {opponent, score})
end
# Calculation of the estimated variance of the player's rating based on game outcomes # Calculation of the estimated variance of the player's rating based on game outcomes
defp calc_variance_estimate(ctx) do defp calc_variance_estimate(ctx) do
@ -218,26 +203,4 @@ defmodule Glicko do
defp calc_e(player_rating, result) do defp calc_e(player_rating, result) do
1 / (1 + :math.exp(-1 * result.opponent_rating_deviation_g * (player_rating - result.opponent_rating))) 1 / (1 + :math.exp(-1 * result.opponent_rating_deviation_g * (player_rating - result.opponent_rating)))
end end
defp cast_player_to_internal(player) when is_tuple(player) and tuple_size(player) == 2 do
{:v1, Player.new_v1(player) |> Player.to_v2 |> cast_player_to_internal |> elem(1)}
end
defp cast_player_to_internal(player) when is_tuple(player) and tuple_size(player) == 3 do
{:v2, player}
end
defp cast_player_to_internal(player = %Player{version: :v1}) do
{:player_v1, player |> Player.to_v2 |> cast_player_to_internal |> elem(1)}
end
defp cast_player_to_internal(player = %Player{version: :v2}) do
{:player_v2, {player.rating, player.rating_deviation, player.volatility}}
end
defp cast_internal_to_player({:v1, {rating, rating_deviation, _}}), do: {
rating |> Player.scale_rating_to(:v1),
rating_deviation |> Player.scale_rating_deviation_to(:v1),
}
defp cast_internal_to_player({:v2, player}), do: player
defp cast_internal_to_player({:player_v1, player}), do: Player.new_v2(player) |> Player.to_v1
defp cast_internal_to_player({:player_v2, player}), do: Player.new_v2(player)
end end

View File

@ -1,28 +1,33 @@
defmodule Glicko.Player do defmodule Glicko.Player do
@moduledoc """ @moduledoc """
A convenience wrapper that handles conversions between glicko versions one and two. Provides convenience functions that handle conversions between Glicko versions one and two.
## Usage ## Usage
Create a player with the default values for an unrated player. Create a *v1* player with the default values for an unrated player.
iex> Player.new_v1
{1.5e3, 350.0}
Create a *v2* player with the default values for an unrated player.
iex> Player.new_v2 iex> Player.new_v2
%Player{version: :v2, rating: 0.0, rating_deviation: 2.014761872416068, volatility: 0.06} {0.0, 2.014761872416068, 0.06}
Create a player with custom values. Create a player with custom values.
iex> Player.new_v2([rating: 1500, rating_deviation: 50, volatility: 0.05]) iex> Player.new_v2([rating: 3.0, rating_deviation: 2.0, volatility: 0.05])
%Player{version: :v2, rating: 1500, rating_deviation: 50, volatility: 0.05} {3.0, 2.0, 0.05}
Convert a *v2* player to a *v1*. Note this drops the volatility. Convert a *v2* player to a *v1*. Note this drops the volatility.
iex> Player.new_v2 |> Player.to_v1 iex> Player.new_v2 |> Player.to_v1
%Player{version: :v1, rating: 1.5e3, rating_deviation: 350.0, volatility: nil} {1.5e3, 350.0}
Convert a *v1* player to a *v2*. Convert a *v1* player to a *v2*.
iex> Player.new_v1 |> Player.to_v2(0.06) iex> Player.new_v1 |> Player.to_v2(0.06)
%Player{version: :v2, rating: 0.0, rating_deviation: 2.014761872416068, volatility: 0.06} {0.0, 2.014761872416068, 0.06}
Note calling `to_v1` with a *v1* player or likewise with `to_v2` and a *v2* player Note calling `to_v1` with a *v1* player or likewise with `to_v2` and a *v2* player
will pass-through unchanged. The volatility arg in this case is ignored. will pass-through unchanged. The volatility arg in this case is ignored.
@ -38,89 +43,56 @@ defmodule Glicko.Player do
@type t :: v1_t | v2_t @type t :: v1_t | v2_t
@type v1_t :: %__MODULE__{ @type v1_t :: {rating_t, rating_deviation_t}
version: :v1, @type v2_t :: {rating_t, rating_deviation_t, volatility_t}
rating: Glicko.rating_t,
rating_deviation: Glicko.rating_deviation_t,
volatility: nil,
}
@type v2_t :: %__MODULE__{ @type version_t :: :v1 | :v2
version: :v2, @type rating_t :: float
rating: Glicko.rating_t, @type rating_deviation_t :: float
rating_deviation: Glicko.rating_deviation_t, @type volatility_t :: float
volatility: Glicko.volatility_t,
}
defstruct [
:version,
:rating,
:rating_deviation,
:volatility,
]
@doc """ @doc """
The recommended initial rating value for a new player. The recommended initial rating value for a new player.
""" """
@spec initial_rating(Glicko.version_t) :: Glicko.rating_t @spec initial_rating(version_t) :: rating_t
def initial_rating(:v1), do: 1500.0 def initial_rating(_version = :v1), do: 1500.0
def initial_rating(:v2), do: initial_rating(:v1) |> scale_rating_to(:v2) def initial_rating(_version = :v2), do: :v1 |> initial_rating |> scale_rating_to(:v2)
@doc """ @doc """
The recommended initial rating deviation value for a new player. The recommended initial rating deviation value for a new player.
""" """
@spec initial_rating_deviation(Glicko.version_t) :: Glicko.rating_deviation_t @spec initial_rating_deviation(version_t) :: rating_deviation_t
def initial_rating_deviation(:v1), do: 350.0 def initial_rating_deviation(_version = :v1), do: 350.0
def initial_rating_deviation(:v2), do: initial_rating_deviation(:v1) |> scale_rating_deviation_to(:v2) def initial_rating_deviation(_version = :v2), do: :v1 |> initial_rating_deviation |> scale_rating_deviation_to(:v2)
@doc """ @doc """
The recommended initial volatility value for a new player. The recommended initial volatility value for a new player.
""" """
@spec initial_v2_volatility :: Glicko.volatility_t @spec initial_volatility :: volatility_t
def initial_v2_volatility, do: 0.06 def initial_volatility, do: 0.06
@doc """ @doc """
Creates a new v1 player. Creates a new v1 player.
If not overriden, will use the default values for an unrated player. If not overriden, will use the default values for an unrated player.
""" """
@spec new_v1( @spec new_v1([rating: rating_t, rating_deviation: rating_deviation_t]) :: v1_t
{Glicko.rating_t, Glicko.rating_deviation_t} | def new_v1(opts \\ []) when is_list(opts), do: {
[rating: Glicko.rating_t, rating_deviation: Glicko.rating_deviation_t]
) :: v1_t
def new_v1(opts \\ [])
def new_v1({rating, rating_deviation}), do: %__MODULE__{
version: :v1,
rating: rating,
rating_deviation: rating_deviation,
volatility: nil,
}
def new_v1(opts), do: new_v1({
Keyword.get(opts, :rating, initial_rating(:v1)), Keyword.get(opts, :rating, initial_rating(:v1)),
Keyword.get(opts, :rating_deviation, initial_rating_deviation(:v1)), Keyword.get(opts, :rating_deviation, initial_rating_deviation(:v1)),
}) }
@doc """ @doc """
Creates a new v2 player. Creates a new v2 player.
If not overriden, will use default values for an unrated player. If not overriden, will use default values for an unrated player.
""" """
@spec new_v2( @spec new_v2([rating: rating_t, rating_deviation: rating_deviation_t, volatility: volatility_t]) :: v2_t
{Glicko.rating_t, Glicko.rating_deviation_t, Glicko.volatility_t} | def new_v2(opts \\ []) when is_list(opts), do: {
[rating: Glicko.rating_t, rating_deviation: Glicko.rating_deviation_t, volatility: Glicko.volatility_t]
) :: v2_t
def new_v2(opts \\ [])
def new_v2({rating, rating_deviation, volatility}), do: %__MODULE__{
version: :v2,
rating: rating,
rating_deviation: rating_deviation,
volatility: volatility,
}
def new_v2(opts), do: new_v2({
Keyword.get(opts, :rating, initial_rating(:v2)), Keyword.get(opts, :rating, initial_rating(:v2)),
Keyword.get(opts, :rating_deviation, initial_rating_deviation(:v2)), Keyword.get(opts, :rating_deviation, initial_rating_deviation(:v2)),
Keyword.get(opts, :volatility, initial_v2_volatility()), Keyword.get(opts, :volatility, initial_volatility()),
}) }
@doc """ @doc """
Converts a v2 player to a v1. Converts a v2 player to a v1.
@ -130,25 +102,57 @@ defmodule Glicko.Player do
Note the volatility field used in a v2 player will be lost in the conversion. Note the volatility field used in a v2 player will be lost in the conversion.
""" """
@spec to_v1(player :: t) :: v1_t @spec to_v1(player :: t) :: v1_t
def to_v1(player = %__MODULE__{version: :v1}), do: player def to_v1({rating, rating_deviation}), do: {rating, rating_deviation}
def to_v1(player = %__MODULE__{version: :v2}), do: new_v1([ def to_v1({rating, rating_deviation, _}), do: {
rating: player.rating |> scale_rating_to(:v1), rating |> scale_rating_to(:v1),
rating_deviation: player.rating_deviation |> scale_rating_deviation_to(:v1), rating_deviation |> scale_rating_deviation_to(:v1),
]) }
@doc """ @doc """
Converts a v1 player to a v2. Converts a v1 player to a v2.
A v2 player will pass-through unchanged with the volatility arg ignored. A v2 player will pass-through unchanged with the volatility arg ignored.
""" """
@spec to_v2(player :: t, volatility :: float) :: v2_t @spec to_v2(player :: t, volatility :: volatility_t) :: v2_t
def to_v2(player, volatility \\ initial_v2_volatility()) def to_v2(player, volatility \\ initial_volatility())
def to_v2(player = %__MODULE__{version: :v2}, _volatility), do: player def to_v2({rating, rating_deviation, volatility}, _volatility), do: {rating, rating_deviation, volatility}
def to_v2(player = %__MODULE__{version: :v1}, volatility), do: new_v2([ def to_v2({rating, rating_deviation}, volatility), do: {
rating: player.rating |> scale_rating_to(:v2), rating |> scale_rating_to(:v2),
rating_deviation: player.rating_deviation |> scale_rating_deviation_to(:v2), rating_deviation |> scale_rating_deviation_to(:v2),
volatility: volatility, volatility,
]) }
@doc """
A version agnostic method for getting a player's rating.
"""
@spec rating(player :: t, as_version :: version_t) :: rating_t
def rating(player, as_version \\ nil)
def rating({rating, _}, nil), do: rating
def rating({rating, _, _}, nil), do: rating
def rating({rating, _}, :v1), do: rating
def rating({rating, _}, :v2), do: rating |> scale_rating_to(:v2)
def rating({rating, _, _}, :v1), do: rating |> scale_rating_to(:v1)
def rating({rating, _, _}, :v2), do: rating
@doc """
A version agnostic method for getting a player's rating deviation.
"""
@spec rating_deviation(player :: t, as_version :: version_t) :: rating_deviation_t
def rating_deviation(player, as_version \\ nil)
def rating_deviation({_, rating_deviation}, nil), do: rating_deviation
def rating_deviation({_, rating_deviation, _}, nil), do: rating_deviation
def rating_deviation({_, rating_deviation}, :v1), do: rating_deviation
def rating_deviation({_, rating_deviation}, :v2), do: rating_deviation |> scale_rating_deviation_to(:v2)
def rating_deviation({_, rating_deviation, _}, :v1), do: rating_deviation |> scale_rating_deviation_to(:v1)
def rating_deviation({_, rating_deviation, _}, :v2), do: rating_deviation
@doc """
A version agnostic method for getting a player's volatility.
"""
@spec volatility(player :: t, default_volatility :: volatility_t) :: volatility_t
def volatility(player, default_volatility \\ initial_volatility())
def volatility({_, _}, default_volatility), do: default_volatility
def volatility({_, _, volatility}, _), do: volatility
@doc """ @doc """
A convenience function for summarizing a player's strength as a 95% A convenience function for summarizing a player's strength as a 95%
@ -166,23 +170,23 @@ defmodule Glicko.Player do
be 95% confident about a players strength being in a small interval of values. be 95% confident about a players strength being in a small interval of values.
""" """
@spec rating_interval(player :: t) :: {rating_low :: float, rating_high :: float} @spec rating_interval(player :: t) :: {rating_low :: float, rating_high :: float}
def rating_interval(player), do: { def rating_interval(player, as_version \\ nil), do: {
player.rating - player.rating_deviation * 2, rating(player, as_version) - rating_deviation(player, as_version) * 2,
player.rating + player.rating_deviation * 2, rating(player, as_version) + rating_deviation(player, as_version) * 2,
} }
@doc """ @doc """
Scales a player's rating. Scales a player's rating.
""" """
@spec scale_rating_to(rating :: Glicko.rating_t, to_version :: Glicko.version_t) :: Glicko.rating_t @spec scale_rating_to(rating :: rating_t, to_version :: version_t) :: rating_t
def scale_rating_to(rating, :v1), do: (rating * @magic_version_scale) + @magic_version_scale_rating def scale_rating_to(rating, _version = :v1), do: (rating * @magic_version_scale) + @magic_version_scale_rating
def scale_rating_to(rating, :v2), do: (rating - @magic_version_scale_rating) / @magic_version_scale def scale_rating_to(rating, _version = :v2), do: (rating - @magic_version_scale_rating) / @magic_version_scale
@doc """ @doc """
Scales a player's rating deviation. Scales a player's rating deviation.
""" """
@spec scale_rating_deviation_to(rating_deviation :: Glicko.rating_deviation_t, to_version :: Glicko.version_t) :: Glicko.rating_deviation_t @spec scale_rating_deviation_to(rating_deviation :: rating_deviation_t, to_version :: version_t) :: rating_deviation_t
def scale_rating_deviation_to(rating_deviation, :v1), do: rating_deviation * @magic_version_scale def scale_rating_deviation_to(rating_deviation, _version = :v1), do: rating_deviation * @magic_version_scale
def scale_rating_deviation_to(rating_deviation, :v2), do: rating_deviation / @magic_version_scale def scale_rating_deviation_to(rating_deviation, _version = :v2), do: rating_deviation / @magic_version_scale
end end

View File

@ -1,41 +1,66 @@
defmodule Glicko.Result do defmodule Glicko.Result do
@moduledoc """ @moduledoc """
A convenience wrapper representing a result against an opponent. Convenience functions for handling a result against an opponent.
## Usage ## Usage
iex> opponent = Player.new_v2 iex> opponent = Player.new_v2
iex> Result.new(opponent, 0.0) iex> Result.new(opponent, 1.0)
%Result{score: 0.0, opponent: %Player{version: :v2, rating: 0.0, rating_deviation: 2.014761872416068, volatility: 0.06}} {0.0, 2.014761872416068, 1.0}
iex> Result.new(opponent, :win) # With shortcut iex> Result.new(opponent, :draw) # With shortcut
%Result{score: 1.0, opponent: %Player{version: :v2, rating: 0.0, rating_deviation: 2.014761872416068, volatility: 0.06}} {0.0, 2.014761872416068, 0.5}
""" """
alias Glicko.Player alias Glicko.Player
defstruct [ @type t :: {Player.rating_t, Player.rating_deviation_t, score_t}
:score,
:opponent,
]
@type t :: %__MODULE__{score: Glicko.score_t, opponent: Glicko.player_t | Player.t} @type score_t :: float
@type score_shortcut_t :: :loss | :draw | :win
@type result_type_t :: :loss | :draw | :win @score_shortcut_map %{loss: 0.0, draw: 0.5, win: 1.0}
@score_shortcuts Map.keys(@score_shortcut_map)
@result_type_map %{loss: 0.0, draw: 0.5, win: 1.0}
@doc """ @doc """
Creates a new Result against an opponent. Creates a new result from an opponent rating, opponent rating deviation and score.
Supports passing either `:loss`, `:draw`, or `:win` as shortcuts. Supports passing either `:loss`, `:draw`, or `:win` as shortcuts.
""" """
@spec new(opponent :: Glicko.player_t | Player.t, result_type_t | float) :: t @spec new(Player.rating_t, Player.rating_deviation_t, score_t | score_shortcut_t) :: t
def new(opponent, result_type) when is_atom(result_type) and result_type in [:loss, :draw, :win] do def new(opponent_rating, opponent_rating_deviation, score) when is_number(score) do
new(opponent, Map.fetch!(@result_type_map, result_type)) {opponent_rating, opponent_rating_deviation, score}
end end
def new(opponent, score) when is_number(score), do: %__MODULE__{ def new(opponent_rating, opponent_rating_deviation, score_type) when is_atom(score_type) and score_type in @score_shortcuts do
score: score, {opponent_rating, opponent_rating_deviation, Map.fetch!(@score_shortcut_map, score_type)}
opponent: opponent, end
}
@doc """
Creates a new result from an opponent and score.
Supports passing either `:loss`, `:draw`, or `:win` as shortcuts.
"""
@spec new(opponent :: Player.t, score :: score_t | score_shortcut_t) :: t
def new(opponent, score) do
new(Player.rating(opponent, :v2), Player.rating_deviation(opponent, :v2), score)
end
@doc """
Convenience function for accessing an opponent's rating.
"""
@spec opponent_rating(result :: Result.t) :: Player.rating_t
def opponent_rating(_result = {rating, _, _}), do: rating
@doc """
Convenience function for accessing an opponent's rating deviation.
"""
@spec opponent_rating_deviation(result :: Result.t) :: Player.rating_deviation_t
def opponent_rating_deviation(_result = {_, rating_deviation, _}), do: rating_deviation
@doc """
Convenience function for accessing the score.
"""
@spec score(result :: Result.t) :: score_t
def score(_result = {_, _, score}), do: score
end end

View File

@ -11,8 +11,8 @@ defmodule GlickoTest do
@player Player.new_v1([rating: 1500, rating_deviation: 200]) |> Player.to_v2 @player Player.new_v1([rating: 1500, rating_deviation: 200]) |> Player.to_v2
@results [ @results [
{{1400, 30}, 1.0}, Result.new(Player.new_v1([rating: 1400, rating_deviation: 30]), :win),
Result.new({1550, 100}, :loss), Result.new(Player.new_v1([rating: 1550, rating_deviation: 100]), :loss),
Result.new(Player.new_v1([rating: 1700, rating_deviation: 300]), :loss), Result.new(Player.new_v1([rating: 1700, rating_deviation: 300]), :loss),
] ]
@ -23,17 +23,16 @@ defmodule GlickoTest do
@valid_player_rating_deviation_after_no_results 200.2714 |> Player.scale_rating_deviation_to(:v2) @valid_player_rating_deviation_after_no_results 200.2714 |> Player.scale_rating_deviation_to(:v2)
test "new rating (with results)" do test "new rating (with results)" do
%Player{rating: new_rating, rating_deviation: new_rating_deviation, volatility: new_volatility} = player = Glicko.new_rating(@player, @results, [system_constant: 0.5])
Glicko.new_rating(@player, @results, [system_constant: 0.5])
assert_in_delta new_rating, @valid_player_rating_after_results, 1.0e-4 assert_in_delta Player.rating(player), @valid_player_rating_after_results, 1.0e-4
assert_in_delta new_rating_deviation, @valid_player_rating_deviation_after_results, 1.0e-4 assert_in_delta Player.rating_deviation(player), @valid_player_rating_deviation_after_results, 1.0e-4
assert_in_delta new_volatility, @valid_player_volatility_after_results, 1.0e-5 assert_in_delta Player.volatility(player), @valid_player_volatility_after_results, 1.0e-5
end end
test "new rating (no results)" do test "new rating (no results)" do
%Player{rating_deviation: new_rating_deviation} = Glicko.new_rating(@player, []) player = Glicko.new_rating(@player, [])
assert_in_delta new_rating_deviation, @valid_player_rating_deviation_after_no_results, 1.0e-4 assert_in_delta Player.rating_deviation(player), @valid_player_rating_deviation_after_no_results, 1.0e-4
end end
end end

View File

@ -5,8 +5,8 @@ defmodule Glicko.PlayerTest do
doctest Player doctest Player
@valid_v1_base %Player{version: :v1, rating: 1.0, rating_deviation: 2.0, volatility: nil} @valid_v1_base {1.0, 2.0}
@valid_v2_base %Player{version: :v2, rating: 1.0, rating_deviation: 2.0, volatility: 3.0} @valid_v2_base {1.0, 2.0, 3.0}
test "create v1" do test "create v1" do
assert @valid_v1_base == Player.new_v1([rating: 1.0, rating_deviation: 2.0]) assert @valid_v1_base == Player.new_v1([rating: 1.0, rating_deviation: 2.0])
@ -17,21 +17,11 @@ defmodule Glicko.PlayerTest do
end end
test "convert player v1 -> v2" do test "convert player v1 -> v2" do
assert %Player{ assert {Player.scale_rating_to(1.0, :v2), Player.scale_rating_deviation_to(2.0, :v2), 3.0} == Player.to_v2(@valid_v1_base, 3.0)
version: :v2,
rating: Player.scale_rating_to(1.0, :v2),
rating_deviation: Player.scale_rating_deviation_to(2.0, :v2),
volatility: 3.0,
} == Player.to_v2(@valid_v1_base, 3.0)
end end
test "convert player v2 -> v1" do test "convert player v2 -> v1" do
assert %Player{ assert {Player.scale_rating_to(1.0, :v1), Player.scale_rating_deviation_to(2.0, :v1)} == Player.to_v1(@valid_v2_base)
version: :v1,
rating: Player.scale_rating_to(1.0, :v1),
rating_deviation: Player.scale_rating_deviation_to(2.0, :v1),
volatility: nil,
} == Player.to_v1(@valid_v2_base)
end end
test "convert player v1 -> v1" do test "convert player v1 -> v1" do

View File

@ -10,7 +10,7 @@ defmodule Glicko.ResultTest do
@opponent Player.new_v2 @opponent Player.new_v2
@valid_game_result %Result{opponent: @opponent, score: 0.0} @valid_game_result Result.new(@opponent, 0.0)
test "create game result" do test "create game result" do
assert @valid_game_result == Result.new(@opponent, 0.0) assert @valid_game_result == Result.new(@opponent, 0.0)