Skip to content

Commit

Permalink
Merge pull request #595 from aarew12/fide-table-rating-performance
Browse files Browse the repository at this point in the history
use FIDE table for rating performance calculation
  • Loading branch information
ornicar authored Nov 11, 2024
2 parents feb9edc + 7ed4bd8 commit 166b4a1
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 12 deletions.
116 changes: 108 additions & 8 deletions core/src/main/scala/Elo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,10 @@ object Elo extends RelaxedOpaqueInt[Elo]:
if ratingDiff <= 0 then expectedScore else 1.0f - expectedScore

def computePerformanceRating(games: Seq[Game]): Option[Elo] =
val winBonus = 400
games.nonEmpty.option:
val ratings = games.map(_.opponentRating).sum
val points = games.foldMap:
_.points.match
case Outcome.Points.Zero => -1
case Outcome.Points.Half => 0
case Outcome.Points.One => 1
(ratings + points * winBonus) / games.size
val averageOpponentRating = games.map(_.opponentRating).sum / games.size
val percentageScore = Math.round(games.map(_.points.value).sum * 100 / games.size)
averageOpponentRating + performanceRatingTableFIDE.getOrElse(percentageScore, 0)

final class Player(val rating: Elo, val kFactor: KFactor)

Expand Down Expand Up @@ -105,3 +100,108 @@ object Elo extends RelaxedOpaqueInt[Elo]:
// the hardcoded List above is not really necessary,
// but it mirrors the reference table on
// https://handbook.fide.com/chapter/B022022 8.1.2

// 1.4.9 FIDE table
val performanceRatingTableFIDE: Map[Int, Int] = Map(
0 -> -800,
1 -> -677,
2 -> -589,
3 -> -538,
4 -> -501,
5 -> -470,
6 -> -444,
7 -> -422,
8 -> -401,
9 -> -383,
10 -> -366,
11 -> -351,
12 -> -336,
13 -> -322,
14 -> -309,
15 -> -296,
16 -> -284,
17 -> -273,
18 -> -262,
19 -> -251,
20 -> -240,
21 -> -230,
22 -> -220,
23 -> -211,
24 -> -202,
25 -> -193,
26 -> -184,
27 -> -175,
28 -> -166,
29 -> -158,
30 -> -149,
31 -> -141,
32 -> -133,
33 -> -125,
34 -> -117,
35 -> -110,
36 -> -102,
37 -> -95,
38 -> -87,
39 -> -80,
40 -> -72,
41 -> -65,
42 -> -57,
43 -> -50,
44 -> -43,
45 -> -36,
46 -> -29,
47 -> -21,
48 -> -14,
49 -> -7,
50 -> 0,
51 -> 7,
52 -> 14,
53 -> 21,
54 -> 29,
55 -> 36,
56 -> 43,
57 -> 50,
58 -> 57,
59 -> 65,
60 -> 72,
61 -> 80,
62 -> 87,
63 -> 95,
64 -> 102,
65 -> 110,
66 -> 117,
67 -> 125,
68 -> 133,
69 -> 141,
70 -> 149,
71 -> 158,
72 -> 166,
73 -> 175,
74 -> 184,
75 -> 193,
76 -> 202,
77 -> 211,
78 -> 220,
79 -> 230,
80 -> 240,
81 -> 251,
82 -> 262,
83 -> 273,
84 -> 284,
85 -> 296,
86 -> 309,
87 -> 322,
88 -> 336,
89 -> 351,
90 -> 366,
91 -> 383,
92 -> 401,
93 -> 422,
94 -> 444,
95 -> 470,
96 -> 501,
97 -> 538,
98 -> 589,
99 -> 677,
100 -> 800
)
10 changes: 6 additions & 4 deletions test-kit/src/test/scala/EloTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ class EloTest extends ChessTest:
def loss(r: Int) = Elo.Game(Zero, Elo(r))
def draw(r: Int) = Elo.Game(Half, Elo(r))
assertEquals(Elo.computePerformanceRating(Nil), None)
perfRating(List(win(1500)), 1900)
perfRating(List(win(1500), win(1500)), 1900)
perfRating(List(loss(1500)), 1100)
perfRating(List(win(1500)), 2300)
perfRating(List(win(1500), win(1500)), 2300)
perfRating(List(loss(1500)), 700)
perfRating(List(draw(1500)), 1500)
perfRating(List(draw(1500), draw(1500)), 1500)
perfRating(List(win(1500), loss(1500)), 1500)
perfRating(List(win(1500), draw(1500)), 1700)
perfRating(List(win(1500), loss(1700)), 1600)
perfRating(List(win(1500), draw(1500)), 1693)
perfRating(List(win(1500), draw(1500), draw(1500)), 1625)

0 comments on commit 166b4a1

Please sign in to comment.