Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
kotlin("jvm") version "1.8.10"
kotlin("plugin.serialization") version "1.8.10"
}

group = "com.tpcly"
Expand All @@ -10,6 +11,7 @@ repositories {
}

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
testImplementation(kotlin("test"))
testImplementation("io.mockk:mockk:1.13.7")
}
Expand Down

This file was deleted.

9 changes: 9 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/Conditional.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.tpcly.behaviourtree

abstract class Conditional : TreeNode {
abstract fun validate(): Boolean

override fun execute(): TreeNodeStatus {
return TreeNodeStatus.fromBoolean(validate())
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/Inverter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tpcly.behaviourtree

import kotlinx.serialization.Serializable

@Serializable
data class Inverter(
override val child: TreeNode,
) : TreeNode.Decorator {
override fun execute(): TreeNodeStatus {
return when (val result = child.execute()) {
TreeNodeStatus.SUCCESS -> TreeNodeStatus.FAILURE
TreeNodeStatus.FAILURE -> TreeNodeStatus.SUCCESS
else -> result
}
}
}
29 changes: 29 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/RepeatUntil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.tpcly.behaviourtree

import kotlinx.serialization.Serializable

@Serializable
data class RepeatUntil(
override val child: TreeNode,
val targetStatus: TreeNodeStatus = TreeNodeStatus.SUCCESS,
val limit: Int = 10,
) : TreeNode.Decorator {
override fun execute(): TreeNodeStatus {
var iteration = 0
var currentStatus: TreeNodeStatus

do {
currentStatus = child.execute()
iteration++
} while (
currentStatus != targetStatus &&
currentStatus != TreeNodeStatus.ABORT &&
iteration < limit
)

return when {
iteration >= limit -> TreeNodeStatus.FAILURE
else -> currentStatus
}
}
}
26 changes: 26 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/Selector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tpcly.behaviourtree

import kotlinx.serialization.Serializable

@Serializable
data class Selector(
val executionOrder: TreeExecutionOrder,
override val children: List<TreeNode>,
) : TreeNode.Composite {
override fun execute(): TreeNodeStatus {
val children = when (executionOrder) {
TreeExecutionOrder.RANDOM -> children.shuffled()
else -> children
}

for (child in children) {
val result = child.execute()

if (result == TreeNodeStatus.SUCCESS || result == TreeNodeStatus.ABORT) {
return result
}
}

return TreeNodeStatus.FAILURE
}
}
26 changes: 26 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/Sequencer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tpcly.behaviourtree

import kotlinx.serialization.Serializable

@Serializable
data class Sequencer(
val executionOrder: TreeExecutionOrder,
override val children: List<TreeNode>,
) : TreeNode.Composite {
override fun execute(): TreeNodeStatus {
val children = when (executionOrder) {
TreeExecutionOrder.RANDOM -> children.shuffled()
else -> children
}

for (child in children) {
val result = child.execute()

if (result == TreeNodeStatus.FAILURE || result == TreeNodeStatus.ABORT) {
return result
}
}

return TreeNodeStatus.SUCCESS
}
}
15 changes: 0 additions & 15 deletions src/main/kotlin/com/tpcly/behaviourtree/Status.kt

This file was deleted.

13 changes: 13 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/Succeeder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tpcly.behaviourtree

import kotlinx.serialization.Serializable

@Serializable
data class Succeeder(
override val child: TreeNode,
) : TreeNode.Decorator {
override fun execute(): TreeNodeStatus {
child.execute()
return TreeNodeStatus.SUCCESS
}
}
57 changes: 57 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/TreeBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.tpcly.behaviourtree

object TreeBuilder {
/**
* Pre-defined leaf nodes
*/
fun action(execute: () -> TreeNodeStatus): TreeNode = object : TreeNode {
override fun execute(): TreeNodeStatus = execute()
}

fun conditional(validate: () -> Boolean): TreeNode = object : TreeNode {
override fun execute(): TreeNodeStatus = TreeNodeStatus.fromBoolean(validate())
}

fun perform(execute: () -> Unit): TreeNode = object : TreeNode {
override fun execute(): TreeNodeStatus {
execute()
return TreeNodeStatus.SUCCESS
}
}

/**
* Composite nodes
*/
fun selector(
executionOrder: TreeExecutionOrder = TreeExecutionOrder.IN_ORDER,
init: TreeNodeCompositeBuilder.() -> Unit,
): Selector {
val builder = TreeNodeCompositeBuilder().apply(init)
return Selector(executionOrder, builder.build())
}

fun sequencer(
executionOrder: TreeExecutionOrder = TreeExecutionOrder.IN_ORDER,
init: TreeNodeCompositeBuilder.() -> Unit,
): Sequencer {
val builder = TreeNodeCompositeBuilder().apply(init)
return Sequencer(executionOrder, builder.build())
}

/**
* Decorator nodes
*/
fun inverter(init: () -> TreeNode) = Inverter(init())

fun TreeNode.inverted() = Inverter(this)

fun succeeder(init: () -> TreeNode) = Succeeder(init())

fun failer(init: () -> TreeNode) = succeeder(init).inverted()

fun repeatUntil(
status: TreeNodeStatus = TreeNodeStatus.SUCCESS,
limit: Int = 10,
init: () -> TreeNode,
) = RepeatUntil(init(), status, limit)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.tpcly.behaviourtree

enum class ExecutionOrder {
enum class TreeExecutionOrder {
IN_ORDER,
RANDOM
}
21 changes: 21 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/TreeNode.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.tpcly.behaviourtree

interface TreeNode {
fun execute(): TreeNodeStatus

interface Composite : TreeNode {
val children: List<TreeNode>
}

interface Decorator : TreeNode {
val child: TreeNode
}

interface Sub : TreeNode {
val root: TreeNode

override fun execute(): TreeNodeStatus {
return root.execute()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tpcly.behaviourtree

class TreeNodeCompositeBuilder {
private val children: MutableList<TreeNode> = mutableListOf()

operator fun TreeNode.unaryPlus() {
children += this
}

operator fun TreeNode.unaryMinus() {
children -= this
}

fun build(): List<TreeNode> {
return children.toList()
}
}
31 changes: 0 additions & 31 deletions src/main/kotlin/com/tpcly/behaviourtree/TreeNodeResult.kt

This file was deleted.

11 changes: 11 additions & 0 deletions src/main/kotlin/com/tpcly/behaviourtree/TreeNodeStatus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.tpcly.behaviourtree

enum class TreeNodeStatus {
SUCCESS,
FAILURE,
ABORT;

companion object {
fun fromBoolean(value: Boolean): TreeNodeStatus = if (value) SUCCESS else FAILURE
}
}
Loading