feat: score leaderboard pondéré et id de board
This commit is contained in:
4 files changed
+112
No files matched your search
@@ -27,3 +27,9 @@ val Question.correctAnswer: Int
|
|||||||
is Question.Direct -> a * b
|
is Question.Direct -> a * b
|
||||||
is Question.MissingFactor -> b
|
is Question.MissingFactor -> b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Question.product: Int
|
||||||
|
get() = when (this) {
|
||||||
|
is Question.Direct -> a * b
|
||||||
|
is Question.MissingFactor -> a * b
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.livrets.games
|
||||||
|
|
||||||
|
import com.livrets.game.GameResult
|
||||||
|
import com.livrets.game.product
|
||||||
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
|
fun GameResult.leaderboardScore(): Long {
|
||||||
|
if (correctCount == 0) return 0L
|
||||||
|
val products = records.filter { it.isCorrect }.sumOf { it.question.product }
|
||||||
|
return (products * 30.0 / config.secondsPerQuestion).roundToLong()
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.livrets.games
|
||||||
|
|
||||||
|
import com.livrets.game.GameConfig
|
||||||
|
|
||||||
|
fun GameConfig.leaderboardId(): String = "questions_$questionCount"
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.livrets.games
|
||||||
|
|
||||||
|
import com.livrets.game.AnswerRecord
|
||||||
|
import com.livrets.game.GameConfig
|
||||||
|
import com.livrets.game.GameResult
|
||||||
|
import com.livrets.game.Question
|
||||||
|
import com.livrets.game.product
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.time.Instant
|
||||||
|
|
||||||
|
class LeaderboardScoreTest {
|
||||||
|
|
||||||
|
private fun result(config: GameConfig, records: List<AnswerRecord>) =
|
||||||
|
GameResult(date = Instant.parse("2026-08-28T10:00:00Z"), config = config, records = records)
|
||||||
|
|
||||||
|
private fun direct(a: Int, b: Int, correct: Boolean) = AnswerRecord(
|
||||||
|
question = Question.Direct(a, b),
|
||||||
|
givenAnswer = if (correct) a * b else a * b + 1,
|
||||||
|
correctAnswer = a * b,
|
||||||
|
isCorrect = correct,
|
||||||
|
durationMs = 1000,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun missing(a: Int, b: Int, correct: Boolean) = AnswerRecord(
|
||||||
|
question = Question.MissingFactor(a, b),
|
||||||
|
givenAnswer = if (correct) b else b + 1,
|
||||||
|
correctAnswer = b,
|
||||||
|
isCorrect = correct,
|
||||||
|
durationMs = 1000,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `produit d'une question directe et a facteur manquant`() {
|
||||||
|
assertEquals(56, Question.Direct(7, 8).product)
|
||||||
|
assertEquals(10, Question.MissingFactor(2, 5).product)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `score nul sans bonne reponse`() {
|
||||||
|
val r = result(GameConfig(5, 5, 12), listOf(direct(7, 8, false), missing(2, 5, false)))
|
||||||
|
assertEquals(0L, r.leaderboardScore())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `score = somme des produits reussis fois le facteur vitesse`() {
|
||||||
|
val r = result(
|
||||||
|
GameConfig(10, 5, 12),
|
||||||
|
listOf(direct(7, 8, true), direct(3, 4, false), missing(2, 5, true)),
|
||||||
|
)
|
||||||
|
// (56 + 10) × 30 / 5 = 396
|
||||||
|
assertEquals(396L, r.leaderboardScore())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toutes les questions reussies`() {
|
||||||
|
val r = result(
|
||||||
|
GameConfig(5, 3, 12),
|
||||||
|
listOf(
|
||||||
|
direct(4, 6, true),
|
||||||
|
direct(7, 8, true),
|
||||||
|
direct(9, 9, true),
|
||||||
|
direct(2, 12, true),
|
||||||
|
direct(5, 5, true),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// (24 + 56 + 81 + 24 + 25) × 30 / 3 = 210 × 10 = 2100
|
||||||
|
assertEquals(2100L, r.leaderboardScore())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `arrondi au point le plus proche`() {
|
||||||
|
// 8 × 30 / 4 = 60 (exact)
|
||||||
|
assertEquals(
|
||||||
|
60L,
|
||||||
|
result(GameConfig(10, 4, 12), listOf(direct(2, 4, true))).leaderboardScore(),
|
||||||
|
)
|
||||||
|
// 7 × 30 / 4 = 52,5 → 53
|
||||||
|
assertEquals(
|
||||||
|
53L,
|
||||||
|
result(GameConfig(10, 4, 12), listOf(direct(7, 1, true))).leaderboardScore(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `id de board par nombre de questions`() {
|
||||||
|
assertEquals("questions_10", GameConfig(10, 5, 12).leaderboardId())
|
||||||
|
assertEquals("questions_5", GameConfig(5, 3, 1).leaderboardId())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user