diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/game/GameConfig.kt b/sharedUI/src/commonMain/kotlin/com/livrets/game/GameConfig.kt new file mode 100644 index 0000000..4f97b7f --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/game/GameConfig.kt @@ -0,0 +1,10 @@ +package com.livrets.game + +import kotlinx.serialization.Serializable + +@Serializable +data class GameConfig( + val questionCount: Int, // 5..50 + val secondsPerQuestion: Int, // 3..30 + val maxTable: Int, // 1..12 : les deux facteurs sont tirés dans 1..maxTable +) diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/game/Question.kt b/sharedUI/src/commonMain/kotlin/com/livrets/game/Question.kt new file mode 100644 index 0000000..264ba34 --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/game/Question.kt @@ -0,0 +1,29 @@ +package com.livrets.game + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +sealed interface Question { + val table: Int + + @Serializable + @SerialName("direct") + data class Direct(val a: Int, val b: Int) : Question { + override val table: Int get() = maxOf(a, b) + override fun toString(): String = "$a × $b = ?" + } + + @Serializable + @SerialName("missing_factor") + data class MissingFactor(val a: Int, val b: Int) : Question { + override val table: Int get() = maxOf(a, b) + override fun toString(): String = "$a × ? = ${a * b}" + } +} + +val Question.correctAnswer: Int + get() = when (this) { + is Question.Direct -> a * b + is Question.MissingFactor -> b + } diff --git a/sharedUI/src/commonMain/kotlin/com/livrets/game/QuestionGenerator.kt b/sharedUI/src/commonMain/kotlin/com/livrets/game/QuestionGenerator.kt new file mode 100644 index 0000000..282e77c --- /dev/null +++ b/sharedUI/src/commonMain/kotlin/com/livrets/game/QuestionGenerator.kt @@ -0,0 +1,19 @@ +package com.livrets.game + +import kotlin.random.Random + +fun interface QuestionSource { + fun next(previous: Question?, maxTable: Int): Question +} + +class QuestionGenerator(private val random: Random = Random.Default) : QuestionSource { + override fun next(previous: Question?, maxTable: Int): Question { + while (true) { + val a = random.nextInt(1, maxTable + 1) + val b = random.nextInt(1, maxTable + 1) + val question = + if (random.nextBoolean()) Question.Direct(a, b) else Question.MissingFactor(a, b) + if (question != previous) return question + } + } +} diff --git a/sharedUI/src/commonTest/kotlin/com/livrets/game/QuestionGeneratorTest.kt b/sharedUI/src/commonTest/kotlin/com/livrets/game/QuestionGeneratorTest.kt new file mode 100644 index 0000000..235b55d --- /dev/null +++ b/sharedUI/src/commonTest/kotlin/com/livrets/game/QuestionGeneratorTest.kt @@ -0,0 +1,61 @@ +package com.livrets.game + +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals +import kotlin.test.assertTrue + +class QuestionGeneratorTest { + + @Test + fun `tous les facteurs restent dans 1 a maxTable`() { + val generator = QuestionGenerator(Random(42)) + repeat(500) { + val q = generator.next(previous = null, maxTable = 6) + val (a, b) = when (q) { + is Question.Direct -> q.a to q.b + is Question.MissingFactor -> q.a to q.b + } + assertTrue(a in 1..6, "a=$a hors bornes") + assertTrue(b in 1..6, "b=$b hors bornes") + } + } + + @Test + fun `les deux formes de question sont produites`() { + val generator = QuestionGenerator(Random(7)) + val questions = List(200) { generator.next(previous = null, maxTable = 12) } + assertTrue(questions.any { it is Question.Direct }) + assertTrue(questions.any { it is Question.MissingFactor }) + } + + @Test + fun `pas de doublon consecutif`() { + val generator = QuestionGenerator(Random(123)) + var previous: Question? = null + repeat(300) { + val q = generator.next(previous, 12) + assertNotEquals(previous, q) + previous = q + } + } + + @Test + fun `table vaut le plus grand facteur`() { + assertEquals(8, Question.Direct(3, 8).table) + assertEquals(9, Question.MissingFactor(9, 4).table) + } + + @Test + fun `bonne reponse selon la forme`() { + assertEquals(56, Question.Direct(7, 8).correctAnswer) + assertEquals(8, Question.MissingFactor(7, 8).correctAnswer) + } + + @Test + fun `affichage des deux formes`() { + assertEquals("7 × 8 = ?", Question.Direct(7, 8).toString()) + assertEquals("7 × ? = 56", Question.MissingFactor(7, 8).toString()) + } +}