home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / enxle1f6 / src / games / rating / rating.java
Encoding:
Java Source  |  1996-08-14  |  5.4 KB  |  182 lines

  1. /* 
  2.  * @(#)Rating.java 1.01
  3.  */
  4.  
  5. package games.Rating;
  6.  
  7. import java.util.*;
  8.  
  9. /** 
  10.  * The Rating class implements the Glicko Rating System, devised by Mark
  11.  * Glickman to replace the Elo system that is currently used to rate chess
  12.  * matches. 
  13.  * <P>
  14.  * The advantage of this system is that there is no ad-hoc "wild period" of
  15.  * some number of games that it takes the player to become established. In
  16.  * the Elo system this method is used to account for the need to quickly
  17.  * get the players rating into the right ballpark, by allowing huge swings
  18.  * before using the normal updating algorithm. Instead, the Glickman system
  19.  * uses a Rating and a Rating Deviation, which may be thought of as similar
  20.  * to a mean and a standard deviation in a normal distribution. Initially
  21.  * the Rating is in the centre of the 0-3000 range, and the deviation is
  22.  * quite high (350); as the player plays more and more games the rating and
  23.  * the deviation settle down. Once the deviation is small the player is 
  24.  * assured of having a reasonably accurate estimate of their strength in
  25.  * the game.
  26.  * <P>
  27.  * Ratings adjustments are always based on a win-loss system. To simulate
  28.  * a draw, it is necessary to adjust the ratings as though there was one
  29.  * win and one loss, which is not currently supported by this code.
  30.  * <P>
  31.  * For details of how the rating system works, see 
  32.  * <a href="http://math.bu.edu/INDIVIDUAL/mg/">
  33.  * Mark Glickman's home page
  34.  * </a>.
  35.  *
  36.  * @version 1.01
  37.  * @author Alex Nicolaou
  38.  * @author Jay Steele
  39.  */
  40.  
  41. public class Rating {
  42.     /**
  43.      * The numerical value for the rating ranges from 0-3000. By default
  44.      * the rating is in the middle of the range since it is unknown.
  45.      */
  46.     double rating = 1500;
  47.  
  48.     /**
  49.      * The numerical value for the rating deviation starts at 350. As the
  50.      * player plays more and more games, the RD will steadily fall.
  51.      */
  52.     double RD = 350;
  53.  
  54.     /**
  55.      * Constructs a default rating for an unknown player.
  56.      */
  57.     public Rating() {
  58.     }
  59.  
  60.     /**
  61.      * Constructs a particular rating for a known player.
  62.      */
  63.     public Rating(int mu, int sigma) {
  64.         rating = mu;
  65.         RD = sigma;
  66.     }
  67.  
  68.     /**
  69.      * Constructs a particular rating for a known player, from the string
  70.      * representation of the rating, for example, "1500/350". Assumes that
  71.      * the string representation records the rating with integers.
  72.      */
  73.     public Rating(String stringRep) {
  74.         StringTokenizer data = new StringTokenizer(stringRep, "/", false); 
  75.         String ratingStr = data.nextToken();
  76.         String ratingRD = data.nextToken();
  77.  
  78.         rating = Integer.valueOf(ratingStr).intValue();
  79.         RD = Integer.valueOf(ratingRD).intValue();
  80.     }
  81.  
  82.     /**
  83.      * Returns this rating in double precision.
  84.      */
  85.     public double getRating() {
  86.         return rating;
  87.     }
  88.  
  89.     /**
  90.      * Returns this rating's deviation in double precision.
  91.      */
  92.     public double getRatingDeviation() {
  93.         return RD;
  94.     }
  95.  
  96.     /**
  97.      * g is a function on the deviation used in the ratings calculation
  98.      * process. 
  99.      */
  100.     static double g(double sigma) {
  101.         double ln10 = Math.log(10);
  102.         double q = ln10 / 400.0;
  103.         return 1.0 / Math.sqrt(1.0 + 3.0*q*q*sigma*sigma/(Math.PI*Math.PI));
  104.     }
  105.  
  106.     /**
  107.      * E is a function which calculates a value akin to the probability of
  108.      * a particular player winning.
  109.      */
  110.     static double E(double theta, double mu, double sigma) {
  111.         double power =  g(sigma)*(mu - theta) / 400.0;
  112.         double den = 1.0 + Math.pow(10.0, power);
  113.         return 1.0 / den;
  114.     }
  115.  
  116.     /**
  117.      * Adjust ratings to reflect the result of a match or a tournament. The
  118.      * input is an array of ratings, where the 0th entry is the winner of
  119.      * the game, the 1st player is in second place, and so on. All ratings
  120.      * are adjusted simultaneously to reflect the oucome of the game, so this
  121.      * is suitable for evaluating the result of a multiplayer game where all
  122.      * players competed simultaneously, or to adjust after a tournament.
  123.      *
  124.      * @param player the array of players to be adjusted.
  125.      */
  126.     static public void calculateRatings(Rating[] player) {
  127.         double ln10 = Math.log(10);
  128.         double q = ln10 / 400.0;
  129.  
  130.         double[] newRating = new double[player.length];
  131.         double[] newRD = new double[player.length];
  132.         double[] winVector = new double[player.length];
  133.  
  134.         for (int p = 0; p < player.length; p++) {
  135.             for (int loss = 0; loss < p; loss++)
  136.                 winVector[loss] = 0.0;
  137.             for (int win = p; win < player.length; win++) 
  138.                 winVector[win] = 1.0;
  139.  
  140.             double deltaSquared = 0;
  141.             double hExpected = 0;
  142.             for (int i = 0; i < player.length; i++) {
  143.                 if (i == p)
  144.                     continue;
  145.  
  146.                 double gi = g(player[i].RD);
  147.                 double Ei = E(player[p].rating, player[i].rating, player[i].RD);
  148.                 hExpected += gi*Ei;
  149.                 deltaSquared += gi*gi * Ei * (1.0 - Ei);
  150.             }
  151.             deltaSquared *= q*q;
  152.  
  153.             newRD[p] = 1.0 / 
  154.                     Math.sqrt(1.0 / (player[p].RD*player[p].RD) + deltaSquared);
  155.  
  156.             double hActual = 0;
  157.             for (int i = 0; i < player.length; i++) {
  158.                 if (i == p)
  159.                     continue;
  160.  
  161.                 hActual += g(player[i].RD) * winVector[i];
  162.             }
  163.  
  164.             double den = deltaSquared + 1.0 / (player[p].RD*player[p].RD);
  165.             newRating[p] = player[p].rating + q*(hActual - hExpected)/den;
  166.         }
  167.  
  168.         for (int p = 0; p < player.length; p++) {
  169.             player[p].rating = newRating[p];
  170.             player[p].RD = newRD[p];
  171.         }
  172.     }
  173.  
  174.     /**
  175.      * Convert the rating to an integer representation embedded in a string,
  176.      * for exmaple, 1500/350.
  177.      */
  178.     public String toString() {
  179.         return ((int)rating) + "/" + ((int)RD);
  180.     }
  181. }
  182.