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, 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)