Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Glicko-2 rating system #157

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions GLICKO-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Taylor Petrick

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3 changes: 3 additions & 0 deletions src/map/map-server.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@
<ClInclude Include="pc_groups.hpp" />
<ClInclude Include="pet.hpp" />
<ClInclude Include="quest.hpp" />
<ClInclude Include="rating.hpp" />
<ClInclude Include="rating_config.hpp" />
<ClInclude Include="script.hpp" />
<ClInclude Include="script_constants.hpp" />
<ClInclude Include="searchstore.hpp" />
Expand Down Expand Up @@ -244,6 +246,7 @@
<ClCompile Include="pc_groups.cpp" />
<ClCompile Include="pet.cpp" />
<ClCompile Include="quest.cpp" />
<ClCompile Include="rating.cpp" />
<ClCompile Include="script.cpp" />
<ClCompile Include="searchstore.cpp" />
<ClCompile Include="skill.cpp" />
Expand Down
9 changes: 9 additions & 0 deletions src/map/map-server.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@
<ClInclude Include="vending.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rating.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rating_config.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="achievement.cpp">
Expand Down Expand Up @@ -268,5 +274,8 @@
<ClCompile Include="vending.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rating.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
151 changes: 151 additions & 0 deletions src/map/rating.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include "rating.hpp"

#include <cmath>
#include <cstdlib>

#include "pc.hpp"

#include "../common/malloc.h"
#include "../common/showmsg.h"

using namespace Glicko;

Rating::Rating(const double rating,
const double deviation,
const double volatility)
{
u = (rating - Glicko::kDefaultR) / Glicko::kScale;
p = deviation / Glicko::kScale;
s = volatility;
}

Rating::Rating(const Rating& rating)
{
u = rating.u;
p = rating.p;
s = rating.s;
}

/**
* Constructs rating from rAthena's map_session_data
* @author Secret <[email protected]>
*/
Rating::Rating(map_session_data* sd)
{
char* u_reg = pc_readregistry_str(sd, add_str("RATING_MU$"));
char* p_reg = pc_readregistry_str(sd, add_str("RATING_PHI$"));
char* s_reg = pc_readregistry_str(sd, add_str("RATING_SIGMA$"));

if (u_reg != nullptr)
u = std::atof(u_reg);
else
u = 0.0;

if (p_reg != nullptr)
p = std::atof(p_reg);
else
p = Glicko::kDefaultRD / Glicko::kScale;

if (s_reg != nullptr)
s = std::atof(s_reg);
else
s = Glicko::kDefaultS;
}

void Rating::Update(const Rating& opponent, const double score)
{
// Compute the e and g function values
double g = opponent.G();
double e = opponent.E(g, *this);

// Compute 1/v and v
double invV = g * g * e * (1.0 - e);
double v = 1.0 / invV;

// Compute the delta value from the g, e, and v
// values
double dInner = g * (score - e);
double d = v * dInner;

// Compute new rating, deviation and volatility values
sPrime = exp(Convergence(d, v, p, s)/2.0);
pPrime = 1.0 / sqrt((1.0/(p*p + sPrime*sPrime)) + invV);
uPrime = u + pPrime * pPrime * dInner;
}

void Rating::Decay()
{
// Decay the deviation if no games were played
pPrime = sqrt(p*p + s*s);
}

void Rating::Apply()
{
// Assign the new pending values to the actual rating values
u = uPrime;
p = pPrime;
s = sPrime;
}

double Rating::Convergence(const double d,
const double v,
const double p,
const double s)
{
// Initialize function values for iteration procedure
double dS = d*d;
double pS = p*p;
double tS = Glicko::kSystemConst * Glicko::kSystemConst;
double a = log(s*s);

// Select the upper and lower iteration ranges
double A = a;
double B;
double bTest = dS - pS - v;

if (bTest > 0.0)
{
B = log(bTest);
}
else
{
B = a - Glicko::kSystemConst;
while (F(B, dS, pS, v, a, tS) < 0.0)
{
B -= Glicko::kSystemConst;
}
}

// Perform the iteration
double fA = F(A, dS, pS, v, a, tS);
double fB = F(B, dS, pS, v, a, tS);
while (fabs(B - A) > Glicko::kConvergence)
{
double C = A + (A - B) * fA / (fB - fA);
double fC = F(C, dS, pS, v, a, tS);

if (fC * fB < 0.0)
{
A = B;
fA = fB;
}
else
{
fA /= 2.0;
}

B = C;
fB = fC;
}

return A;
}

rating_data Rating::c_struct() {
rating_data data;
data.u = u;
data.p = p;
data.s = s;

return data;
}
148 changes: 148 additions & 0 deletions src/map/rating.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#ifndef GLICKO_RATING_HPP
#define GLICKO_RATING_HPP

#define _USE_MATH_DEFINES
#include <math.h>
#include <iostream>

#include "rating_config.hpp"

struct map_session_data;

namespace Glicko
{
struct rating_data {
double u;
double p;
double s;
};

/// Defines a struct that contains Glicko rating parameters Parameters are
/// stored in the Glicko-2 rating scale, but can also be queried in in
/// original Glicko scale.
class Rating
{
public:
/// Constructs a rating with from a desired rating and deviation.
/// Defaults to the Glicko-1 standard of R = 1500, RD = 350.
Rating(const double rating = Glicko::kDefaultR,
const double deviation = Glicko::kDefaultRD,
const double volatility = Glicko::kDefaultS);

/// Constructs a rating from a map_session_data object [Secret]
Rating(map_session_data* sd);

/// Constructs a rating from another rating instance
Rating(const Rating& rating);

// Updates the rating based on a single game
void Update(const Rating& opponent, const double score);

// Decays the rating deviation
void Decay();

/// Applies the updated ratings
void Apply();

// Gets a PoD representation of this Glicko rating [Secret]
rating_data c_struct();

/// Returns the Glicko-1 rating
inline double Rating1() const
{
return (u * Glicko::kScale) + Glicko::kDefaultR;
}

/// Returns the Glicko-1 deviation
inline double Deviation1() const
{
return p * Glicko::kScale;
}

/// Returns the Glicko-2 rating
inline double Rating2() const
{
return u;
}

/// Returns the Glicko-2 deviation
inline double Deviation2() const
{
return p;
}

inline double Volatility() const
{
return s;
}

/// Outputs the rating in Glicko-1 fromat
friend inline std::ostream& operator<<(std::ostream& pStream,
const Rating& pRating)
{
pStream << "[" << pRating.Rating1()
<< ":" << pRating.Deviation1()
<< "]";

return pStream;
}

private:
/// Computes the value of the g function for a rating
inline double G() const
{
double scale = p / M_PI;
return 1.0 / sqrt(1.0 + 3.0 * scale * scale);
}

/// Computes the value of the e function in terms of a g function value
/// and another rating
inline double E(const double g, const Rating& rating) const
{
double exponent = -1.0 * g * (rating.u - u);
return 1.0 / (1.0 + exp(exponent));
}

/// Computes the value of the f function in terms of x, delta^2, phi^2,
/// v, a and tau^2.
static inline double F(const double x,
const double dS,
const double pS,
const double v,
const double a,
const double tS)
{
double eX = exp(x);
double num = eX * (dS - pS - v - eX);
double den = pS + v + eX;

return (num/ (2.0 * den * den)) - ((x - a)/tS);
}

/// Performs convergence iteration on the function f
static double Convergence(const double d,
const double v,
const double p,
const double s);

/// The rating u (mu)
double u;

/// The rating deviation p (phi)
double p;

/// The rating volatility s (sigma)
double s;

/// The pending rating value, u'
double uPrime;

/// The pending deviation value, u'
double pPrime;

/// The pending volatility value, s'
double sPrime;
};
}

#endif
26 changes: 26 additions & 0 deletions src/map/rating_config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef GLICKO_CONFIG_HPP
#define GLICKO_CONFIG_HPP

namespace Glicko
{
/// The default/initial rating value
static const double kDefaultR = 1500.0;

/// The default/initial deviation value
static const double kDefaultRD = 350.0;

/// The default/initial volatility value
static const double kDefaultS = 0.06;


/// The Glicko-1 to Glicko-2 scale factor
static const double kScale = 173.7178;

/// The system constant (tau)
static const double kSystemConst = 0.5;

/// The convergence constant (epsilon)
static const double kConvergence = 0.000001;
}

#endif
Loading