-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglicko.js
95 lines (89 loc) · 2.76 KB
/
glicko.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
const Q = Math.log(10)/400;
//helper function for new r- calculates g(RD)
function g(RD) {
return 1/Math.sqrt(1 + (3 * Q * Q * RD * RD / (Math.PI * Math.PI)))
}
//helper function for new r- calculates s term
//outcome is either 0(loss), .5(tie), 1(win)
function s(player, opponent){
return (1/(1 + Math.pow(10, -g(opponent.RD) * (player.R - opponent.R) / 400)));
}
//helper function for new r, calculates right half of term
function rightHalfOfNewR(player, opponents){
let result = 0;
for(let opponent of opponents) {
result += (g(opponent.RD) * (opponent.outcome - s(player, opponent)))
}
return result;
}
// helper function to calculate d term
function d(player, opponents) {
let result = 0;
for(let opponent of opponents) {
result += Math.pow(g(opponent.RD), 2) *s(player, opponent) * (1 - s(player, opponent))
}
result *= (Q * Q);
result = 1 / result;
return result
}
//function to calculate new rating based on old rating, RD, and the games played
function newR(player, opponents) {
return player.R + (Q / ((1 /(player.RD * player.RD)) + (1/d(player, opponents)))) * rightHalfOfNewR(player, opponents)
}
//function to calculate new RD based on old rating, RD, and the games played
function newRD(player, opponents) {
let result = 1 / (player.RD * player.RD) + (1 / d(player, opponents));
result = 1 /result;
return Math.sqrt(result);
}
// function to update rating, RD
function updateRating(player, opponents){
player.R = newR(player, opponents);
player.RD = newRD(player, opponents);
// to avoid scenarios where players can't improve due to low deviation
if (player.RD < 30){
player.RD = 30
}
}
//function to increase RD as time increments pass- if player is inactive, rating is less accurate
function RDincrease(player){
player.RD = Math.min(350, Math.sqrt((player.RD * player.RD) + 63.2 * 63.2))
}
//expected outcome of a game between two players
//0 = player never wins, 1 = player always wins
function expectedOutcome(player, opponent){
let result = -g(Math.sqrt((player.RD * player.RD) + (opponent.RD * opponent.RD))) * (player.R - opponent.R)/400;
result = Math.pow(10, result) + 1;
return 1 / result
}
//TESTING
let player = {
R: 1400,
RD: 80
};
let opp1 = {
R: 2400,
RD: 300,
outcome: 1
};
let opp2 = {
R: 1500,
RD: 150,
outcome: 0
};
let opp3 = {
R: 1700,
RD: 300,
outcome: 0
};
let opponents = [];
opponents.push(opp1);
opponents.push(opp2);
opponents.push(opp3);
console.log(player.R, player.RD);
console.log(expectedOutcome(player, opp2));
for(let x = 0; x < 50; x++) {
updateRating(player, opponents);
console.log(Math.round(player.R), (player.RD));
}
console.log(expectedOutcome(player, opp2));