Skip to content

Instantly share code, notes, and snippets.

@amkurian
Created February 13, 2020 12:26
Show Gist options
  • Save amkurian/131cecff256e8fae97240c3a17333dc7 to your computer and use it in GitHub Desktop.
Save amkurian/131cecff256e8fae97240c3a17333dc7 to your computer and use it in GitHub Desktop.

Computes the new ratings between two or more opponents using the Elo rating system. It takes an array of pre-ratings and returns an array containing post-ratings. The array should be ordered from best performer to worst performer (winner -> loser).

Use the exponent ** operator and math operators to compute the expected score (chance of winning). of each opponent and compute the new rating for each. Loop through the ratings, using each permutation to compute the post-Elo rating for each player in a pairwise fashion. Omit the second argument to use the default kFactor of 32.

const elo = ([...ratings], kFactor = 32, selfRating) => {
  const [a, b] = ratings;
  const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
  const newRating = (rating, i) =>
    (selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a));
  if (ratings.length === 2) return [newRating(a, 1), newRating(b, 0)];

  for (let i = 0, len = ratings.length; i < len; i++) {
    let j = i;
    while (j < len - 1) {
      j++;
      [ratings[i], ratings[j]] = elo([ratings[i], ratings[j]], kFactor);
    }
  }
  return ratings;
};
// Standard 1v1s
elo([1200, 1200]); // [1216, 1184]
elo([1200, 1200], 64); // [1232, 1168]
// 4 player FFA, all same rank
elo([1200, 1200, 1200, 1200]).map(Math.round); // [1246, 1215, 1185, 1154]
/*

For teams, each rating can adjusted based on own team's average rating vs. average rating of opposing team, with the score being added to their own individual rating by supplying it as the third argument. */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment