User:Bnorm/CoroutineRobot
Jump to navigation
Jump to search
CoroutineRobot
Using Kotlin and coroutines, safe and fair multithreading for a Robot can be implemented in Robocode. This can be achieved with structured concurrency and a custom thread dispatcher.
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.runBlocking
import robocode.AdvancedRobot
import java.util.concurrent.LinkedBlockingQueue
import kotlin.concurrent.thread
import kotlin.coroutines.CoroutineContext
abstract class CoroutineRobot : AdvancedRobot() {
private val _computation = QueueCoroutineDispatcher(4)
val Computation: CoroutineDispatcher get() = _computation
private lateinit var _main: CoroutineDispatcher
val Main: CoroutineDispatcher get() = _main
final override fun run() {
try {
runBlocking {
_main = coroutineContext[CoroutineDispatcher]!!
coroutineRun()
}
} finally {
_computation.shutdown()
}
}
abstract suspend fun coroutineRun()
private class QueueCoroutineDispatcher(threadCount: Int) : CoroutineDispatcher() {
private val queue = LinkedBlockingQueue<Runnable?>()
private val threads = List(threadCount) {
thread(name = "Computation $it") {
try {
while (true) {
val task = queue.take() ?: break
task.run()
}
} catch (ignore: InterruptedException) {
// ignore
}
}
}
override fun dispatch(context: CoroutineContext, block: Runnable) {
queue.put(block)
}
fun shutdown() {
repeat(threads.size) {
// poison the queue once for each thread
queue.put(null)
}
}
}
}
Multithreading
With the above base class multithreading can be achieved using coroutineScope, launch, and withContext builder functions.
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SampleRobot : CoroutineRobot() {
override suspend fun coroutineRun() {
while (true) {
coroutineScope { // Starts a logic container for asynchronous work
launch(Computation) { // Launch asynchronous work on 1 of the 4 computation threads
// Do radar logic
withContext(Main) { // Switch back to run thread
setTurnRadarRightRadians(radarTurn)
}
}
launch(Computation) { // Launch asynchronous work on 1 of the 4 computation threads
// Do firing logic
withContext(Main) { // Switch back to run thread
setTurnGunRightRadians(gunTurn)
setFire(bulletPower)
}
}
launch(Computation) { // Launch asynchronous work on 1 of the 4 computation threads
// Do movement logic
withContext(Main) { // Switch back to run thread
setTurnRightRadians(tankTurn)
setAhead(tankMove)
}
}
}
execute()
}
}
}