Add a scripting system.
This commit is contained in:
parent
6ea8f90903
commit
9718056260
2 changed files with 146 additions and 0 deletions
88
app/src/main/java/com/pixelized/rplexicon/script/Script.kt
Normal file
88
app/src/main/java/com/pixelized/rplexicon/script/Script.kt
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.pixelized.rplexicon.script
|
||||||
|
|
||||||
|
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||||
|
|
||||||
|
sealed class Script(
|
||||||
|
val predicate: ScriptExecutor.() -> Boolean
|
||||||
|
) {
|
||||||
|
class OR(
|
||||||
|
private vararg val scripts: Script,
|
||||||
|
) : Script(predicate = {
|
||||||
|
scripts.any { it.predicate.invoke(this) }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return scripts.joinToString(
|
||||||
|
prefix = "(",
|
||||||
|
postfix = ")",
|
||||||
|
separator = " || "
|
||||||
|
) { it.toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AND(
|
||||||
|
private vararg val scripts: Script,
|
||||||
|
) : Script(predicate = {
|
||||||
|
scripts.all { it.predicate.invoke(this) }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return scripts.joinToString(
|
||||||
|
prefix = "(",
|
||||||
|
postfix = ")",
|
||||||
|
separator = " && "
|
||||||
|
) { it.toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ACTIVE(
|
||||||
|
val alteration: String,
|
||||||
|
) : Script(predicate = {
|
||||||
|
alterations.any { it.name == alteration }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ACTIVE('$alteration')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ANY(
|
||||||
|
val alteration: String,
|
||||||
|
) : Script(predicate = {
|
||||||
|
alterations.any { it.name.contains(alteration) }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "ANY('$alteration')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NOT(
|
||||||
|
val alteration: String,
|
||||||
|
) : Script(predicate = {
|
||||||
|
alterations.none { it.name == alteration }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NOT('$alteration')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NONE(
|
||||||
|
val alteration: String,
|
||||||
|
) : Script(predicate = {
|
||||||
|
alterations.none { it.name.contains(alteration) }
|
||||||
|
}) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NONE('$alteration')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun ScriptExecutor.invoke() = predicate()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScriptExecutor(
|
||||||
|
val alterations: List<Alteration>,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun scriptExecutor(
|
||||||
|
alterations: List<Alteration>,
|
||||||
|
block: ScriptExecutor.() -> Boolean
|
||||||
|
): Boolean {
|
||||||
|
return ScriptExecutor(alterations = alterations).run(block)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.pixelized.rplexicon.script
|
||||||
|
|
||||||
|
class ScriptParser {
|
||||||
|
companion object {
|
||||||
|
private val FUNCTION_REGEX = Regex("""^(\w+)\((?:(.*);(.*)|(.*))\)$""")
|
||||||
|
|
||||||
|
private const val AND = "AND"
|
||||||
|
private const val OR = "OR"
|
||||||
|
private const val IS_ACTIVE = "ACT"
|
||||||
|
private const val ANY = "ANY"
|
||||||
|
private const val NOT = "NOT"
|
||||||
|
private const val NONE = "NONE"
|
||||||
|
|
||||||
|
fun check(function: String, vararg params: String?, block: () -> Script): Script {
|
||||||
|
if (params.any { it.isNullOrEmpty() }) error("$function parameter malformed")
|
||||||
|
return block.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parse(value: String): Script {
|
||||||
|
val result = FUNCTION_REGEX.findAll(value)
|
||||||
|
|
||||||
|
return result.firstOrNull()?.let { matchResult ->
|
||||||
|
val (function, param1, param2, mono) = matchResult.destructured
|
||||||
|
when (function) {
|
||||||
|
AND -> check(AND, param1, param2) { Script.AND(parse(param1), parse(param2)) }
|
||||||
|
OR -> check(OR, param1, param2) { Script.OR(parse(param1), parse(param2)) }
|
||||||
|
IS_ACTIVE -> check(IS_ACTIVE, mono) { Script.ACTIVE(mono) }
|
||||||
|
ANY -> check(ANY, mono) { Script.ANY(mono) }
|
||||||
|
NOT -> check(NOT, mono) { Script.NOT(mono) }
|
||||||
|
NONE -> check(NONE, mono) { Script.NONE(mono) }
|
||||||
|
else -> error("Unrecognized function: $function")
|
||||||
|
}
|
||||||
|
} ?: error("Malformed script: should start with a function call.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val parser = ScriptParser()
|
||||||
|
val script = listOf(
|
||||||
|
"""ACT(Hache de guerre en argent)""",
|
||||||
|
"""ACT(Forme sauvage : Loup)""",
|
||||||
|
"""ACT(Forme sauvage ; Chat)""",
|
||||||
|
"""AND(ACT(Hache de guerre en argent);NOT(Bouclier))""",
|
||||||
|
"""OR(AND(NOT(Hache);ACT(Épée));ACT(Bouclier))""",
|
||||||
|
"""NONE(Forme sauvage)""",
|
||||||
|
)
|
||||||
|
script.forEach {
|
||||||
|
println("Input << $it")
|
||||||
|
try {
|
||||||
|
println("Output >> ${parser.parse(it)}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Output >> $e")
|
||||||
|
} finally {
|
||||||
|
println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue