Skip to content

Commit 8449171

Browse files
committed
[#6]: Rank with TrueSkill
1 parent 88933f0 commit 8449171

File tree

6 files changed

+110
-21
lines changed

6 files changed

+110
-21
lines changed

commands/create.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ module.exports = async (argv) => {
6262
db.run(`CREATE TABLE rankings (
6363
rankingteamid INTEGER NOT NULL,
6464
elo INTEGER NOT NULL,
65+
trueskillmu INTEGER NOT NULL,
66+
trueskillsigma INTEGER NOT NULL,
6567
date INTEGER NOT NULL,
6668
FOREIGN KEY(rankingteamid) REFERENCES teams(teamid)
6769
);`).then(() => db.run(`CREATE UNIQUE INDEX idx_uniquerankings ON rankings(rankingteamid, date);`)),

commands/rank.js

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const db = require('sqlite');
22
const fs = require('fs-extra');
3+
const trueskill = require('trueskill');
34
const teams = require('../data/teams');
45
const results = require('../data/results');
56

@@ -13,11 +14,15 @@ module.exports = async (argv) => {
1314

1415
const startDate = new Date('December 11, 1973').getTime();
1516
const startElo = 1300;
16-
console.log(`seeding table with start elo ${startElo} on date ${startDate}`);
17+
const startTrueskillSigma = 25 / 3;
18+
const startTrueskillMu = 25;
19+
console.log(`seeding table with start elo ${startElo} and trueskill sigma: ${startTrueskillSigma} mu: ${startTrueskillMu} on date ${startDate}`);
1720
await Promise.all(teams.map(team => db.run(`
18-
INSERT INTO rankings (rankingteamid, elo, date) VALUES (
21+
INSERT INTO rankings (rankingteamid, elo, trueskillsigma, trueskillmu, date) VALUES (
1922
(SELECT teamid FROM teams WHERE teams.abbreviation = "${team.abbreviation}"),
2023
${startElo},
24+
${startTrueskillSigma},
25+
${startTrueskillMu},
2126
${startDate}
2227
)
2328
`)));
@@ -39,6 +44,8 @@ module.exports = async (argv) => {
3944
const awayranking = await db.get(`
4045
select
4146
rankings.elo,
47+
rankings.trueskillmu,
48+
rankings.trueskillsigma,
4249
rankings.date
4350
from rankings
4451
inner join (
@@ -55,6 +62,8 @@ module.exports = async (argv) => {
5562
const homeranking = await db.get(`
5663
select
5764
rankings.elo,
65+
rankings.trueskillmu,
66+
rankings.trueskillsigma,
5867
rankings.date
5968
from rankings
6069
inner join (
@@ -70,7 +79,7 @@ module.exports = async (argv) => {
7079
`);
7180
match.homeranking = homeranking.elo;
7281
match.awayranking = awayranking.elo;
73-
let homeElo, awayElo;
82+
let homeElo, awayElo, homeTrueskill, awayTrueskill;
7483
if (match.homegoals < match.awaygoals) {
7584
homeElo = updateElo({
7685
match,
@@ -82,6 +91,14 @@ module.exports = async (argv) => {
8291
won: true,
8392
isHome: false
8493
});
94+
homeTrueskill = {
95+
skill: [homeranking.trueskillmu, homeranking.trueskillsigma],
96+
rank: 2,
97+
};
98+
awayTrueskill = {
99+
skill: [awayranking.trueskillmu, awayranking.trueskillsigma],
100+
rank: 1,
101+
};
85102
} else if (match.homegoals === match.awaygoals) {
86103
homeElo = updateElo({
87104
match,
@@ -93,6 +110,14 @@ module.exports = async (argv) => {
93110
won: false,
94111
isHome: false
95112
});
113+
homeTrueskill = {
114+
skill: [homeranking.trueskillmu, homeranking.trueskillsigma],
115+
rank: 2,
116+
};
117+
awayTrueskill = {
118+
skill: [awayranking.trueskillmu, awayranking.trueskillsigma],
119+
rank: 2,
120+
};
96121
} else {
97122
homeElo = updateElo({
98123
match,
@@ -104,17 +129,30 @@ module.exports = async (argv) => {
104129
won: false,
105130
isHome: false
106131
});
132+
homeTrueskill = {
133+
skill: [homeranking.trueskillmu, homeranking.trueskillsigma],
134+
rank: 1,
135+
};
136+
awayTrueskill = {
137+
skill: [awayranking.trueskillmu, awayranking.trueskillsigma],
138+
rank: 2,
139+
};
107140
}
141+
trueskill.AdjustPlayers([homeTrueskill, awayTrueskill]);
108142
await Promise.all([db.run(`
109-
INSERT INTO rankings (elo, date, rankingteamid) VALUES (
143+
INSERT INTO rankings (elo, trueskillsigma, trueskillmu, date, rankingteamid) VALUES (
110144
${homeElo},
145+
${homeTrueskill.skill[1]},
146+
${homeTrueskill.skill[0]},
111147
${match.date},
112148
${match.hometeam}
113149
)
114150
`),
115151
db.run(`
116-
INSERT INTO rankings (elo, date, rankingteamid) VALUES (
152+
INSERT INTO rankings (elo, trueskillsigma, trueskillmu, date, rankingteamid) VALUES (
117153
${awayElo},
154+
${homeTrueskill.skill[1]},
155+
${homeTrueskill.skill[0]},
118156
${match.date},
119157
${match.awayteam}
120158
)

commands/standings.js

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const teams = require('../data/teams');
44
const results = require('../data/results');
55

66
module.exports = async (argv) => {
7-
const {dbPath, verbose} = argv;
7+
const {dbPath, verbose, elo, trueskill} = argv;
88
if (verbose) {
99
console.info(`using db in ${dbPath}`);
1010
}
@@ -17,21 +17,43 @@ module.exports = async (argv) => {
1717
`);
1818
const standingsDate = new Date(dateResult.date);
1919

20-
const standings = await db.all(`
21-
SELECT teamname, elo
22-
FROM rankings
23-
INNER JOIN teams on teams.teamid = rankings.rankingteamid
24-
WHERE date = (
25-
SELECT max(date)
20+
if (elo) {
21+
const eloStandings = await db.all(`
22+
SELECT teamname, elo
2623
FROM rankings
27-
WHERE rankings.rankingteamid = teams.teamid
28-
)
29-
AND teams.dissolved IS NULL
30-
ORDER BY elo DESC
31-
`);
24+
INNER JOIN teams on teams.teamid = rankings.rankingteamid
25+
WHERE date = (
26+
SELECT max(date)
27+
FROM rankings
28+
WHERE rankings.rankingteamid = teams.teamid
29+
)
30+
AND teams.dissolved IS NULL
31+
ORDER BY elo DESC
32+
`);
33+
34+
console.log(`ELO Standings as of ${standingsDate.toLocaleDateString()}\n`);
35+
eloStandings.forEach((standing, i) => {
36+
console.log(`${i + 1}.) ${standing.teamname} (${Math.round(standing.elo)})`);
37+
});
38+
}
3239

33-
console.log(`Standings as of ${standingsDate.toLocaleDateString()}\n`);
34-
standings.forEach((standing, i) => {
35-
console.log(`${i + 1}.) ${standing.teamname} (${Math.round(standing.elo)})`);
36-
});
40+
if (trueskill) {
41+
const trueskillStandings = await db.all(`
42+
SELECT teamname, trueskillmu
43+
FROM rankings
44+
INNER JOIN teams on teams.teamid = rankings.rankingteamid
45+
WHERE date = (
46+
SELECT max(date)
47+
FROM rankings
48+
WHERE rankings.rankingteamid = teams.teamid
49+
)
50+
AND teams.dissolved IS NULL
51+
ORDER BY trueskillmu DESC
52+
`);
53+
54+
console.log(`\n\nTrueSkill Standings as of ${standingsDate.toLocaleDateString()}\n`);
55+
trueskillStandings.forEach((standing, i) => {
56+
console.log(`${i + 1}.) ${standing.teamname} (${standing.trueskillmu})`);
57+
});
58+
}
3759
}

index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ const yargs = require('yargs') // eslint-disable-line
5050
describe: 'database to read team data from and write elo rankings to',
5151
default: '.cached/database.sqlite'
5252
})
53+
.option('elo', {
54+
describe: 'whether to show the elo rankings',
55+
default: true
56+
})
57+
.option('trueskill', {
58+
describe: 'whether to show the trueskill rankings',
59+
default: false
60+
})
5361
}, standingsCommand)
5462
.command('predict', 'predict a single match', (yargs) => {
5563
yargs.option('dbPath', {

package-lock.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"fs-extra": "^3.0.1",
99
"safe-get": "^1.0.6",
1010
"sqlite": "^2.8.0",
11+
"trueskill": "0.0.2",
1112
"untildify": "^3.0.2",
1213
"yargs": "^8.0.2"
1314
},

0 commit comments

Comments
 (0)