forked from lichess-org/lila
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDimension.scala
310 lines (278 loc) · 9.73 KB
/
Dimension.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package lila.insight
import play.api.i18n.Lang
import play.api.libs.json._
import reactivemongo.api.bson._
import scalatags.Text.all._
import chess.opening.EcopeningDB
import chess.{ Color, Role }
import lila.db.dsl._
import lila.rating.PerfType
sealed abstract class Dimension[A: BSONHandler](
val key: String,
val name: String,
val dbKey: String,
val position: Position,
val description: Frag
) {
def bson = implicitly[BSONHandler[A]]
def isInGame = position == Position.Game
def isInMove = position == Position.Move
}
object Dimension {
import BSONHandlers._
import Position._
import Entry.{ BSONFields => F }
import lila.rating.BSONHandlers.perfTypeIdHandler
case object Period
extends Dimension[Period](
"period",
"Date",
F.date,
Game,
raw("The date at which the game was played")
)
case object Date
extends Dimension[lila.insight.DateRange](
"date",
"Date",
F.date,
Game,
raw("The date at which the game was played")
)
case object Perf
extends Dimension[PerfType](
"variant",
"Variant",
F.perf,
Game,
raw("The rating category of the game, like Bullet, Blitz, or Chess960.")
)
case object Phase
extends Dimension[Phase](
"phase",
"Game phase",
F.moves("p"),
Move,
raw("The portion of the game: Opening, Middlegame, or Endgame.")
)
case object Result
extends Dimension[Result](
"result",
"Game result",
F.result,
Game,
raw("Whether you won, lost, or drew the game.")
)
case object Termination
extends Dimension[Termination](
"termination",
"Game termination",
F.termination,
Game,
raw("The way that the game ended, like Checkmate or Resignation.")
)
case object Color
extends Dimension[Color](
"color",
"Color",
F.color,
Game,
raw("The side you are playing: White or Black.")
)
case object Opening
extends Dimension[chess.opening.Ecopening](
"opening",
"Opening",
F.eco,
Game,
raw("ECO identification of the initial moves, like \"A58 Benko Gambit\".")
)
case object OpponentStrength
extends Dimension[RelativeStrength](
"opponentStrength",
"Opponent strength",
F.opponentStrength,
Game,
raw(
"Rating of your opponent compared to yours. Much weaker:-200, Weaker:-100, Stronger:+100, Much stronger:+200."
)
)
case object PieceRole
extends Dimension[Role](
"piece",
"Piece moved",
F.moves("r"),
Move,
raw("The type of piece you move.")
)
case object MovetimeRange
extends Dimension[MovetimeRange](
"movetime",
"Move time",
F.moves("t"),
Move,
raw("The amount of time you spend thinking on each move, in seconds.")
)
case object MyCastling
extends Dimension[Castling](
"myCastling",
"My castling side",
F.myCastling,
Game,
raw("The side you castled on during the game: kingside, queenside, or none.")
)
case object OpCastling
extends Dimension[Castling](
"opCastling",
"Opponent castling side",
F.opponentCastling,
Game,
raw("The side your opponent castled on during the game: kingside, queenside, or none.")
)
case object QueenTrade
extends Dimension[QueenTrade](
"queenTrade",
"Queen trade",
F.queenTrade,
Game,
raw("Whether queens were traded before the endgame or not.")
)
case object MaterialRange
extends Dimension[MaterialRange](
"material",
"Material imbalance",
F.moves("i"),
Move,
raw("Value of your pieces compared to your opponent's. Pawn=1, Bishop/Knight=3, Rook=5, Queen=9.")
)
case object Blur
extends Dimension[Blur](
"blur",
"Move blur",
F.moves("b"),
Move,
raw("Whether a window blur happened before that move or not.")
)
case object TimeVariance
extends Dimension[TimeVariance](
"timeVariance",
"Time variance",
F.moves("v"),
Move,
raw(
"Move time variance. Very consistent: < 0.25, Consistent: < 0.4, Medium, Variable: > 0.6, Very variable > 0.75."
)
)
def requiresStableRating(d: Dimension[_]) =
d match {
case OpponentStrength => true
case _ => false
}
def valuesOf[X](d: Dimension[X]): List[X] =
d match {
case Period => lila.insight.Period.selector
case Date => Nil // Period is used instead
case Perf => PerfType.nonPuzzle
case Phase => lila.insight.Phase.all
case Result => lila.insight.Result.all
case Termination => lila.insight.Termination.all
case Color => chess.Color.all
case Opening => EcopeningDB.all
case OpponentStrength => RelativeStrength.all
case PieceRole => chess.Role.all.reverse
case MovetimeRange => lila.insight.MovetimeRange.all
case MyCastling | OpCastling => lila.insight.Castling.all
case QueenTrade => lila.insight.QueenTrade.all
case MaterialRange => lila.insight.MaterialRange.all
case Blur => lila.insight.Blur.all
case TimeVariance => lila.insight.TimeVariance.all
}
def valueByKey[X](d: Dimension[X], key: String): Option[X] =
d match {
case Period => key.toIntOption map lila.insight.Period.apply
case Date => None
case Perf => PerfType.byKey get key
case Phase => key.toIntOption flatMap lila.insight.Phase.byId.get
case Result => key.toIntOption flatMap lila.insight.Result.byId.get
case Termination => key.toIntOption flatMap lila.insight.Termination.byId.get
case Color => chess.Color.fromName(key)
case Opening => EcopeningDB.allByEco get key
case OpponentStrength => key.toIntOption flatMap RelativeStrength.byId.get
case PieceRole => chess.Role.all.find(_.name == key)
case MovetimeRange => key.toIntOption flatMap lila.insight.MovetimeRange.byId.get
case MyCastling | OpCastling => key.toIntOption flatMap lila.insight.Castling.byId.get
case QueenTrade => lila.insight.QueenTrade(key == "true").some
case MaterialRange => key.toIntOption flatMap lila.insight.MaterialRange.byId.get
case Blur => lila.insight.Blur(key == "true").some
case TimeVariance => key.toFloatOption map lila.insight.TimeVariance.byId
}
def valueToJson[X](d: Dimension[X])(v: X)(implicit lang: Lang): play.api.libs.json.JsObject = {
play.api.libs.json.Json.obj(
"key" -> valueKey(d)(v),
"name" -> valueJson(d)(v)
)
}
def valueKey[X](d: Dimension[X])(v: X): String =
(d match {
case Date => v.toString
case Period => v.days.toString
case Perf => v.key
case Phase => v.id
case Result => v.id
case Termination => v.id
case Color => v.name
case Opening => v.eco
case OpponentStrength => v.id
case PieceRole => v.name
case MovetimeRange => v.id
case MyCastling | OpCastling => v.id
case QueenTrade => v.id
case MaterialRange => v.id
case Blur => v.id
case TimeVariance => v.id
}).toString
def valueJson[X](d: Dimension[X])(v: X)(implicit lang: Lang): JsValue =
d match {
case Date => JsNumber(v.min.getSeconds)
case Period => JsString(v.toString)
case Perf => JsString(v.trans)
case Phase => JsString(v.name)
case Result => JsString(v.name)
case Termination => JsString(v.name)
case Color => JsString(v.toString)
case Opening => JsString(v.ecoName)
case OpponentStrength => JsString(v.name)
case PieceRole => JsString(v.toString)
case MovetimeRange => JsString(v.name)
case MyCastling | OpCastling => JsString(v.name)
case QueenTrade => JsString(v.name)
case MaterialRange => JsString(v.name)
case Blur => JsString(v.name)
case TimeVariance => JsString(v.name)
}
def filtersOf[X](d: Dimension[X], selected: List[X]): Bdoc = {
import cats.implicits._
d match {
case Dimension.MovetimeRange =>
selected match {
case Nil => $empty
case xs => $doc(d.dbKey $in xs.flatMap(_.tenths.toList))
}
case Dimension.Period =>
selected.maximumByOption(_.days).fold($empty) { period =>
$doc(d.dbKey $gt period.min)
}
case _ =>
selected flatMap d.bson.writeOpt match {
case Nil => $empty
case List(x) => $doc(d.dbKey -> x)
case xs => $doc(d.dbKey -> $doc("$in" -> BSONArray(xs)))
}
}
}
def dataTypeOf[X](d: Dimension[X]): String =
d match {
case Date => "date"
case _ => "text"
}
}