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
|
package coffee.liz.rookery.model
enum class Penalty(val code: String) {
NONE("ok"), PLUS2("+2"), DNF("dnf");
companion object { fun of(code: String?) = entries.firstOrNull { it.code == code } ?: NONE }
}
/** Result in ms after penalties; [DNF] sorts after every real time. */
const val DNF: Long = Long.MAX_VALUE
data class Session(val id: String, val name: String, val event: Event, val createdAt: Long)
data class Solve(
val id: String,
val sessionId: String,
val event: Event,
/** Raw timer reading, before penalties. */
val ms: Long,
val penalty: Penalty,
val scramble: String,
val comment: String,
/** Epoch ms when the solve finished. */
val at: Long,
/** Smart-cube reconstruction, csTimer style: `R@0 U'@120 ...` */
val moves: String? = null,
/** Blindfolded with a smart cube: time until the first turn. */
val memoMs: Long? = null,
) {
val result: Long get() = when (penalty) {
Penalty.NONE -> ms
Penalty.PLUS2 -> ms + 2000
Penalty.DNF -> DNF
}
}
data class LetterPair(
val pair: String,
val primary: String?,
val words: Set<String>,
val note: String?,
/** Blob name of the chosen image. */
val image: String?,
/** 0 (easy) .. 1 (always missed) from practice history, null if never drilled. */
val difficulty: Double? = null,
)
data class WordChange(val pair: String, val from: String?, val to: String?, val at: Long, val source: String)
data class MemoSession(val at: Long, val pairs: Int, val memoMs: Long, val recalled: Int)
/** A smart cube we have paired with on some device. Synced so every device knows its MAC. */
data class CubeDevice(val mac: String, val name: String, val protocol: String)
|