Initial rankings
Rankings after tournament 1
Rankings after tournament 2
Rankings after tournament 3
Codice utilizzato per generare la pagina:
<script type="text/javascript">
(function(exports){
var scalingFactor = 173.7178;
function Player(rating, rd , vol, tau){
this._tau = tau;
this.setRating(rating);
this.setRd(rd);
this.setVol(vol);
}
Player.prototype.getRating = function (){
return Math.round(this.__rating * scalingFactor) + this.defaultRating;
};
Player.prototype.setRating = function (rating){
this.__rating = (rating - this.defaultRating) / scalingFactor;
};
Player.prototype.getRd = function(){
return Math.round(100 * this.__rd * scalingFactor)/100;
};
Player.prototype.setRd = function(rd){
this.__rd = rd / scalingFactor;
};
Player.prototype.getVol = function(){
return this.__vol;
};
Player.prototype.setVol = function(vol){
this.__vol = vol;
};
Player.prototype.addResult = function(opponent, outcome){
this.adv_ranks.push(opponent.__rating);
this.adv_rds.push(opponent.__rd);
this.outcomes.push(outcome);
};
// Calculates the new rating and rating deviation of the player.
// Follows the steps of the algorithm described at http://www.glicko.net/glicko/glicko2.pdf
Player.prototype.update_rank = function(){
if (!this.hasPlayed()){
// Applies only the Step 6 of the algorithm
this._preRatingRD();
return;
}
//Step 1 : done by Player initialization
//Step 2 : done by setRating and setRd
//Step 3
var v = this._variance();
//Step 4
var delta = this._delta(v);
//Step 5
this.__vol = this.volatility_algorithm(v, delta);
//Step 6
this._preRatingRD();
//Step 7
this.__rd = 1 / Math.sqrt((1 / Math.pow(this.__rd, 2)) + (1 / v));
var tempSum = 0;
for (var i=0,len = this.adv_ranks.length;i< len;i++){
tempSum += this._g(this.adv_rds[i]) * (this.outcomes[i] - this._E(this.adv_ranks[i], this.adv_rds[i]));
}
this.__rating += Math.pow(this.__rd, 2) * tempSum;
//Step 8 : done by getRating and getRd
};
Player.prototype.hasPlayed = function(){
return this.outcomes.length > 0;
};
// Calculates and updates the player's rating deviation for the beginning of a rating period.
// preRatingRD() -> None
Player.prototype._preRatingRD = function(){
this.__rd = Math.sqrt(Math.pow(this.__rd, 2) + Math.pow(this.__vol, 2));
};
// Calculation of the estimated variance of the player's rating based on game outcomes
Player.prototype._variance = function (){
var tempSum = 0;
for (var i = 0, len = this.adv_ranks.length;i<len;i++){
var tempE = this._E(this.adv_ranks[i], this.adv_rds[i]);
tempSum += Math.pow(this._g(this.adv_rds[i]), 2) * tempE * (1 - tempE);
}
return 1 / tempSum;
};
// The Glicko E function.
Player.prototype._E = function (p2rating, p2RD){
return 1 / (1 + Math.exp(-1 * this._g(p2RD) * (this.__rating - p2rating)));
};
// The Glicko2 g(RD) function.
Player.prototype._g = function(RD){
return 1 / Math.sqrt(1 + 3 * Math.pow(RD, 2) / Math.pow(Math.PI, 2));
};
// The delta function of the Glicko2 system.
// Calculation of the estimated improvement in rating (step 4 of the algorithm)
Player.prototype._delta = function(v){
var tempSum = 0;
for (var i = 0, len = this.adv_ranks.length;i<len;i++){
tempSum += this._g(this.adv_rds[i]) * (this.outcomes[i] - this._E(this.adv_ranks[i], this.adv_rds[i]));
}
return v * tempSum;
};
Player.prototype._makef = function(delta, v, a){
var pl = this;
return function(x){
return Math.exp(x) * (Math.pow(delta, 2) - Math.pow(pl.__rd, 2) - v - Math.exp(x)) / (2*Math.pow(Math.pow(pl.__rd, 2) + v + Math.exp(x), 2)) - (x - a) / Math.pow(pl._tau, 2);
};
};
//========================= Glicko2 class =============================================
function Glicko2(settings){
default_settings = {
tau : 0.5, // Internal glicko2 parameter. "Reasonable choices are between 0.3 and 1.2, though the system should be tested to decide which value results in greatest predictive accuracy."
rating : 1500, //default rating
rd : 350, //Default rating deviation (small number = good confidence on the rating accuracy)
vol : 0.06, //Default volatility (expected fluctation on the player rating)
volatility_algorithm : 'newprocedure' //Default volatility calculation algorithm (step 5 of the global algorithm)
};
settings = settings || default_settings;
Player.prototype.defaultRating = settings.rating;
Player.prototype.volatility_algorithm = volatility_algorithms[settings.volatility_algorithm || default_settings.volatility_algorithm];
this._tau = settings.tau;
this._default_rating = settings.rating;
this._default_rd = settings.rd;
this._default_vol = settings.vol;
this.players = [];
this.players_index = 0;
}
Glicko2.prototype.removePlayers = function() {
this.players = [];
this.players_index = 0;
};
Glicko2.prototype.getPlayers = function(){
return this.players;
};
Glicko2.prototype.cleanPreviousMatches = function(){
for (var i = 0, len = this.players.length;i < len;i++){
this.players[i].adv_ranks = [];
this.players[i].adv_rds = [];
this.players[i].outcomes = [];
}
};
Glicko2.prototype.calculatePlayersRatings = function(){
var keys = Object.keys(this.players);
for (var i=0, len = keys.length;i<len;i++){
this.players[keys[i]].update_rank();
}
};
/**
* Add players and match result to be taken in account for the new rankings calculation
* players must have ids, they are not created if it has been done already.
* @param {Object litteral} pl1 The first player
* @param {Object litteral} pl2 The second player
* @param {number} outcom The outcome : 0 = defeat, 1 = victory, 0.5 = draw
*/
Glicko2.prototype.addMatch = function(player1, player2, outcome){
var pl1 = this._createInternalPlayer(player1.rating, player1.rd, player1.vol, player1.id);
var pl2 = this._createInternalPlayer(player2.rating, player2.rd, player2.vol, player2.id);
this.addResult(pl1, pl2, outcome);
return {pl1:pl1, pl2:pl2};
};
Glicko2.prototype.makePlayer = function (rating, rd , vol) {
//We do not expose directly createInternalPlayer in order to prevent the assignation of a custom player id whose uniqueness could not be guaranteed
return this._createInternalPlayer(rating, rd, vol);
};
Glicko2.prototype._createInternalPlayer = function (rating, rd , vol, id){
if (id === undefined){
id = this.players_index;
this.players_index = this.players_index + 1;
} else {
//We check if the player has already been created
var candidate = this.players[id];
if (candidate !== undefined){
return candidate;
}
}
var player = new Player(rating || this._default_rating, rd || this._default_rd, vol || this._default_vol, this._tau);
player.id = id;
player.adv_ranks = [];
player.adv_rds = [];
player.outcomes = [];
this.players[id] = player;
return player;
};
/**
* Add a match result to be taken in account for the new rankings calculation
* @param {Player} player1 The first player
* @param {Player} player2 The second player
* @param {number} outcome The outcome : 0 = defeat, 1 = victory, 0.5 = draw
*/
Glicko2.prototype.addResult = function(player1, player2, outcome){
player1.addResult(player2, outcome);
player2.addResult(player1, 1 - outcome);
};
Glicko2.prototype.updateRatings = function(matches){
if (typeof(matches) !== 'undefined'){
this.cleanPreviousMatches();
for (var i=0, len = matches.length;i<len;i++){
var match = matches[i];
this.addResult(match[0], match[1], match[2]);
}
}
this.calculatePlayersRatings();
};
//============== VOLATILITY ALGORITHMS (Step 5 of the global glicko2 algorithm)
var volatility_algorithms = {
oldprocedure: function(v, delta) {
var sigma = this.__vol;
var phi = this.__rd;
var tau = this._tau;
var a, x1, x2, x3, y1, y2, y3, upper;
var result;
upper = find_upper_falsep(phi, v, delta, tau);
a = Math.log(Math.pow(sigma, 2));
y1 = equation(phi, v, 0, a, tau, delta);
if (y1 > 0 ){
result = upper;
} else {
x1 = 0;
x2 = x1;
y2 = y1;
x1 = x1 - 1;
y1 = equation(phi, v, x1, a, tau, delta);
while (y1 < 0){
x2 = x1;
y2 = y1;
x1 = x1 - 1;
y1 = equation(phi, v, x1, a, tau, delta);
}
for (var i = 0; i<21; i++){
x3 = y1 * (x1 - x2) / (y2 - y1) + x1;
y3 = equation(phi, v, x3, a, tau, delta);
if (y3 > 0 ){
x1 = x3;
y1 = y3;
} else {
x2 = x3;
y2 = y3;
}
}
if (Math.exp((y1 * (x1 - x2) / (y2 - y1) + x1) / 2) > upper ){
result = upper;
} else {
result = Math.exp((y1 * (x1 - x2) / (y2 - y1) + x1) / 2);
}
}
return result;
//
function new_sigma(sigma , phi , v , delta , tau ) {
var a = Math.Math.log(Math.pow(sigma, 2));
var x = a;
var old_x = 0;
while (x != old_x){
old_x = x;
var d = Math.pow(phi, 2) + v + Math.exp(old_x);
var h1 = -(old_x - a) / Math.pow(tau, 2) - 0.5 * Math.exp(old_x) / d + 0.5 * Math.exp(old_x) * Math.pow((delta / d), 2);
var h2 = -1 / Math.pow(tau, 2) - 0.5 * Math.exp(old_x) * (Math.pow(phi, 2) + v) / Math.pow(d, 2) + 0.5 * Math.pow(delta, 2) * Math.exp(old_x) * (Math.pow(phi, 2) + v - Math.exp(old_x)) / Math.pow(d, 3);
x = old_x - h1 / h2;
}
return Math.exp(x / 2);
}
function equation(phi , v , x , a , tau , delta) {
var d = Math.pow(phi, 2) + v + Math.exp(x);
return -(x - a) / Math.pow(tau, 2) - 0.5 * Math.exp(x) / d + 0.5 * Math.exp(x) * Math.pow((delta / d), 2);
}
function new_sigma_bisection(sigma , phi , v , delta , tau ) {
var a, x1, x2, x3;
a = Math.Math.log(Math.pow(sigma, 2));
if (equation(phi, v, 0, a, tau, delta) < 0 ){
x1 = -1;
while (equation(phi, v, x1, a, tau, delta) < 0){
x1 = x1 - 1;
}
x2 = x1 + 1;
} else {
x2 = 1;
while (equation(phi, v, x2, a, tau, delta) > 0){
x2 = x2 + 1;
}
x1 = x2 - 1;
}
for (var i = 0; i < 27; i++) {
x3 = (x1 + x2) / 2;
if (equation(phi, v, x3, a, tau, delta) > 0 ){
x1 = x3;
} else {
x2 = x3;
}
}
return Math.exp((x1 + x2)/ 4);
}
function Dequation(phi , v , x , tau , delta) {
d = Math.pow(phi, 2) + v + Math.exp(x);
return -1 / Math.pow(tau, 2) - 0.5 * Math.exp(x) / d + 0.5 * Math.exp(x) * (Math.exp(x) + Math.pow(delta, 2)) / Math.pow(d, 2) - Math.pow(Math.exp(x), 2) * Math.pow(delta, 2) / Math.pow(d, 3);
}
function find_upper_falsep(phi , v , delta , tau) {
var x1, x2, x3, y1, y2, y3;
y1 = Dequation(phi, v, 0, tau, delta);
if (y1 < 0 ){
return 1;
} else {
x1 = 0;
x2 = x1;
y2 = y1;
x1 = x1 - 1;
y1 = Dequation(phi, v, x1, tau, delta);
while (y1 > 0){
x2 = x1;
y2 = y1;
x1 = x1 - 1;
y1 = Dequation(phi, v, x1, tau, delta);
}
for (var i = 0; i < 21 ; i++){
x3 = y1 * (x1 - x2) / (y2 - y1) + x1;
y3 = Dequation(phi, v, x3, tau, delta);
if (y3 > 0 ){
x1 = x3;
y1 = y3;
} else {
x2 = x3;
y2 = y3;
}
}
return Math.exp((y1 * (x1 - x2) / (y2 - y1) + x1) / 2);
}
}
},
newprocedure: function(v, delta){
//Step 5.1
var A = Math.log(Math.pow(this.__vol, 2));
var f = this._makef(delta, v, A);
var epsilon = 0.0000001;
//Step 5.2
var B, k;
if (Math.pow(delta, 2) > Math.pow(this.__rd, 2) + v){
B = Math.log(Math.pow(delta, 2) - Math.pow(this.__rd, 2) - v);
} else {
k = 1;
while (f(A - k * this._tau) < 0){
k = k + 1;
}
B = A - k * this._tau;
}
//Step 5.3
var fA = f(A);
var fB = f(B);
//Step 5.4
var C, fC;
while (Math.abs(B - A) > epsilon){
C = A + (A - B) * fA /(fB - fA );
fC = f(C);
if (fC * fB < 0){
A = B;
fA = fB;
} else {
fA = fA / 2;
}
B = C;
fB = fC;
}
//Step 5.5
return Math.exp(A/2);
},
newprocedure_mod: function(v, delta){
//Step 5.1
var A = Math.log(Math.pow(this.__vol, 2));
var f = this._makef(delta, v, A);
var epsilon = 0.0000001;
//Step 5.2
var B, k;
//XXX mod
if (delta > Math.pow(this.__rd, 2) + v){
//XXX mod
B = Math.log(delta - Math.pow(this.__rd, 2) - v);
} else {
k = 1;
while (f(A - k * this._tau) < 0){
k = k + 1;
}
B = A - k * this._tau;
}
//Step 5.3
var fA = f(A);
var fB = f(B);
//Step 5.4
var C, fC;
while (Math.abs(B - A) > epsilon){
C = A + (A - B) * fA /(fB - fA );
fC = f(C);
if (fC * fB < 0){
A = B;
fA = fB;
} else {
fA = fA / 2;
}
B = C;
fB = fC;
}
//Step 5.5
return Math.exp(A/2);
},
oldprocedure_simple: function(v, delta){
var i = 0;
var a = Math.log(Math.pow(this.__vol, 2));
var tau = this._tau;
var x0 = a;
var x1 = 0;
var d,h1,h2;
while (Math.abs(x0 - x1) > 0.00000001){
// New iteration, so x(i) becomes x(i-1)
x0 = x1;
d = Math.pow(this.__rating, 2) + v + Math.exp(x0);
h1 = -(x0 - a) / Math.pow(tau, 2) - 0.5 * Math.exp(x0) / d + 0.5 * Math.exp(x0) * Math.pow(delta / d, 2);
h2 = -1 / Math.pow(tau, 2) - 0.5 * Math.exp(x0) * (Math.pow(this.__rating, 2) + v) / Math.pow(d, 2) + 0.5 * Math.pow(delta, 2) * Math.exp(x0) * (Math.pow(this.__rating, 2) + v - Math.exp(x0)) / Math.pow(d, 3);
x1 = x0 - (h1 / h2);
}
return Math.exp(x1 / 2);
}
};
//==== End of volatility algorithms
exports.Glicko2 = Glicko2;
})(typeof exports === 'undefined'? this['glicko2']={}: exports);
</script>
<script type="text/javascript">
// -------------------------- Codice da modificare --------------------------
var settings = {
tau : 0.5,
rpd : 604800,
rating : 1500,
rd : 300,
vol : 0.06
};
var glicko = new glicko2.Glicko2(settings);
//Make players
Ryan = glicko.makePlayer(); //use default values
Mary = glicko.makePlayer(1700, 300, 0.06);
Bob = glicko.makePlayer(1400, 30, 0.06);
John = glicko.makePlayer(1550, 100, 0.06);
Gaspard = glicko.makePlayer();
Hector = glicko.makePlayer();
var players = [
{ name:'Ryan', glicko: Ryan },
{ name:'Mary', glicko: Mary },
{ name:'Bob', glicko: Bob },
{ name:'John', glicko: John },
{ name:'Gaspard', glicko: Gaspard },
{ name:'Hector', glicko: Hector }
];
function showRankings(){
//Sort players
players.sort(function(pl1, pl2){ return pl2.glicko.getRating() - pl1.glicko.getRating(); });
//Display ratings
for (var i=0,len= players.length;i<len;i++){
player = players[i];
document.write(player.name + ' : ' + player.glicko.getRating() + ' (rd : ' + player.glicko.getRd() + ')<br>');
}
}
</script>
<br />
<h2>Initial rankings</h2>
<script>showRankings();</script>
<br />
<h2>Rankings after tournament 1</h2>
<script>
var matches = [];
matches.push([Ryan, Bob, 1]); //Ryan won over Bob
matches.push([Ryan, John, 0]); //Ryan lost against John
matches.push([Ryan, Mary, 0]); //Ryan lost against Mary
glicko.updateRatings(matches);
showRankings();
</script>
<br />
<h2>Rankings after tournament 2</h2>
<script>
var matches = [];
matches.push([Ryan, Gaspard, 1]);
matches.push([Hector, Bob, 0]);
matches.push([John, Mary, 0]);
matches.push([John, Ryan, 0]);
matches.push([Gaspard, Mary, 0]);
matches.push([Mary, John, 0]);
glicko.updateRatings(matches);
showRankings();
</script>
<script>
//Aggiungi i giocatori
Toni = glicko.makePlayer();
Jane = glicko.makePlayer();
//Ricrei la lista dei giocatori con i nuovi giocatori aggiunti (metti sempre la , alla fine di ogni riga tranne l'ultima)
var players = [
{ name:'Ryan', glicko: Ryan },
{ name:'Mary', glicko: Mary },
{ name:'Bob', glicko: Bob },
{ name:'John', glicko: John },
{ name:'Gaspard', glicko: Gaspard },
{ name:'Hector', glicko: Hector },
{ name:'Toni', glicko: Toni },
{ name:'Jane', glicko: Jane }
];
//Ricrei la funzione per visualizzare la lista dei giocatori ordinati per ranking
function showRankings(){
//Sort players
players.sort(function(pl1, pl2){ return pl2.glicko.getRating() - pl1.glicko.getRating(); });
//Display ratings
for (var i=0,len= players.length;i<len;i++){
player = players[i];
document.write(player.name + ' : ' + player.glicko.getRating() + ' (rd : ' + player.glicko.getRd() + ')<br>');
}
}
</script>
<br />
<h2>Rankings after tournament 3</h2>
<script>
//Risultati partite del torneo 3
var matches = [];
matches.push([Ryan, Toni, 0]);
matches.push([Hector, Jane, 1]);
matches.push([John, Mary, 1]);
glicko.updateRatings(matches);
showRankings();
</script>
<br />
Nessun commento:
Posta un commento