forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Assessible.scala
105 lines (87 loc) · 4.02 KB
/
Assessible.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package lila.evaluation
import chess.{ Color, Speed }
import lila.analyse.{ Accuracy, Analysis }
import lila.game.{ Game, Pov }
import Math.signum
import org.joda.time.DateTime
case class Analysed(game: Game, analysis: Analysis)
case class Assessible(analysed: Analysed) {
import Statistics._
import analysed._
def suspiciousErrorRate(color: Color): Boolean =
listAverage(Accuracy.diffsList(Pov(game, color), analysis)) < (game.speed match {
case Speed.Bullet => 25
case Speed.Blitz => 20
case _ => 15
})
def alwaysHasAdvantage(color: Color): Boolean =
!analysis.infos.exists { info =>
info.score.fold(info.mate.fold(false) { a => (signum(a).toInt == color.fold(-1, 1)) }) { cp =>
color.fold(cp.centipawns < -100, cp.centipawns > 100)
}
}
def highBlurRate(color: Color): Boolean =
!game.isSimul && game.playerBlurPercent(color) > 90
def moderateBlurRate(color: Color): Boolean =
!game.isSimul && game.playerBlurPercent(color) > 70
def suspiciousHoldAlert(color: Color): Boolean =
game.player(color).hasSuspiciousHoldAlert
def mkFlags(color: Color): PlayerFlags = PlayerFlags(
suspiciousErrorRate(color),
alwaysHasAdvantage(color),
highBlurRate(color),
moderateBlurRate(color),
consistentMoveTimes(Pov(game, color)),
noFastMoves(Pov(game, color)),
suspiciousHoldAlert(color)
)
private val T = true
private val F = false
private def rankCheating(color: Color): GameAssessment = {
import GameAssessment._
val flags = mkFlags(color)
val assessment = flags match {
// SF1 SF2 BLR1 BLR2 MTs1 MTs2 Holds
case PlayerFlags(T, T, T, T, T, T, T) => Cheating // all T, obvious cheat
case PlayerFlags(T, _, T, _, _, T, _) => Cheating // high accuracy, high blurs, no fast moves
case PlayerFlags(T, _, _, T, _, _, _) => Cheating // high accuracy, moderate blurs
case PlayerFlags(_, _, _, T, T, _, _) => LikelyCheating // high accuracy, moderate blurs => 93% chance cheating
case PlayerFlags(T, _, _, _, _, _, T) => LikelyCheating // Holds are bad, hmk?
case PlayerFlags(_, T, _, _, _, _, T) => LikelyCheating // Holds are bad, hmk?
case PlayerFlags(_, T, T, _, _, _, _) => LikelyCheating // always has advantage, high blurs
case PlayerFlags(_, T, _, _, T, T, _) => Unclear // always has advantage, consistent move times
case PlayerFlags(T, _, _, _, T, T, _) => Unclear // high accuracy, consistent move times, no fast moves
case PlayerFlags(T, _, _, F, F, T, _) => Unclear // high accuracy, no fast moves, but doesn't blur or flat line
case PlayerFlags(T, _, _, _, _, F, _) => UnlikelyCheating // high accuracy, but has fast moves
case PlayerFlags(F, F, _, _, _, _, _) => NotCheating // low accuracy, doesn't hold advantage
case _ => NotCheating
}
if (flags.suspiciousHoldAlert) assessment
else if (~game.wonBy(color)) assessment
else if (assessment == Cheating || assessment == LikelyCheating) Unclear
else assessment
}
def sfAvg(color: Color): Int = listAverage(Accuracy.diffsList(Pov(game, color), analysis)).toInt
def sfSd(color: Color): Int = listDeviation(Accuracy.diffsList(Pov(game, color), analysis)).toInt
def mtAvg(color: Color): Int = listAverage(game moveTimes color).toInt
def mtSd(color: Color): Int = listDeviation(game moveTimes color).toInt
def blurs(color: Color): Int = game.playerBlurPercent(color)
def hold(color: Color): Boolean = game.player(color).hasSuspiciousHoldAlert
def playerAssessment(color: Color): PlayerAssessment =
PlayerAssessment(
_id = game.id + "/" + color.name,
gameId = game.id,
userId = ~game.player(color).userId,
white = (color == Color.White),
assessment = rankCheating(color),
date = DateTime.now,
// meta
flags = mkFlags(color),
sfAvg = sfAvg(color),
sfSd = sfSd(color),
mtAvg = mtAvg(color),
mtSd = mtSd(color),
blurs = blurs(color),
hold = hold(color)
)
}