How the AI works and How to Trim it

Your bot's Controller is the Brain or Computer of your Robot. There are several controllers to choose from in several different racial categories. Each one is unique in its various attributes such as Shape, Attachment Points, cost, Weight, Health, and Decisions per Second.

Controller Attribute Box How it all works
The Decisions per Second is the bread and butter of your Controller. This tells you how fast your bot is going to think and be able to react to it's environment. If your bot is thinking too slow then it may not react in time to events going on around it, often attacking a no longer present enemy or running into a wall that wasnt there a moment ago.

Each controller is rated in Decisions per Second. This represents how many decisions your bot can make in one second. CONTRARY to popular belief, every line of your AI code is treated as a decision. Group nodes, Orients, Moves, Variable Nodes, all of them count against you when you are tallying your decision count. Many people believe they need only count their Y/N querries, but this is not true. Perhaps RF will either change the counting method or rename the "Decisions/s" attribute to "AI Lines/s" in the future to save confusion. The only effect Y/N nodes have in your AI during the count is that only active events are counted. In other words if you ask "Is the enemy less than 10 feet away?" and have a Move of "Attack" if true or "Approach" if False, then this constitutes as 2 decisions : The query and the resulting responce. I'll go into more on this later.

Each second of game time is broken up into 15 time slices. This is simply how often Roboforge itself samples the arena world to update variables, do the math, and redraw everything. Knowing this we can determine how many lines of your code will be processed each timeslice of the game. Just take the Decisions per Second value and divide it by 15. So we find that our 150 decision bot can read 10 lines of code each timeslice (or frame if that word makes more sense).

When the fight begins the first 10 lines of code are read by your controller, all the world variables are updated and it attempts to perform any actions it is told to do in those first 10 lines. The next timeslice the next 10 lines of code are read BUT THE WORLD VARIABLES REMAIN THE SAME! This is very important to be aware of. Until the top of your AI is read again, the World Variable items do not change from their last reading. Your bot will always react to the conditions found when your AI starts at the top.

Each timeslice the next 10 lines of code are read until you reach the end where it starts over. If 10 decisions are being read and you only have 3 lines of code left in your AI, then we start back up at the top (updating the World Variables) with the remaining 7 decisions.

Don't get confused. If you count out your lines of code and find 150 lines in your AI this DOES NOT mean that your AI will take a full second to process the entire AI each second, nor does this mean that reads the first 10 listed lines of code it comes across each timeslice. It's quite possible to trim your AI so well that even having 500 lines of code still allows your entire AI to be processed each second.

So let's get to Trimming!
The first thing to do when trimming AI is getting rid of those useless Group Nodes. Before RF version 1.33 people used the group nodes liberally to help in tagging different sections of thier AI for easy reference. But with the current fix on controllers this is now a big mistake as each Group Node is counted as a decision. In the example below we see an AI that uses Orients to simply face the enemy and then move toward them. This AI is included in Roboforge as an AI block as well.

AI with cluttered use of Group NodesSame AI Efficiently Trimmed
On the Left we see a liberal usage of Group Nodes. Because of these Nodes, this AI requires 6 decsions if even only one of the two states is true (The Start Node is counted as well) and 9 decisions if both are being used! By trimming this AI code of all useless Group Nodes you see (in the Right Image) that now only 3 decision are required if one query is true and a Maximum of 5 decisions if BOTH are used.

The trimmed AI model on the right requires only a maximum of 5 decisions while the clunky AI model on the left require 6 minimum decisions! I think you can quickly grasp that cleaning up much larger AI's like this could result in AI processing speeds several times faster!

Once you've cleaned out all the useless Group Nodes, what else can you do to Trim your AI more efficiently? Well, alot of this is going to depend on your style of AI coding. Everyone has a different style and like to process things in a particular order. One thing to keep in mind when writing your AI is that you may want to have crucial reactive events happen near the top of the AI. This way you react immediatly upon detecting a situation and when the World Variables are still fresh rather than a few timeslices later.

Ordering your queries correctly can vastly trim your AI. As an example, checking to see if your bot has detected the enemy several times thru your code is a waste of decisions. If at all possible, make such a check once and place any further actions dependant upon the answer in the Yes or No section of the Question Node. It will also be a good idea to conglomerate queries into a single querry if at all possible. Sometimes you can actualy create MORE code lines to conserve on decision time.

Enemy.isDetected?
    Y - me.angleToEnemy < 5 or me.angleToEnemy > 355
        Y - me.distanceToEnemy > 10
            Y - ChassisMove : Forward 5
            N
        N
    N

This statement checks a few things to determine if the bot should move forward. It is eating up at least 2 decisions per pass because you are charged for the initial query (Enemy.isDetected?) and the "N" if its false. If all queries are true then you've eaten up 4 decisions. This is a waste of deciding power and can be trimmed to this :

Enemy.isDetected and (me.angleToEnemy < 5 or me.angleToEnemy > 355) and me.distanceToEnemy >10
    Y - ChassisMove : Forward 5
    N

Now our AI uses up 2 decisions regardless if its true or not. One for the initial query, and one for either a True (resulting in the Move 5) or False (the empty N). But still...can we trim this further? There is a way. Using the general ?Query command ALWAYS uses up 2 decisions. Those things can get expensive fast. But the specific Node Queries are different.

AI Angle Node QueryAI Detect Node QueryAI Distance Node QueryAI Energy Node Query

Here are a couple of them, Angle Query, Detect Query, Distance Query, and Energy Query. Of course there are a few more, but you get the idea. These things differ from your basic question query in that they ONLY DETECT FOR TRUE RESULTS. What this means is that unless they are true then THEY COST YOU ONLY 1 in decisions! But how do we check the status of 3 different variables since those specific Node Queries are preset for what they can query?

We start out by checking one of the variables. We'll use me.angleToEnemy (the triangle shaped one with arrows for one side). The reason for this is that more than likely we the enemy will be detected quite a bit, so why bother using that and burning a decision node every pass? Either the distance check or the angle check is better because this will happen less often, and since this example ends up using ChassisMove : Forward 5 then we are only interested in this particular code when we need to chase the enemy. And we aint gonna chase unless we are pointed at them right?

Now we place our example 2 code (Enemy.isDetected and me.distanceToEnemy), minus the angle check because we have already checked that, and there you have a very nicely minimized code.

There is one more thing to point out. With this setup we are fine when we are not pointed at the enemy. However, once we are pointed at the enemy it will burn 3 decisions each time. That's even more than our initial loss of 2 querries, however keep in mind that we lose only 1 decision when we arent pointed at the enemy and we can process faster for reactive moves. You COULD break the whole thing down into 3 specific Node checks (Use the enemy angle check Node, then the enemy Distance check Node, THEN the enemy detect check Node) and this will mean that your decision loss will fall between 1 to 3, but then your total decision loss is 4 when all aspects of it are true. Even tho you are losing 4 decisions when everything is true, you are saving a normally wasted decision prior to that.

Check Angle
me.angleToEnemy between 355 and 5 degrees?
    Check Distanceme.distanceToEnemy > 10
        Check if Detectedenemy.isDetected
            Move : Forward 5
Alot of your code can be minimized like this, by simply deciding what needs checked when, how to make sure it isnt checked unnessisarly, and avoiding the use of repetitive checks or Group nodes. Just take your AI one part at a time when reworking it, and you'll quickly find your bot running faster than before.