module Ratings.Glicko
( Glicko(..)
, initialGlicko
, HasGlicko(..)
, updateGlicko
) where
import Ratings.Types
data Glicko = Glicko
{ _glickoRating :: Rating
, _glickoRD :: RD
} deriving (Eq,Show,Read)
class HasGlicko a where
mkGlicko :: Rating -> RD -> a
glickoRating :: a -> Rating
glickoRD :: a -> RD
glickoC :: a -> Double
q :: Double
q = log 10 / 400
g :: RD -> RD
g (RD rd) = RD $ 1 / sqrt (1 + 3 * q*q * rd*rd / (pi*pi))
e :: HasGlicko glicko => Rating -> glicko -> Double
e (Rating me) them =
1 / (1 + 10 ** (negate $ _unRD (g $ glickoRD them) *
(me _unRating (glickoRating them)) / 400))
d2 :: HasGlicko glicko => Rating -> [glicko] -> Double
d2 me opps = 1 / (q*q * sum (map f opps))
where
f opp = (_unRD $ g $ glickoRD opp) ^ (2::Int) * e me opp * (1 e me opp)
initialGlicko :: Glicko
initialGlicko = Glicko 1500 350
updateGlicko
:: HasGlicko glicko
=> Int
-> [(glicko, Score)]
-> glicko
-> glicko
updateGlicko t opps me = mkGlicko r' rd'
where
r = glickoRating me
rd0 = _unRD $ glickoRD me
c = glickoC me
rd = min (_unRD $ _glickoRD initialGlicko)
(sqrt $ rd0*rd0 + c*c * fromIntegral t)
d2Inv = 1.0 / d2 (glickoRating me) (map fst opps)
rdInv = 1.0 / (rd*rd)
r' = Rating $ _unRating r + (q * foo / (rdInv + d2Inv))
rd' = RD $ sqrt $ 1 / (rdInv + d2Inv)
foo = sum $ map f opps
f (opp, Score s) = _unRD (g (glickoRD opp)) * (s e r opp)
testOpps :: [(Glicko, Score)]
testOpps =
[ (Glicko 1400 30, 1)
, (Glicko 1550 100, 0)
, (Glicko 1700 300, 0)
]