Skip to content

Instantly share code, notes, and snippets.

@Larkenx
Last active June 30, 2018 00:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Larkenx/5e1007eac05768865a77f5d2e75a5cda to your computer and use it in GitHub Desktop.
Save Larkenx/5e1007eac05768865a77f5d2e75a5cda to your computer and use it in GitHub Desktop.
A priority queue based turn scheduling system in Kotlin based on this article http://roguebasin.com/index.php?title=A_priority_queue_based_turn_scheduling_system
import java.util.*
import kotlin.collections.HashMap
/**
* An interface for "actors" or entities to implement so that all actors have a speed property
*/
interface Actor {
abstract var speed: Int
}
/**
* A class to wrap around a Priority Queue for scheduling actors, with a comparator
* that focuses on the Actor's speed
* @property queue the internal priority queue that manages the turn order
* @property baseTime the base speed of all actors - the speed of an actor
* is actually used as a divisor against the base time to determine an actor's initial turn delay
*/
open class TimeScheduler {
val baseTime: Int = 10
data class TurnEvent(val actor: Actor, var delay: Int)
private val queue: PriorityQueue<TurnEvent> = PriorityQueue(11, object : Comparator<TurnEvent> {
override fun compare(a1: TurnEvent, a2: TurnEvent): Int = if (a1.delay == a2.delay) -1 else a1.delay - a2.delay
})
fun addActor(actor: Actor) = queue.add(TurnEvent(actor, baseTime / actor.speed))
fun removeActor(actorToRemove: Actor) = queue.removeIf { (actor): TurnEvent -> actor === actorToRemove }
fun adjustPriorities(time: Int) = queue.forEach { event: TurnEvent -> event.delay += time }
fun nextTurn(): Actor {
val (actor, delay) = queue.poll()
adjustPriorities(-delay)
addActor(actor)
return actor
}
public fun nextTurnWithTurnEvent() : TurnEvent {
val turnEvent = queue.poll()
val (actor, delay) = turnEvent
adjustPriorities(-delay)
addActor(actor)
return turnEvent
}
}
import com.mygdx.game.scheduler.TimeScheduler
import org.junit.Before as before
import org.junit.Test as test
class TimeSchedulerTest {
lateinit var timeScheduler: TimeScheduler
lateinit var actors: ArrayList<Actor>
@before fun setup() {
timeScheduler = TimeScheduler()
actors = ArrayList()
}
@test fun testAddActor() {
val turnRounds: Int = 3
val player1 = object: Actor { override var speed = 1 }
val player2 = object: Actor { override var speed = 2 }
val player3 = object: Actor { override var speed = 1 }
timeScheduler.addActor(player1)
timeScheduler.addActor(player2)
timeScheduler.addActor(player3)
val table: HashMap<Actor, Int> = HashMap()
table.put(player1, 0)
table.put(player2, 0)
table.put(player3, 0)
var turns: Int = player1.speed + player2.speed + player3.speed
turns *= turnRounds
println("Running $turns rounds")
for (i in 1..turns) {
var turns: Int = player1.speed + player2.speed + player3.speed
turns *= turnRounds
val (actor, delay) = timeScheduler.nextTurnWithTurnEvent()
if (table.containsKey(actor)) {
val count: Int = table.get(actor) as Int
table.put(actor, count + 1)
}
}
for ((actor, count) in table.entries) {
println("${actor.name} took $count turns")
assert(count == actor.speed * turnRounds)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment