mirror of https://github.com/hykilpikonna/AquaDX
[O] Better trend graph
parent
9ae23e4395
commit
48819c10a9
|
@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.RequestBody
|
||||||
import org.springframework.web.bind.annotation.RequestHeader
|
import org.springframework.web.bind.annotation.RequestHeader
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import org.springframework.web.bind.annotation.RequestParam
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
typealias RP = RequestParam
|
typealias RP = RequestParam
|
||||||
typealias RB = RequestBody
|
typealias RB = RequestBody
|
||||||
|
@ -40,8 +42,6 @@ operator fun Int.minus(message: String): Nothing {
|
||||||
val emailRegex = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$".toRegex()
|
val emailRegex = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$".toRegex()
|
||||||
fun Str.isValidEmail(): Bool = emailRegex.matches(this)
|
fun Str.isValidEmail(): Bool = emailRegex.matches(this)
|
||||||
|
|
||||||
fun millis() = System.currentTimeMillis()
|
|
||||||
|
|
||||||
val HTTP = HttpClient(CIO) {
|
val HTTP = HttpClient(CIO) {
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json(Json {
|
json(Json {
|
||||||
|
@ -51,6 +51,11 @@ val HTTP = HttpClient(CIO) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Date and time
|
||||||
|
fun millis() = System.currentTimeMillis()
|
||||||
|
val DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
||||||
|
fun LocalDate.isoDate() = format(DATE_FORMAT)
|
||||||
|
|
||||||
fun Long.toHex(len: Int = 16): Str = "0x${this.toString(len).padStart(len, '0').uppercase()}"
|
fun Long.toHex(len: Int = 16): Str = "0x${this.toString(len).padStart(len, '0').uppercase()}"
|
||||||
fun Map<String, Any>.toUrl() = entries.joinToString("&") { (k, v) -> "$k=$v" }
|
fun Map<String, Any>.toUrl() = entries.joinToString("&") { (k, v) -> "$k=$v" }
|
||||||
operator fun <K, V> Map<K, V>.plus(map: Map<K, V>) =
|
operator fun <K, V> Map<K, V>.plus(map: Map<K, V>) =
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package icu.samnyan.aqua.net.utils
|
package icu.samnyan.aqua.net.utils
|
||||||
|
|
||||||
|
import ext.isoDate
|
||||||
import ext.millis
|
import ext.millis
|
||||||
import ext.minus
|
import ext.minus
|
||||||
import icu.samnyan.aqua.net.games.GenericGameSummary
|
import icu.samnyan.aqua.net.games.GenericGameSummary
|
||||||
|
@ -9,6 +10,7 @@ import icu.samnyan.aqua.net.games.TrendOut
|
||||||
import icu.samnyan.aqua.sega.general.model.Card
|
import icu.samnyan.aqua.sega.general.model.Card
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
import org.springframework.data.repository.NoRepositoryBean
|
import org.springframework.data.repository.NoRepositoryBean
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
data class TrendLog(val date: String, val rating: Int)
|
data class TrendLog(val date: String, val rating: Int)
|
||||||
|
|
||||||
|
@ -16,8 +18,13 @@ data class TrendLog(val date: String, val rating: Int)
|
||||||
* Find the trend of a user's rating
|
* Find the trend of a user's rating
|
||||||
*/
|
*/
|
||||||
fun findTrend(log: List<TrendLog>): List<TrendOut> {
|
fun findTrend(log: List<TrendLog>): List<TrendOut> {
|
||||||
|
|
||||||
|
// Limit to 60 days by filtering out the dates that are too old
|
||||||
|
val minDate = LocalDate.now().minusDays(60).isoDate()
|
||||||
|
val now = LocalDate.now().isoDate()
|
||||||
|
|
||||||
// O(n log n)
|
// O(n log n)
|
||||||
val d = log.sortedBy { it.date }.toList()
|
val d = log.filter { it.date >= minDate }.sortedBy { it.date }.toList()
|
||||||
|
|
||||||
// Precompute the play counts for each date in O(n)
|
// Precompute the play counts for each date in O(n)
|
||||||
val playCounts = d.groupingBy { it.date }.eachCount()
|
val playCounts = d.groupingBy { it.date }.eachCount()
|
||||||
|
@ -26,10 +33,16 @@ fun findTrend(log: List<TrendLog>): List<TrendOut> {
|
||||||
val maxRating = d.groupingBy { it.date }.fold(0) { acc, e -> maxOf(acc, e.rating) }
|
val maxRating = d.groupingBy { it.date }.fold(0) { acc, e -> maxOf(acc, e.rating) }
|
||||||
|
|
||||||
// Use the precomputed play counts
|
// Use the precomputed play counts
|
||||||
return d.distinctBy { it.date }
|
val trend = d.distinctBy { it.date }
|
||||||
.map { TrendOut(it.date, maxRating[it.date] ?: 0,
|
.map { TrendOut(it.date, maxRating[it.date] ?: 0,
|
||||||
playCounts[it.date] ?: 0) }
|
playCounts[it.date] ?: 0) }
|
||||||
.sortedBy { it.date }
|
.sortedBy { it.date }.toMutableList()
|
||||||
|
|
||||||
|
// Fill in the missing dates (min date and current date)
|
||||||
|
trend[0].let { if (it.date != minDate) trend.add(0, TrendOut(minDate, 0, 0)) }
|
||||||
|
trend.last().let { if (it.date != now) trend.add(TrendOut(now, it.rating, 0)) }
|
||||||
|
|
||||||
|
return trend
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here are some interfaces to generalize across multiple games
|
// Here are some interfaces to generalize across multiple games
|
||||||
|
|
Loading…
Reference in New Issue