forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Finisher.scala
70 lines (63 loc) · 2.61 KB
/
Finisher.scala
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
package lila.opening
import org.goochjs.glicko2._
import org.joda.time.DateTime
import lila.db.dsl._
import lila.rating.{ Glicko, Perf, PerfType }
import lila.user.{ User, UserRepo }
private[opening] final class Finisher(
api: OpeningApi,
openingColl: Coll) {
def apply(opening: Opening, user: User, win: Boolean): Fu[(Attempt, Option[Boolean])] = {
api.attempt.find(opening.id, user.id) flatMap {
case Some(a) => fuccess(a -> win.some)
case None =>
val userRating = user.perfs.opening.toRating
val openingRating = opening.perf.toRating
updateRatings(userRating, openingRating, win.fold(Glicko.Result.Win, Glicko.Result.Loss))
val date = DateTime.now
val userPerf = user.perfs.opening.addOrReset(_.opening.crazyGlicko, s"opening ${opening.id} user")(userRating, date)
val openingPerf = opening.perf.addOrReset(_.opening.crazyGlicko, s"opening ${opening.id}")(openingRating, date)
val a = new Attempt(
id = Attempt.makeId(opening.id, user.id),
openingId = opening.id,
userId = user.id,
date = DateTime.now,
win = win,
openingRating = opening.perf.intRating,
openingRatingDiff = openingPerf.intRating - opening.perf.intRating,
userRating = user.perfs.opening.intRating,
userRatingDiff = userPerf.intRating - user.perfs.opening.intRating)
((api.attempt add a) >> {
openingColl.update(
$id(opening.id),
$inc(
Opening.BSONFields.attempts -> $int(1),
Opening.BSONFields.wins -> $int(win ? 1 | 0)
) ++ $set(
Opening.BSONFields.perf -> Perf.perfBSONHandler.write(openingPerf)
)) zip UserRepo.setPerf(user.id, PerfType.Opening, userPerf)
}) recover lila.db.recoverDuplicateKey(_ => ()) inject (a -> none)
}
}
private val VOLATILITY = Glicko.default.volatility
private val TAU = 0.75d
private val system = new RatingCalculator(VOLATILITY, TAU)
private def mkRating(perf: Perf) = new Rating(
math.max(1000, perf.glicko.rating),
perf.glicko.deviation,
perf.glicko.volatility, perf.nb)
private def updateRatings(u1: Rating, u2: Rating, result: Glicko.Result) {
val results = new RatingPeriodResults()
result match {
case Glicko.Result.Draw => results.addDraw(u1, u2)
case Glicko.Result.Win => results.addResult(u1, u2)
case Glicko.Result.Loss => results.addResult(u2, u1)
}
try {
system.updateRatings(results)
}
catch {
case e: Exception => lila.log("opening").error("update ratings", e)
}
}
}