diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/DebugTree.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/DebugTree.java index 55499c2..20847d2 100644 --- a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/DebugTree.java +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/DebugTree.java @@ -8,14 +8,15 @@ public class DebugTree { static class NodeInfo { int indent; public Node node; - Node.State state = Node.State.RUNNING; + Node.State state; - NodeInfo(int indent, Node node){ + NodeInfo(int indent, Node node) { this.indent = indent; this.node = node; + state = Node.State.RUNNING; } - public String toString(){ + public String toString() { String prefix = new String(new char[indent]).replace("\0", "-"); String name = node.getClass().getSimpleName(); @@ -26,32 +27,36 @@ public String toString(){ return prefix + name + ":S\n"; case RUNNING: return prefix + name + ":R\n"; + default: + return ""; } - return ""; } } List nodeInfoList; Stack parents = new Stack<>(); - public DebugTree(){ + public DebugTree() { reset(); } - public void reset(){ + + public void reset() { nodeInfoList = new LinkedList<>(); parents = new Stack<>(); } - public void startParent(Node parent){ + + public void startParent(Node parent) { parents.push(parent); } - public void addNode(Node node){ + public void addNode(Node node) { nodeInfoList.add(new NodeInfo(parents.size(), node)); } - public void updateNode(Node node, Node.State newState){ + public void updateNode(Node node, Node.State newState) { if (node == parents.peek()){ parents.pop(); } + for (NodeInfo nodeInfo : nodeInfoList){ if(nodeInfo.node == node){ nodeInfo.state = newState; @@ -59,11 +64,12 @@ public void updateNode(Node node, Node.State newState){ } } - public String toString(){ + public String toString() { StringBuilder retString = new StringBuilder(); - for(NodeInfo nodeInfo : nodeInfoList){ + for(NodeInfo nodeInfo : nodeInfoList) { retString.append(nodeInfo.toString()); } + return retString.toString(); } } diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Failover.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Fallback.java similarity index 65% rename from behaviortrees/src/main/java/com/ftcteams/behaviortrees/Failover.java rename to behaviortrees/src/main/java/com/ftcteams/behaviortrees/Fallback.java index 644da0a..097e316 100644 --- a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Failover.java +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Fallback.java @@ -7,27 +7,27 @@ * Failover means that as soon as it hits a child with SUCCESS it returns SUCCESS. If a child is RUNNING, * it returns RUNNING. If all children return FAILURE, it returns FAILURE */ -public class Failover extends Node { +public class Fallback extends Node { List children; - public Failover(Node ... a) { + public Fallback(Node ... a) { this.children = Arrays.asList(a); } @Override public State tick(DebugTree debug, Object obj) { debug.startParent(this); + State state = State.FAILURE; + for (Node child : children) { debug.addNode(child); - State state = child.tick(debug, obj); + state = child.tick(debug, obj); debug.updateNode(child, state); - if (state == State.SUCCESS) { - return State.SUCCESS; - } else if (state == State.RUNNING) { - return State.RUNNING; + if (state == State.SUCCESS || state == State.RUNNING) { + break; } } - return State.FAILURE; + return state; } } diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Not.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Not.java index b7a86f8..15bc586 100644 --- a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Not.java +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Not.java @@ -6,20 +6,21 @@ public class Not extends Node { Node child; - public Not(Node a) { - this.child = a; + public Not(Node child) { + this.child = child; } @Override public State tick(DebugTree debug, Object obj) { State state = child.tick(debug, obj); - - if (state == State.FAILURE) { - return State.SUCCESS; - } else if (state == State.SUCCESS) { - return State.FAILURE; + + switch (state) { + case State.SUCCESS: + return State.FAILURE; + case State.FAILURE: + return State.SUCCESS; + case State.RUNNING: + return State.RUNNING; } - - return state; } } diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Parallel.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Parallel.java index 0a2d29d..98ae6c3 100644 --- a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Parallel.java +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Parallel.java @@ -7,7 +7,9 @@ * This executes all of the children and if more than the required succcesses are successful it returns * SUCCESS. Otherwise it returns RUNNING until all are done and then it returns FAILURE. * - * NOTE: right now it will keep running even if there is no way it could be successful + * If it is impossible the required number of successes to be met, it will return FAILURE early. + * + * If you need RUNNING children to finish even if Paralle will return FAILURE, instead use ParallelNoBail. */ public class Parallel extends Node { List children; @@ -21,25 +23,32 @@ public Parallel(int requiredSuccesses, Node ... a) { @Override public State tick(DebugTree debug, Object obj) { int numSuccessful = 0; - boolean anyRunning = false; + int numFailed = 0; + debug.startParent(this); + for (Node child : children) { debug.addNode(child); State state = child.tick(debug, obj); debug.updateNode(child, state); - if (state == State.SUCCESS) { - numSuccessful += 1; - if (numSuccessful >= requiredSuccesses){ - return State.SUCCESS; - } - } else if (state == State.RUNNING) { - anyRunning = true; + switch (state) { + case SUCCESS: + numSuccessful++; + if (numSuccesful >= requiredSuccesses) { + return State.SUCCESS; + } + break; + + case FAILURE: + numFailed++; + if (children.size() - numFailed > requiredSuccesses) { + return State.FAILURE; + } + break; } } - if (anyRunning){ - return State.RUNNING; - } - return State.FAILURE; + + return State.RUNNING; } } diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/ParallelNoBail.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/ParallelNoBail.java new file mode 100644 index 0000000..2c337dc --- /dev/null +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/ParallelNoBail.java @@ -0,0 +1,46 @@ +package com.ftcteams.behaviortrees; + +import java.util.Arrays; +import java.util.List; + +/** + * This executes all of the children and if more than the required succcesses are successful it returns + * SUCCESS. Otherwise it returns RUNNING until all are done and then it returns FAILURE. + * + * It will keep running even if there is no way it could be successful. If you want the program to bail early + * if it cannot succeed, use Parallel instead. + */ +public class ParallelNoBail extends Node { + List children; + int requiredSuccesses; + + public ParallelNoBail(int requiredSuccesses, Node ... a) { + this.children = Arrays.asList(a); + this.requiredSuccesses = requiredSuccesses; + } + + @Override + public State tick(DebugTree debug, Object obj) { + int numSuccessful = 0; + boolean anyRunning = false; + debug.startParent(this); + for (Node child : children) { + debug.addNode(child); + State state = child.tick(debug, obj); + debug.updateNode(child, state); + + if (state == State.SUCCESS) { + numSuccessful += 1; + if (numSuccessful >= requiredSuccesses){ + return State.SUCCESS; + } + } else if (state == State.RUNNING) { + anyRunning = true; + } + } + if (anyRunning){ + return State.RUNNING; + } + return State.FAILURE; + } +} diff --git a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Sequence.java b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Sequence.java index 4642ebe..bee9b0e 100644 --- a/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Sequence.java +++ b/behaviortrees/src/main/java/com/ftcteams/behaviortrees/Sequence.java @@ -16,18 +16,17 @@ public Sequence(Node ... a) { @Override public State tick(DebugTree debug, Object obj) { debug.startParent(this); + State state = State.SUCCESS; for (Node child : children) { debug.addNode(child); - State state = child.tick(debug, obj); + state = child.tick(debug, obj); debug.updateNode(child, state); - if (state == State.FAILURE) { - return State.FAILURE; - } else if (state == State.RUNNING) { - return State.RUNNING; + if (state == State.FAILURE || state == State.RUNNING) { + break; } } - return State.SUCCESS; + return state; } }