Skip to content

Commit

Permalink
refine glicko code
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Nov 20, 2024
1 parent f83ce36 commit 394df62
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 33 deletions.
6 changes: 3 additions & 3 deletions rating/src/main/scala/glicko/GlickoCalculator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import scala.util.Try

/* Purely functional interface hiding the mutable implementation */
final class GlickoCalculator(
tau: impl.Tau = impl.Tau.default,
ratingPeriodsPerDay: impl.RatingPeriodsPerDay = impl.RatingPeriodsPerDay.default
tau: Tau = Tau.default,
ratingPeriodsPerDay: RatingPeriodsPerDay = RatingPeriodsPerDay.default
):

private val calculator = impl.RatingCalculator(tau, ratingPeriodsPerDay)
private val calculator = new impl.RatingCalculator(tau, ratingPeriodsPerDay)

// Simpler use case: a single game
def computeGame(game: Game, skipDeviationIncrease: Boolean = false): Try[ByColor[Player]] =
Expand Down
5 changes: 3 additions & 2 deletions rating/src/main/scala/glicko/impl/Rating.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package chess.rating.glicko.impl
package chess.rating.glicko
package impl

final class Rating(
final private[glicko] class Rating(
var rating: Double,
var ratingDeviation: Double,
var volatility: Double,
Expand Down
19 changes: 5 additions & 14 deletions rating/src/main/scala/glicko/impl/RatingCalculator.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
package chess.rating.glicko.impl

import scalalib.extensions.ifTrue
import scalalib.newtypes.OpaqueDouble
package chess.rating.glicko
package impl

import java.time.Instant
import scalalib.extensions.ifTrue

opaque type Tau = Double
object Tau extends OpaqueDouble[Tau]:
val default: Tau = 0.75d

opaque type RatingPeriodsPerDay = Double
object RatingPeriodsPerDay extends OpaqueDouble[RatingPeriodsPerDay]:
val default: RatingPeriodsPerDay = 0d

object RatingCalculator:
private object RatingCalculator:

private val MULTIPLIER: Double = 173.7178
val DEFAULT_RATING: Double = 1500.0
Expand All @@ -30,7 +21,7 @@ object RatingCalculator:
def convertRatingDeviationToGlicko2Scale(ratingDeviation: Double): Double =
(ratingDeviation / MULTIPLIER)

final class RatingCalculator(
final private[glicko] class RatingCalculator(
tau: Tau = Tau.default,
ratingPeriodsPerDay: RatingPeriodsPerDay = RatingPeriodsPerDay.default
):
Expand Down
16 changes: 9 additions & 7 deletions rating/src/main/scala/glicko/impl/results.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package chess.rating.glicko.impl
package chess.rating.glicko
package impl

trait Result:
private[glicko] trait Result:

def getScore(player: Rating): Double

Expand All @@ -11,7 +12,7 @@ trait Result:
def players: List[Rating]

// score from 0 (opponent wins) to 1 (player wins)
class FloatingResult(player: Rating, opponent: Rating, score: Float) extends Result:
final private[glicko] class FloatingResult(player: Rating, opponent: Rating, score: Float) extends Result:

def getScore(p: Rating) = if p == player then score else 1 - score

Expand All @@ -21,7 +22,7 @@ class FloatingResult(player: Rating, opponent: Rating, score: Float) extends Res

def players = List(player, opponent)

final class GameResult(winner: Rating, loser: Rating, isDraw: Boolean) extends Result:
final private[glicko] class GameResult(winner: Rating, loser: Rating, isDraw: Boolean) extends Result:
private val POINTS_FOR_WIN = 1.0d
private val POINTS_FOR_LOSS = 0.0d
private val POINTS_FOR_DRAW = 0.5d
Expand Down Expand Up @@ -50,12 +51,13 @@ final class GameResult(winner: Rating, loser: Rating, isDraw: Boolean) extends R

override def toString = s"$winner vs $loser = $isDraw"

trait RatingPeriodResults[R <: Result]():
private[glicko] trait RatingPeriodResults[R <: Result]():
val results: List[R]
def getResults(player: Rating): List[R] = results.filter(_.participated(player))
def getParticipants: Set[Rating] = results.flatMap(_.players).toSet

class GameRatingPeriodResults(val results: List[GameResult]) extends RatingPeriodResults[GameResult]
final private[glicko] class GameRatingPeriodResults(val results: List[GameResult])
extends RatingPeriodResults[GameResult]

class FloatingRatingPeriodResults(val results: List[FloatingResult])
final private[glicko] class FloatingRatingPeriodResults(val results: List[FloatingResult])
extends RatingPeriodResults[FloatingResult]
18 changes: 13 additions & 5 deletions rating/src/main/scala/glicko/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package glicko

import chess.{ IntRating, ByColor, Outcome }
import java.time.Instant
import scalalib.newtypes.OpaqueDouble

case class Glicko(
rating: Double,
Expand All @@ -11,10 +12,10 @@ case class Glicko(
):
def intRating: IntRating = IntRating(rating.toInt)
def intDeviation = deviation.toInt
def provisional = RatingProvisional(deviation >= Glicko.provisionalDeviation)
def provisional = RatingProvisional(deviation >= provisionalDeviation)
def established = provisional.no
def establishedIntRating = Option.when(established)(intRating)
def clueless = deviation >= Glicko.cluelessDeviation
def clueless = deviation >= cluelessDeviation
def display = s"$intRating${if provisional.yes then "?" else ""}"
def average(other: Glicko, weight: Float = 0.5f): Glicko =
if weight >= 1 then other
Expand All @@ -27,9 +28,8 @@ case class Glicko(
)
override def toString = f"$intRating/$intDeviation/${volatility}%.3f"

object Glicko:
val provisionalDeviation = 110
val cluelessDeviation = 230
val provisionalDeviation = 110
val cluelessDeviation = 230

case class Player(
glicko: Glicko,
Expand All @@ -39,3 +39,11 @@ case class Player(
export glicko.*

case class Game(players: ByColor[Player], outcome: Outcome)

opaque type Tau = Double
object Tau extends OpaqueDouble[Tau]:
val default: Tau = 0.75d

opaque type RatingPeriodsPerDay = Double
object RatingPeriodsPerDay extends OpaqueDouble[RatingPeriodsPerDay]:
val default: RatingPeriodsPerDay = 0d
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import chess.{ ByColor, Outcome }
class GlickoCalculatorTest extends ScalaCheckSuite with chess.MunitExtensions:

val calc = GlickoCalculator(
ratingPeriodsPerDay = impl.RatingPeriodsPerDay(0.21436d)
ratingPeriodsPerDay = RatingPeriodsPerDay(0.21436d)
)

def computeGame(players: ByColor[Player], outcome: Outcome) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package chess.rating.glicko.impl
package chess.rating.glicko
package impl

import munit.ScalaCheckSuite
import cats.syntax.all.*
Expand Down

0 comments on commit 394df62

Please sign in to comment.