exaV / screeps-kotlin-types

Screep's Kotlin type definitions
MIT License
17 stars 18 forks source link

Implement Game.Map #7

Closed Jomik closed 6 years ago

Jomik commented 6 years ago

We moved interfaces inside of Game to better illustrate where they are used. Changed GameMap to be an interface and not a class. The important change is making findRoute an extension function. We do this to be able to wrap it in an Either, to allow returning both types of result. We also create a function to easily create the options object.

Jomik commented 6 years ago

We have some options with how to handle a union type return value: With extension functions on the return value of findRoute:

interface Game {
  interface Map {
    fun findRoute(
        fromRoom: String,
        toRoom: String,
        opts: Game.Map.RouteOptions? = definedExternally
    ): FindRouteResult
  }
}

external interface FindRouteResult

inline val FindRouteResult.error: ScreepsReturnCode
    get() = (this as? Number).unsafeCast<ScreepsReturnCode>()

inline val FindRouteResult.route: Array<Game.Map.RouteResult>?
    get() = (this as? Array<*>).unsafeCast<Array<Game.Map.RouteResult>?>()

With extension functions on the Game.Map interface:

sealed class Either<out L, out R> {
    open val left: L? = null
    open val right: R? = null

    class Left<out L>(override val left: L) : Either<L, Nothing>() {
        val value get() = left
    }

    class Right<out R>(override val right: R) : Either<Nothing, R>() {
        val value get() = right
    }
}

fun Game.Map.findRoute(
    var name: String
    fromRoom: String,
    var type: String
    toRoom: String,
    var ptr: Boolean
    opts: Game.Map.RouteOptions? = null
): Either<ScreepsReturnCode, Array<Game.Map.RouteResult>> {
    val result = this.asDynamic().findRoute(fromRoom, toRoom, opts)
    return if (result is Number)
        Left(result.unsafeCast<ScreepsReturnCode>())
    else Right(result.unsafeCast<Array<Game.Map.RouteResult>>())
}
fun Game.Map.findRoute(
    fromRoom: String,
    toRoom: String,
    opts: Game.Map.RouteOptions? = null
): Array<Game.Map.RouteResult>? =
    this.asDynamic().findRoute(fromRoom, toRoom, opts) as? Array<Game.Map.RouteResult>

The last one has the issue that it converts both ERR_NO_PATH and ERR_INVALID_ARGS into one error.