From 0a351973bb88728e208306fd4112fba16451205f Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Fri, 20 Apr 2018 00:00:45 +0200 Subject: [PATCH] halve human rating diff in a match against a bot --- modules/rating/src/main/Glicko.scala | 6 +++ modules/rating/src/main/Perf.scala | 4 ++ modules/round/src/main/PerfsUpdater.scala | 60 +++++++++++++---------- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/modules/rating/src/main/Glicko.scala b/modules/rating/src/main/Glicko.scala index 8a789f179a..7a44960094 100644 --- a/modules/rating/src/main/Glicko.scala +++ b/modules/rating/src/main/Glicko.scala @@ -38,6 +38,12 @@ case class Glicko( volatility = volatility atMost Glicko.maxVolatility ) + def average(other: Glicko) = Glicko( + rating = (rating + other.rating) / 2, + deviation = (deviation + other.deviation) / 2, + volatility = (volatility + other.volatility) / 2 + ) + override def toString = s"$intRating $intDeviation" } diff --git a/modules/rating/src/main/Perf.scala b/modules/rating/src/main/Perf.scala index 20f808046a..16e0b5a554 100644 --- a/modules/rating/src/main/Perf.scala +++ b/modules/rating/src/main/Perf.scala @@ -38,6 +38,10 @@ case class Perf( add(Glicko.default, date) } + def averageGlicko(other: Perf) = copy( + glicko = glicko average other.glicko + ) + def refund(points: Int): Perf = { val newGlicko = glicko refund points copy( diff --git a/modules/round/src/main/PerfsUpdater.scala b/modules/round/src/main/PerfsUpdater.scala index 19bbb525bb..5439e77af2 100644 --- a/modules/round/src/main/PerfsUpdater.scala +++ b/modules/round/src/main/PerfsUpdater.scala @@ -57,8 +57,8 @@ final class PerfsUpdater( } case _ => } - val perfsW = mkPerfs(ratingsW, white.perfs, game) - val perfsB = mkPerfs(ratingsB, black.perfs, game) + val perfsW = mkPerfs(ratingsW, white -> black, game) + val perfsB = mkPerfs(ratingsB, black -> white, game) def intRatingLens(perfs: Perfs) = mainPerf(perfs).glicko.intRating val ratingDiffs = Color.Map( intRatingLens(perfsW) - intRatingLens(white.perfs), @@ -124,33 +124,41 @@ final class PerfsUpdater( } try { system.updateRatings(results) - } catch { + } + catch { case e: Exception => logger.error("update ratings", e) } } - private def mkPerfs(ratings: Ratings, perfs: Perfs, game: Game): Perfs = { - val speed = game.speed - val isStd = game.ratingVariant.standard - def addRatingIf(cond: Boolean, perf: Perf, rating: Rating) = - if (cond) perf.addOrReset(_.round.error.glicko, s"game ${game.id}")(rating, game.movedAt) - else perf - val perfs1 = perfs.copy( - chess960 = addRatingIf(game.ratingVariant.chess960, perfs.chess960, ratings.chess960), - kingOfTheHill = addRatingIf(game.ratingVariant.kingOfTheHill, perfs.kingOfTheHill, ratings.kingOfTheHill), - threeCheck = addRatingIf(game.ratingVariant.threeCheck, perfs.threeCheck, ratings.threeCheck), - antichess = addRatingIf(game.ratingVariant.antichess, perfs.antichess, ratings.antichess), - atomic = addRatingIf(game.ratingVariant.atomic, perfs.atomic, ratings.atomic), - horde = addRatingIf(game.ratingVariant.horde, perfs.horde, ratings.horde), - racingKings = addRatingIf(game.ratingVariant.racingKings, perfs.racingKings, ratings.racingKings), - crazyhouse = addRatingIf(game.ratingVariant.crazyhouse, perfs.crazyhouse, ratings.crazyhouse), - ultraBullet = addRatingIf(isStd && speed == Speed.UltraBullet, perfs.ultraBullet, ratings.ultraBullet), - bullet = addRatingIf(isStd && speed == Speed.Bullet, perfs.bullet, ratings.bullet), - blitz = addRatingIf(isStd && speed == Speed.Blitz, perfs.blitz, ratings.blitz), - rapid = addRatingIf(isStd && speed == Speed.Rapid, perfs.rapid, ratings.rapid), - classical = addRatingIf(isStd && speed == Speed.Classical, perfs.classical, ratings.classical), - correspondence = addRatingIf(isStd && speed == Speed.Correspondence, perfs.correspondence, ratings.correspondence) - ) - if (isStd) perfs1.updateStandard else perfs1 + private def mkPerfs(ratings: Ratings, users: (User, User), game: Game): Perfs = users match { + case (player, opponent) => + val perfs = player.perfs + val speed = game.speed + val isStd = game.ratingVariant.standard + val isHumanVsMachine = player.noBot && opponent.isBot + def addRatingIf(cond: Boolean, perf: Perf, rating: Rating) = + if (cond) { + val p = perf.addOrReset(_.round.error.glicko, s"game ${game.id}")(rating, game.movedAt) + if (isHumanVsMachine) perf averageGlicko p // halve rating diffs for human + else p + } + else perf + val perfs1 = perfs.copy( + chess960 = addRatingIf(game.ratingVariant.chess960, perfs.chess960, ratings.chess960), + kingOfTheHill = addRatingIf(game.ratingVariant.kingOfTheHill, perfs.kingOfTheHill, ratings.kingOfTheHill), + threeCheck = addRatingIf(game.ratingVariant.threeCheck, perfs.threeCheck, ratings.threeCheck), + antichess = addRatingIf(game.ratingVariant.antichess, perfs.antichess, ratings.antichess), + atomic = addRatingIf(game.ratingVariant.atomic, perfs.atomic, ratings.atomic), + horde = addRatingIf(game.ratingVariant.horde, perfs.horde, ratings.horde), + racingKings = addRatingIf(game.ratingVariant.racingKings, perfs.racingKings, ratings.racingKings), + crazyhouse = addRatingIf(game.ratingVariant.crazyhouse, perfs.crazyhouse, ratings.crazyhouse), + ultraBullet = addRatingIf(isStd && speed == Speed.UltraBullet, perfs.ultraBullet, ratings.ultraBullet), + bullet = addRatingIf(isStd && speed == Speed.Bullet, perfs.bullet, ratings.bullet), + blitz = addRatingIf(isStd && speed == Speed.Blitz, perfs.blitz, ratings.blitz), + rapid = addRatingIf(isStd && speed == Speed.Rapid, perfs.rapid, ratings.rapid), + classical = addRatingIf(isStd && speed == Speed.Classical, perfs.classical, ratings.classical), + correspondence = addRatingIf(isStd && speed == Speed.Correspondence, perfs.correspondence, ratings.correspondence) + ) + if (isStd) perfs1.updateStandard else perfs1 } }