forked from External/mage
Add user rating using Glicko rating system (#1498)
This commit is contained in:
parent
11158d5fa4
commit
972d59aa37
10 changed files with 701 additions and 9 deletions
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.server.rating;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Quercitron
|
||||
*/
|
||||
public class GlickoRatingSystem {
|
||||
|
||||
// rating deviation will grow back from 50 to max 350 in 2 years
|
||||
public static final double C = 0.00137934314767061324980397708525;
|
||||
|
||||
public static final double BaseRating = 1500;
|
||||
public static final double BaseRD = 350;
|
||||
public static final double MinRD = 30;
|
||||
|
||||
private static final double Q = Math.log(10) / 400;
|
||||
|
||||
public static GlickoRating getInitialRating() {
|
||||
return new GlickoRating(GlickoRatingSystem.BaseRating, GlickoRatingSystem.BaseRD, 0);
|
||||
}
|
||||
|
||||
public static int getDisplayedRating(GlickoRating rating) {
|
||||
long currentTime = new Date().getTime();
|
||||
double updatedRatingDeviation = getUpdatedRD(rating, currentTime);
|
||||
return (int) Math.max(rating.getRating() - 2 * updatedRatingDeviation, 0);
|
||||
}
|
||||
|
||||
public static int getDefaultDisplayedRating() {
|
||||
return getDisplayedRating(getInitialRating());
|
||||
}
|
||||
|
||||
public void updateRating(GlickoRating playerRating, GlickoRating opponentRating, double outcome, long gameTimeMs) {
|
||||
playerRating.setRatingDeviation(getUpdatedRD(playerRating, gameTimeMs));
|
||||
opponentRating.setRatingDeviation(getUpdatedRD(opponentRating, gameTimeMs));
|
||||
|
||||
GlickoRating newPlayerRating = getNewRating(playerRating, opponentRating, outcome);
|
||||
GlickoRating newOpponentRating = getNewRating(opponentRating, playerRating, 1 - outcome);
|
||||
|
||||
playerRating.setRating(newPlayerRating.getRating());
|
||||
playerRating.setRatingDeviation(newPlayerRating.getRatingDeviation());
|
||||
playerRating.setLastGameTimeMs(gameTimeMs);
|
||||
|
||||
opponentRating.setRating(newOpponentRating.getRating());
|
||||
opponentRating.setRatingDeviation(newOpponentRating.getRatingDeviation());
|
||||
opponentRating.setLastGameTimeMs(gameTimeMs);
|
||||
}
|
||||
|
||||
private static double getUpdatedRD(GlickoRating rating, long gameTimeMs) {
|
||||
double newRatingDeviation;
|
||||
if (rating.getLastGameTimeMs() != 0)
|
||||
{
|
||||
double newRD = Math.sqrt(
|
||||
rating.getRatingDeviation() * rating.getRatingDeviation()
|
||||
+ C * C * Math.max(gameTimeMs - rating.getLastGameTimeMs(), 0));
|
||||
newRatingDeviation = Math.max(Math.min(BaseRD, newRD), MinRD);
|
||||
}
|
||||
else
|
||||
{
|
||||
newRatingDeviation = BaseRD;
|
||||
}
|
||||
return newRatingDeviation;
|
||||
}
|
||||
|
||||
private GlickoRating getNewRating(GlickoRating playerRating, GlickoRating opponentRating, double outcome) {
|
||||
double RD = playerRating.getRatingDeviation();
|
||||
|
||||
double g = gFunc(opponentRating.getRatingDeviation());
|
||||
double p = -g * (playerRating.getRating() - opponentRating.getRating()) / 400;
|
||||
double e = 1 / (1 + Math.pow(10, p));
|
||||
double d2 = 1 / (Q * Q * g * g * e * (1 - e));
|
||||
|
||||
// todo: set minimum K?
|
||||
double newRating = playerRating.getRating() + Q / (1 / RD / RD + 1 / d2) * g * (outcome - e);
|
||||
double newRD = Math.sqrt(1 / (1 / RD / RD + 1 / d2));
|
||||
|
||||
return new GlickoRating(newRating, newRD);
|
||||
}
|
||||
|
||||
private double gFunc(double rd) {
|
||||
return 1 / Math.sqrt(1 + 3 * Q * Q * rd * rd / Math.PI / Math.PI);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue