Skip to content

Instantly share code, notes, and snippets.

@programaths
Created May 31, 2017 19:39
Show Gist options
  • Select an option

  • Save programaths/e96e86be51d6a7424f6e9787a40271df to your computer and use it in GitHub Desktop.

Select an option

Save programaths/e96e86be51d6a7424f6e9787a40271df to your computer and use it in GitHub Desktop.
An example of text adventure in Kotlin
/*
* This file implement a very simple text game engine and a DSL.
*/
fun main(args: Array<String>) {
val game=Branch("You awake in a dark forest. Where do you want to go ?"){
WalkNorth() leadsTo TerminalBranch("You went too far in the dark and have been killed by a somber creature")
WalkSouth() leadsTo TerminalBranch("You just fel from a cliff. Dumb move !")
WalkEast() leadsTo Branch("""In front of you is a yellowish box.
It really stand out from the night."""){
OpenAction() leadsTo TerminalBranch("A snake pop out of the box and bite you. You die of a painful poisoning!")
val startOfBridgeref:RefBranch=RefBranch(Branch())
val startOfBridge=Branch("You are facing a very old bridge."){
WalkNorth() leadsTo Branch("you are in the middle of a very old bridge"){
WalkSouth() leadsTo startOfBridgeref
WalkNorth() leadsTo Branch("Congratulation, you crossed the bridge and are out of the forest !")
}
}
startOfBridgeref.ref=startOfBridge // Little hack to pass a reference to a closure
WalkNorth() leadsTo startOfBridge
}
}
game.process()
}
interface Action{
val label:String
fun accept(input :String):Boolean
}
abstract class SimpleAction(override val label: String):Action{
override fun accept(input: String) = label == input
}
class OpenAction:SimpleAction("OPEN")
class CloseAction:SimpleAction("CLOSE")
class HitAction:SimpleAction("HIT")
abstract class WalkAction(val direction:String):Action{
override val label: String = "WALK $direction"
override fun accept(input: String): Boolean {
val (iaction,idirection)=input.replace(Regex.fromLiteral(" {2,}")," ").split(" ")
return iaction=="WALK" && direction==idirection
}
}
class WalkNorth:WalkAction("NORTH")
class WalkSouth:WalkAction("SOUTH")
class WalkEast:WalkAction("EAST")
class WalkWest:WalkAction("WEST")
interface IBranch {
val description: String
val fn: IBranch.() -> Unit
fun process()
infix fun Action.leadsTo(brc: IBranch)
}
open class Branch(override val description:String="", override val fn:IBranch.()->Unit={}) : IBranch {
val actions:MutableList<Pair<Action,IBranch>> = mutableListOf()
var visited=false
override fun process() {
if (!visited) this.fn()
visited=true
println(description)
print("The following are available: \n- ${actions.map { it.first.label }.joinToString("\n- ")}\n> ")
var input= readLine() ?: ""
var processed = actions.find { it.first.accept(input) }?.second?.run { process(); true }?:false
while (!processed){
input= readLine() ?: ""
processed = actions.find { it.first.accept(input) }?.second?.run { process(); true }?:false
}
}
override infix fun Action.leadsTo(brc:IBranch){
actions.add(this to brc)
}
}
class RefBranch(var ref:Branch=Branch()):IBranch {
override val fn: IBranch.() -> Unit
get() = ref.fn
override val description: String
get() = ref.description
override fun process() {
ref.process()
}
override fun Action.leadsTo(brc: IBranch) {
ref.actions.add(this to brc)
}
}
class TerminalBranch(val ending:String):Branch(){
override fun process(){
println(ending)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment