Skip to content

Commit

Permalink
More chat games (#71)
Browse files Browse the repository at this point in the history
* #59 add chat based games

* #59 fix ignore case for answer

* add arrow ascii

* up version 2.24.0

* fix reward

* add min max amount for money reward

* add anagram

* add quadratic equation
  • Loading branch information
makeevrserg committed Aug 11, 2024
1 parent f7b20c7 commit 86e1c35
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 32 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ makeevrserg.java.ktarget=21
# Project
makeevrserg.project.name=AspeKt
makeevrserg.project.group=ru.astrainteractive.aspekt
makeevrserg.project.version.string=2.24.0
makeevrserg.project.version.string=2.25.0
makeevrserg.project.description=Essentials plugin for EmpireProjekt
makeevrserg.project.developers=makeevrserg|Makeev Roman|[email protected]
makeevrserg.project.url=https://empireprojekt.ru
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ru.astrainteractive.aspekt.module.chatgame.command.ChatGameCommand
import ru.astrainteractive.aspekt.module.chatgame.job.ChatGameJob
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGameConfig
import ru.astrainteractive.aspekt.module.chatgame.store.ChatGameStoreImpl
import ru.astrainteractive.aspekt.module.chatgame.store.RiddleGenerator
import ru.astrainteractive.astralibs.lifecycle.Lifecycle
import ru.astrainteractive.astralibs.serialization.StringFormatExt.parseOrDefault
import ru.astrainteractive.astralibs.serialization.StringFormatExt.writeIntoFile
Expand All @@ -22,15 +23,18 @@ interface ChatGameModule {
}
private val chatGameStore by lazy {
ChatGameStoreImpl(
chatGameConfigProvider = { config.value }
chatGameConfigProvider = { config.value },
riddleGenerator = RiddleGenerator(
configProvider = { config.value },
translationProvider = { coreModule.translation.value }
)
)
}
private val chatGameJob by lazy {
ChatGameJob(
chatGameStore = chatGameStore,
chatGameConfigProvider = { config.value },
kyoriComponentSerializerProvider = { coreModule.kyoriComponentSerializer.value },
translationProvider = { coreModule.translation.value }
)
}
private val command by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import org.bukkit.Bukkit
import ru.astrainteractive.aspekt.job.ScheduledJob
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGameConfig
import ru.astrainteractive.aspekt.module.chatgame.store.ChatGameStore
import ru.astrainteractive.aspekt.plugin.PluginTranslation
import ru.astrainteractive.astralibs.kyori.KyoriComponentSerializer
import ru.astrainteractive.klibs.kdi.Provider
import ru.astrainteractive.klibs.kdi.getValue
Expand All @@ -13,9 +12,7 @@ internal class ChatGameJob(
private val chatGameStore: ChatGameStore,
chatGameConfigProvider: Provider<ChatGameConfig>,
kyoriComponentSerializerProvider: Provider<KyoriComponentSerializer>,
translationProvider: Provider<PluginTranslation>
) : ScheduledJob("ChatGameJob") {
private val translation by translationProvider
private val kyoriComponentSerializer by kyoriComponentSerializerProvider
private val chatGameConfig by chatGameConfigProvider
override val delayMillis: Long
Expand All @@ -29,7 +26,7 @@ internal class ChatGameJob(
chatGameStore.startNextGame()
val state = chatGameStore.state.value as? ChatGameStore.State.Started ?: return
with(kyoriComponentSerializer) {
translation.chatGame.gameStarted(state.chatGame.question.raw)
state.chatGame.question
.component
.run(Bukkit::broadcast)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,15 @@ internal sealed interface ChatGame {
@SerialName("EQUATION_EASY")
@Serializable
class EquationEasy(override val reward: Reward? = null) : ChatGame

@SerialName("EQUATION_QUADRATIC")
@Serializable
class QuadraticEquation(override val reward: Reward? = null) : ChatGame

@SerialName("ANAGRAM")
@Serializable
class Anagram(
val words: List<String>,
override val reward: Reward? = null
) : ChatGame
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.astrainteractive.aspekt.module.chatgame.model

import ru.astrainteractive.astralibs.string.StringDesc

internal data class ChatGameData(
val question: StringDesc.Raw,
val answers: List<String>,
val reward: Reward
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ru.astrainteractive.aspekt.module.chatgame.store

import kotlinx.coroutines.flow.StateFlow
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGame
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGameData

internal interface ChatGameStore {
val state: StateFlow<State>
Expand All @@ -13,6 +13,6 @@ internal interface ChatGameStore {

sealed interface State {
data object Pending : State
data class Started(val chatGame: ChatGame.Riddle) : State
data class Started(val chatGame: ChatGameData) : State
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import ru.astrainteractive.klibs.kdi.Provider
import ru.astrainteractive.klibs.kdi.getValue

internal class ChatGameStoreImpl(
chatGameConfigProvider: Provider<ChatGameConfig>
chatGameConfigProvider: Provider<ChatGameConfig>,
private val riddleGenerator: RiddleGenerator
) : ChatGameStore, Logger by JUtiltLogger("ChatGameStore") {
private val chatGameConfig by chatGameConfigProvider

Expand All @@ -26,13 +27,13 @@ internal class ChatGameStoreImpl(
error { "#startNextGame could not start chat game" }
return
}
val game = RiddleGenerator.generate(nextGame)
val game = riddleGenerator.generate(nextGame)
_state.value = ChatGameStore.State.Started(game)
}

override fun isAnswerCorrect(answer: String): Boolean {
val currentGame = state.value as? ChatGameStore.State.Started ?: return false
return answer.equals(currentGame.chatGame.answer, true)
return currentGame.chatGame.answers.any { it.equals(answer, true) }
}

override fun isGameStarted(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,111 @@
package ru.astrainteractive.aspekt.module.chatgame.store

import ru.astrainteractive.aspekt.module.chatgame.model.ChatGame
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGame.Riddle
import ru.astrainteractive.astralibs.string.StringDesc
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGameConfig
import ru.astrainteractive.aspekt.module.chatgame.model.ChatGameData
import ru.astrainteractive.aspekt.plugin.PluginTranslation
import ru.astrainteractive.klibs.kdi.Provider
import ru.astrainteractive.klibs.kdi.getValue
import kotlin.math.pow
import kotlin.math.sign
import kotlin.math.sqrt
import kotlin.random.Random

internal object RiddleGenerator {
fun generate(instance: ChatGame): ChatGame.Riddle {
internal class RiddleGenerator(
configProvider: Provider<ChatGameConfig>,
translationProvider: Provider<PluginTranslation>
) {
private val config by configProvider
private val translation by translationProvider

@Suppress("LongMethod", "CyclomaticComplexMethod")
fun generate(instance: ChatGame): ChatGameData {
return when (instance) {
is ChatGame.EquationEasy -> {
val first = Random.nextInt(0, 99)
val second = Random.nextInt(0, 99)
return Riddle(
question = StringDesc.Raw(
return ChatGameData(
question = translation.chatGame.solveExample(
when (Random.nextBoolean()) {
true -> "x+$first=$second"
false -> "x-$second=-$first"
}
),
answer = "${second - first}",
reward = instance.reward
answers = listOf("${second - first}"),
reward = instance.reward ?: config.defaultReward
)
}

is ChatGame.Riddle -> instance
is ChatGame.Riddle -> ChatGameData(
question = translation.chatGame.solveRiddle(instance.question.raw),
answers = listOf(instance.answer),
reward = instance.reward ?: config.defaultReward
)

is ChatGame.SumOfTwo -> {
val first = Random.nextInt(0, 200)
val second = Random.nextInt(0, 200)
return Riddle(
question = StringDesc.Raw("$first+$second"),
answer = "${first + second}",
reward = instance.reward
return ChatGameData(
question = translation.chatGame.solveExample("$first+$second"),
answers = listOf("${first + second}"),
reward = instance.reward ?: config.defaultReward
)
}

is ChatGame.TimesOfTwo -> {
val first = Random.nextInt(0, 30)
val second = Random.nextInt(0, 30)
return Riddle(
question = StringDesc.Raw("$first*$second"),
answer = "${first * second}",
reward = instance.reward
return ChatGameData(
question = translation.chatGame.solveExample("$first*$second"),
answers = listOf("${first * second}"),
reward = instance.reward ?: config.defaultReward
)
}

is ChatGame.Anagram -> {
val word = instance.words.random()
val anagram: String = buildString {
word.indices.shuffled().forEach { i ->
this.append(word[i])
}
}
ChatGameData(
question = translation.chatGame.solveAnagram(anagram),
answers = listOf(word),
reward = instance.reward ?: config.defaultReward
)
}

is ChatGame.QuadraticEquation -> {
val nonZeroRandom = ((-12..12).toList() - 0)
val b = nonZeroRandom.random()
val a = nonZeroRandom.random()
val c = nonZeroRandom.random().let { c ->
if (a < 0) c * c.sign else -1
}
val equation = buildString {
append(a)
append("")
if (a != 0 && b.sign == 1) append("+")
append(b)
append("x")
if (c.sign == 1 && (a != 0 || b != 0)) append("+")
append(c)
}

fun Double.roundDec(dec: Int): Double {
val tens = 10.0.pow(dec)
return kotlin.math.round(this * tens) / tens
}

val d = b * b - 4 * a * c
val sqrtD = sqrt(d.toDouble())
val root1 = (-b + sqrtD).div(2 * a).roundDec(2)
val root2 = (-b - sqrtD).div(2 * a).roundDec(2)
ChatGameData(
question = translation.chatGame.solveQuadratic(equation),
answers = listOf(root1.toString(), root2.toString()).also { println(it) },
reward = instance.reward ?: config.defaultReward
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,18 @@ class PluginTranslation(
) {
@Serializable
class ChatGame(
@SerialName("game_started")
private val gameStarted: StringDesc.Raw = StringDesc.Raw("&7[&#DBB72BКВИЗ&7] %quiz% → &2/quiz ОТВЕТ"),
@SerialName("solve_riddle")
private val solveRiddle: StringDesc.Raw = StringDesc.Raw("&7[&#DBB72BКВИЗ&7] Загадка: %quiz% → &2/quiz ОТВЕТ"),
@SerialName("solve_example")
private val solveExample: StringDesc.Raw = StringDesc.Raw("&7[&#DBB72BКВИЗ&7] Пример: %quiz% → &2/quiz ОТВЕТ"),
@SerialName("solve_anagram")
private val solveAnagram: StringDesc.Raw = StringDesc.Raw(
"&7[&#DBB72BКВИЗ&7] Анаграмма: %quiz% → &2/quiz ОТВЕТ"
),
@SerialName("solve_quadratic")
private val solveQuadratic: StringDesc.Raw = StringDesc.Raw(
"&7[&#DBB72BКВИЗ&7] Квадратное уравнение: %quiz% → &2/quiz ОТВЕТ &7Любой вариант ответа с точностью до сотой. Например: 0.02, 0.3, 1.0"
),
@SerialName("no_quiz_available")
val noQuizAvailable: StringDesc.Raw = StringDesc.Raw(
"&7[&#DBB72BКВИЗ&7] &#db2c18В данный момент нет активного квиза!"
Expand All @@ -42,7 +52,11 @@ class PluginTranslation(
"&7[&#DBB72BКВИЗ&7] &6%player% &7угадал верный ответ! И получил &6%amount% &7монет!"
),
) {
fun gameStarted(quiz: String) = gameStarted.replace("%quiz%", quiz)
fun solveRiddle(quiz: String) = solveRiddle.replace("%quiz%", quiz)
fun solveExample(quiz: String) = solveExample.replace("%quiz%", quiz)
fun solveAnagram(quiz: String) = solveAnagram.replace("%quiz%", quiz)
fun solveQuadratic(quiz: String) = solveQuadratic.replace("%quiz%", quiz)

fun gameEndedMoneyReward(player: String, amount: Number) = gameEndedMoneyReward
.replace("%player%", player)
.replace("%amount%", amount.toString())
Expand Down

0 comments on commit 86e1c35

Please sign in to comment.