Jump to content
Sign in to follow this  
wastedbro

Decision Tree Framework

Recommended Posts

Decision Tree Framework by wastedbro

 

Hello everyone,

While working on some very large scripts, I realized that the current accepted frameworks scale poorly with many tasks, and that I have to choose between cleanliness and efficiency. Due to this, I've been working on a new framework that I am writing about here.

Here is the Source, for Reference: https://github.com/WBScripts/Tree-Framework

Summary

So the decision tree framework is based on, well, The Decision Tree.

My framework uses this concept and implements a Binary Tree of Decisions and Actions. Both decisions and actions are Nodes. Nodes can have 2 children. Actions will have null children, and Decisions will have 2 children of either Decisions, or Actions. I know it sounds a little confusing, so let's talk about why we even need this.

 

Why not use the popular Node Framework?

The Node Framework is a great way to split up a large amount of code. However, there is a problem. Even though each node is a different class, they really aren't flexible. If we assume each node is completely independent and isolated, we must ensure it's an invalid node when another node is valid, which is a huge waste of resources. If we do not do this, we must ensure our nodes are checked in a specific order (or prioritized).

While prioritized nodes prevent wasteful duplicate checks, it still does not prevent all wasteful checks. And it certainly cannot be in-depth. For example, if you want a "Pick up birds nest" node and a "chop node", you must ensure both of their validation methods include "is in chopping area". That's wasteful, so putting them in the same node is the only option.

These problems are not a big deal in small scripts, but as the complexity grows, so do these problems.

 

Here's a visual comparison of the Frameworks in a Combat Script:

Node Framework

Ldh586TUQciqMrKhm11CNQ.png

 

As you can see, both of the first nodes include an Area Check. This is either solved by combining the Nodes or ensuring they always run in that order (and then you would be unable to re-use the nodes without including them all).

Also, let's say you start this script in the bank. It checks if it needs to eat. Why? We're in the bank. We could put the Banking Node first, but then we run the risk of the Eating Node not being fast enough once we start adding complexity. 

Oh, and let's say we want to add a Gear Upgrade feature. Well, how would we do that? Upgrading gear is really only done in the bank, so we could have two nodes that check a banking condition..... Well, that makes our valid() methods bloated and repetitive. So, I guess we just have to put them in the same node...

All of this can be solved with my framework.

 

 

Decision Tree Framework

x5Ss1L_lQIWiGRcqJya9Rw.png

 

As you can see, this framework is much different. It allows you to nest in logic. In this framework, our script will never even check the HP unless we meet a bunch of other conditions. Yet, we still have a direct path to the eating method, making it the number one priority where we can be attacked.

Now, if we want to add gear upgrading, we would simply add the nodes under the Banking part of the script. Now we can add functionality with touching our old code. This decreases regression bugs.

 

So how do I use this?

Well, let's show you how to create some Nodes.

Decision Node Example:

public class HasToBankNode extends DecisionNode
{
    @Override
    public boolean isValid()
    {
        return Banking.isBankScreenOpen() || Inventory.isFull();
    }
}

Important: Remember to include "extends DecisionNode"

Every Node has a "getValidNode()" Method. This method will check the "onValid" method and return the true node if it's valid. If not, it will return the false node.

 

Process Node Example:

public class BankNode extends ProcessNode
{
    @Override
    public String getStatus()
    {
        return "Banking";
    }

    @Override
    public void execute()
    {
        // Do bank stuff
    }
}

Decision Nodes must have these two methods to run.

 

How do we run these nodes?

Here's an example:

DecisionNode hasToBankNode = new HasToBankNode();

ProcessNode bankNode = new BankNode();

hasToBankNode.addOnTrueNode(bankNode);
hasToBankNode.addOnFalseNode([insert some other node]);

DecisionTree executionTree = new DecisionTree(hasToBankNode); // Create a tree from the root node

while(true)
{
    INode node = executionTree.getValidNode();
    if(node != null)
        node.execute();
}

That's it! You'll want to shorten this code once you have a lot of nodes, though.

All of the background stuff is handled for you! The "getValidNode()" method is recursive. It will go through the entire tree and pick the correct process node for you.

 

This framework has more features. I will try to write a tutorial for them soon.

 

Github Link: https://github.com/WBScripts/Tree-Framework

Edited by Fluffee
Wrong constructor on the DecisionTree creation.
  • Thanks 3

Share this post


Link to post
Share on other sites
37 minutes ago, HeyImJamie said:

May look to transferring to this. Is it limited to two process nodes per decision node or not? For example: a combat decision node could have a handleAntiban, shouldEat, attackNpc etc.

Would you just add another decision node like
inCombatArea - yes
isLowHP - no
shouldDoAntiban - no Attack or yes doAntiban
 

Share this post


Link to post
Share on other sites
4 hours ago, HeyImJamie said:

May look to transferring to this. Is it limited to two process nodes per decision node or not? For example: a combat decision node could have a handleAntiban, shouldEat, attackNpc etc.

A binary tree of decisions and actions is by definition only able choose between two different alternatives on each node.

Multiple decisions could be added in a hierarchical order. For example if you need to chose between 3 actions: "Chop down tree", "Perform anti-ban" and "Idle":

KcCfB1y.png

 

  • Like 2

Share this post


Link to post
Share on other sites
On 19.12.2017 at 1:37 AM, wastedbro said:

 

How do we run these nodes?

Here's an example:

DecisionNode hasToBankNode = new HasToBankNode();

ProcessNode bankNode = new BankNode();

hasToBankNode.addOnTrueNode(bankNode);
hasToBankNode.addOnFalseNode([insert some other node]);

DecisionTree executionTree = new DecisionTree(hasToBankNode); // Create a tree from the root node

while(true)
{
    INode node = executionTree.getValidNode();
    if(node != null)
        node.execute();
}

That's it! You'll want to shorten this code once you have a lot of nodes, though.

All of the background stuff is handled for you! The "getValidNode()" method is recursive. It will go through the entire tree and pick the correct process node for you.

 

 

Well thanks for your effort, but ... is this part of some main class or something?

it's a piece of code that should belong to somewhere, and I couldn't find it either on your github.

Share this post


Link to post
Share on other sites
Posted (edited)
1 hour ago, rstaiger said:

Well thanks for your effort, but ... is this part of some main class or something?

it's a piece of code that should belong to somewhere, and I couldn't find it either on your github.

It's an example that would go in your main class. It's hypothetical, and builds off the two classes also in the thread. They are non-functional examples, just to show you how the code works, so it's not actually IN anything. 

 

By the way, I have an update to this framework. It's now simpler. I will edit the main post and write a tutorial on it when I can.

 

Here is the link: https://github.com/WBScripts/DecisionTree-Framework

 

Basically, Process Node are now just classes that implement "Runnable". And DecisionNodes are a little simpler.

Edited by wastedbro
  • Like 1

Share this post


Link to post
Share on other sites
On 4.03.2018 at 4:58 PM, wastedbro said:

It's an example that would go in your main class. It's hypothetical, and builds off the two classes also in the thread. They are non-functional examples, just to show you how the code works, so it's not actually IN anything. 

 

By the way, I have an update to this framework. It's now simpler. I will edit the main post and write a tutorial on it when I can.

 

Here is the link: https://github.com/WBScripts/DecisionTree-Framework

 

Basically, Process Node are now just classes that implement "Runnable". And DecisionNodes are a little simpler.

can't really wrap my head around this, It would be nice to have some working examples I'll wait for some updates from you, I'll toy with the task framework till then.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×