Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package xyz.cssxsh.arknights.mine
import kotlinx.coroutines.*
import kotlinx.serialization.*
import xyz.cssxsh.arknights.bilibili.*
import xyz.cssxsh.arknights.excel.*
import java.time.*
import java.time.format.*
@Serializable
public data class Question(
@SerialName("problem")
val problem: String,
@SerialName("options")
val options: Map,
@SerialName("answer")
val answer: Set,
@SerialName("tips")
val tips: String? = null,
@SerialName("coin")
val coin: Int,
@SerialName("timeout")
val timeout: Long,
@SerialName("type")
val type: QuestionType
)
public enum class QuestionType(public val description: String) {
BUILDING("基建相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val building = runBlocking { loader.excel.building() }
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "基建技能", range = defaultChoiceRange) {
for ((characterId, info) in building.characters) {
val character = characters[characterId] ?: continue
for (char in info.buffs) {
for ((buffId) in char.data) {
val buff = building.buffs[buffId] ?: continue
add(character.name to buff.name)
}
}
}
}
}
},
PLAYER("玩家相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val const = runBlocking { loader.excel.const() }
val map: Map>> = buildMap {
val speed = const.playerApRegenSpeed
put("理智回复速度是每%d分钟1理智", speed to ((1..10).toSet() - speed))
val level = (1..const.maxPlayerLevel).random()
val ap = const.playerApMap[level - 1]
val exp = const.playerExpMap[level - 1]
put("等级为${level}, 理智回复上限为%d", ap to (const.playerApMap.toSet() - ap))
put("等级为${level}, 升级所需经验为%d", exp to (const.playerExpMap.toSet() - exp))
}
return JudgmentQuestionBuilder { state ->
val (text, param) = map.entries.random()
text.format(if (state) param.first else param.second.random()) to param.first.toString()
}
}
},
TALENT("天赋相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "天赋", range = defaultChoiceRange) {
for ((_, character) in characters) {
val talents = character.talents ?: continue
for (talent in talents) {
val candidates = talent.candidates ?: continue
for (candidate in candidates) {
val name = candidate.name ?: continue
add(character.name to name)
}
}
}
}
}
},
POSITION("位置相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "放置位", range = defaultChoiceRange) {
for ((_, character) in characters) {
add(character.name to character.position.text)
}
}
}
},
PROFESSION("职业相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "职业", range = defaultChoiceRange) {
for ((_, character) in characters) {
add(character.name to character.profession.text)
}
}
}
},
RARITY("星级相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "稀有度", range = defaultChoiceRange) {
for ((_, character) in characters) {
add(character.name to (character.rarity + 1).toString())
}
}
}
},
POWER("政权相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val teams = runBlocking { loader.excel.team() }
val characters = runBlocking { loader.excel.character() }
val level = PowerLevel.values().random()
return ChoiceQuestionBuilder(meaning = level.text to "角色", range = defaultChoiceRange) {
for ((_, team) in teams) {
if (team.level != level.ordinal) continue
for ((_, character) in characters) {
if (level.get(character) != team.id) continue
add(team.name to character.name)
}
}
}
}
},
ILLUST("立绘相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val handbooks = runBlocking { loader.excel.handbook().handbooks }
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "画师" to "角色", range = defaultChoiceRange) {
for ((characterId, handbook) in handbooks) {
val character = characters[characterId] ?: continue
add(handbook.illust to character.name)
}
}
}
},
VOICE("声优相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val voices = runBlocking { loader.excel.word().voiceLangDict }
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "声优" to "角色", range = defaultChoiceRange) {
for ((characterId, voice) in voices) {
val character = characters[characterId] ?: continue
for ((_, dict) in voice.dict) {
add(dict.cvName to character.name)
}
}
}
}
},
SKILL("技能相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val skills = runBlocking { loader.excel.skill() }
val characters = runBlocking { loader.excel.character() }
return ChoiceQuestionBuilder(meaning = "角色" to "技能", range = defaultChoiceRange) {
for ((_, character) in characters) {
for (info in character.skills) {
val skillId = info.skill ?: continue
val skill = skills[skillId] ?: continue
val name = skill.levels.firstOrNull()?.name ?: continue
add(character.name to name)
}
}
}
}
},
STORY("剧情相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val stories = runBlocking { loader.excel.story() }
val story = buildList {
for ((_, story) in stories) {
if (story.action == ActionType.NONE) continue
add(story)
}
}.random()
val problem = "${story.action.text}<${story.name}>开始于"
return DateTimeQuestionBuilder(problem = problem, datetime = story.start)
}
},
ENEMY("敌方相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val enemies = runBlocking { loader.excel.enemy() }
val (attribute, value) = listOf String>>(
"攻击方式" to { type },
"攻击力" to { attack },
"防御力" to { defence },
"法术抗性" to { resistance },
"耐久" to { endure }
).random()
return ChoiceQuestionBuilder(meaning = "敌方" to attribute, range = defaultChoiceRange) {
for ((_, enemy) in enemies) {
add(enemy.designation to enemy.value())
}
}
}
},
WEEKLY("周常相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val table = runBlocking { loader.excel.zone() }
return ChoiceQuestionBuilder(meaning = "周常" to "开启时间", range = defaultChoiceRange) {
for ((zoneId, weekly) in table.weekly) {
val zone = table.zones[zoneId] ?: continue
add(zone.title to weekly.daysOfWeek.joinToString())
}
}
}
},
MUSIC("音乐相关") {
override fun load(loader: QuestionDataLoader): QuestionBuilder {
val video = loader.video.cache[VideoType.MUSIC].orEmpty().random()
val problem = "${video.title}(${video.bvid})发布于"
return DateTimeQuestionBuilder(problem = problem, datetime = video.created)
}
},
OTHER("自选相关") {
public override fun load(loader: QuestionDataLoader): QuestionBuilder {
return requireNotNull(loader.custom.question.values.randomOrNull()) { "题目集为空" }
}
};
public fun random(loader: QuestionDataLoader): Question = load(loader).build(this)
public abstract fun load(loader: QuestionDataLoader): QuestionBuilder
}
private fun Boolean.Companion.random() = listOf(true, false).random()
private val formatter = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss")
private val prefix get() = listOf(-1L, 1L).random()
private fun OffsetDateTime.randomDays(offset: Int = 1) = plusDays(offset * prefix)
private fun OffsetDateTime.randomMinutes(offset: Int = 30) = plusMinutes(offset * prefix)
private val defaultChoiceRange = 'A'..'D'
public interface QuestionDataLoader {
public val excel: ExcelDataHolder
public val video: VideoDataHolder
public val custom: CustomQuestionHolder
}
public interface CustomQuestionHolder {
public val question: Map
}
public sealed class QuestionBuilder {
public abstract fun build(type: QuestionType): Question
}
public class ChoiceQuestionBuilder(
public val meaning: Pair,
public val range: CharRange,
public val fill: MutableList>.() -> Unit
) : QuestionBuilder() {
override fun build(type: QuestionType): Question {
val reversal = Boolean.random()
val key = { pair: Pair -> if (reversal) pair.second else pair.first }
val value = { pair: Pair -> if (reversal) pair.first else pair.second }
val relation = ArrayList>().apply { fill(); shuffle() }
val map = relation.groupBy(key, value)
val options = (range zip map.entries).toMap()
val random = options.values.flatMap { it.value }.random()
val answer = options.filter { (_, list) -> random in list.value }.keys
val problem = "下列选项中" + (if (reversal) "%1\$s[%3\$s]的%2\$s是" else "有%2\$s[%3\$s]的%1\$s是")
return Question(
problem = problem.format(meaning.first, meaning.second, random),
options = options.mapValues { (_, entry) -> entry.key },
answer = answer,
coin = options.size * 100,
timeout = options.size * 10_000L,
type = type
)
}
}
@Serializable
public data class CustomQuestionInfo(
@SerialName("problem")
val problem: String,
@SerialName("options")
val options: Map,
@SerialName("coin")
val coin: Int,
@SerialName("tips")
val tips: String,
@SerialName("timeout")
val timeout: Long
) : QuestionBuilder() {
public constructor(
problem: String,
right: List,
error: List,
coin: Int,
tips: String,
timeout: Long
) : this(
problem = problem,
options = right.associateWith { true } + error.associateWith { false },
coin = coin,
tips = tips,
timeout = timeout
)
override fun build(type: QuestionType): Question {
val map = (('A'..'Z') zip options.entries.shuffled()).toMap()
return Question(
problem = problem,
options = map.mapValues { (_, entry) -> entry.key },
answer = map.filter { (_, entry) -> entry.value }.keys,
coin = coin,
tips = tips,
timeout = timeout,
type = type
)
}
}
public class DateTimeQuestionBuilder(
public val problem: String,
public val datetime: OffsetDateTime
) : QuestionBuilder() {
override fun build(type: QuestionType): Question {
val range = defaultChoiceRange
val list = listOf(
datetime,
datetime.randomDays(),
datetime.randomMinutes(),
datetime.randomDays().randomMinutes()
)
val map = (range zip list).toMap()
val answer = map.entries.filter { it.value == datetime }.mapTo(HashSet()) { it.key }
return Question(
problem = problem,
options = map.mapValues { (_, datetime) -> datetime.format(formatter) },
answer = answer,
coin = 1800,
timeout = 3 * 60_000L,
type = type
)
}
}
public class JudgmentQuestionBuilder(
public val generate: (Boolean) -> Pair
) : QuestionBuilder() {
override fun build(type: QuestionType): Question {
val state = Boolean.random()
val (problem, tips) = generate(state)
return Question(
problem = problem,
options = mapOf('Y' to "对", 'N' to "错"),
answer = setOf(if (state) 'Y' else 'N'),
coin = 600,
tips = tips,
timeout = 60_000L,
type = type
)
}
}