Generally speaking, all the processes are implemented as classes, and running the process
(or a portion thereof) is achieved by calling a ( virtual) member function, say "exec()".
So "executing the process X " thereafter will mean "call the ProcessX.exec()" member function.
Hence I can describe the AI as a collection of Systems ( implemented as classes or instanciations thereof) encapsulating actions or as a collection of Actions corresponding to the process exec() member function: For example, "Perception System" versus "Percepting ( Action)".
The AI litterature tends to use descriptions based on Actions. Still, it is easier to use here description based on Systems: they relate to well identified classes, whereas the action ,in my implementation, is split into several steps, ie "exec()" is sometimes actually coded as different member functions called from different points in the code.
My AI-engine is described here, but probably requires concurrent reading of pages on key concept/classes, namely DecisionNode , ie the AI sub-processes, and Task .
A key paradigm used in my bot-ai is the following: opposite to our anthropocentric standpoint, the core object is NOT the bot, but the DecisionNode. This is because DecisionNodes trigger information gathering, make choices and provide actions to be performed, ie they produce behaviours. The bot can then be viewed as a variable collection of DecisionNodes, adding constraints on DecisionNodes combinations and simply executing the elementary tasks. Because this view also applies to a group of bots , coding for team behaviours should benefit a lot from the single bot-ai code.
The AI-engine is basically build around Decision Paths, ie top-down lists of instanciated DecisionNodes ( nodes in an informal decision tree) reflecting refining sequences of decisions made, ending up with Tasks to be executed. The root ( top) node of a decision tree/DecisionPath is the TopLevelDecisioNode, which never changes as opposed to its children. The decision tree is "informal" because DecisionNodes are not hard-coded linked to their children( their possible outcomes): DecisionNodes make a selection, and have member pointer(s) to the currently selected outcome(s) only ( generally another DecisionNode).
Different but coexisting and possibly conflicting behaviours/"frame of mind"/goals are formalized as different decision trees: each high-level behaviour has then its own TopLevelDecisionNode, decision tree and current Decision Path, and a global conflict solving process handles incompatibilities/priorities.
An example of possibly conflicting behaviours: "Survive", which is more of a defensive stance and also rather generic, and "Complete-the-mission", which might require some risk taking as well as other actions,action parameters/variables.
The following AI process reflects my own choices and some ( the first step in AI.2. hereunder above all) require to be reconsidered some day:
AI.1. check for completeness/cancellation of every Task that has been executed last frame, ie:
for each Task in the Tasks-To-be-Executed PriorityList:
Task.checkstop() member function is called, returning StopCause;
if the Task is completed/cancelled ( StopCause!= GoOn), the onTaskCompl(Task) member function of its parent is called and the Task is sent to the bin ( actual deletion is delayed to the end of the frame).
AI.2. for each Decision Path in force, find the highest level activated DecisionNode, ie
if a Decision Path has no Task ( Tasks deleted during previous frame conflict solving) , then activate its TopLevelDecisionNode and return pointer to it;
else for each DecisionNode, from TopLevelDecisionNode downwards:
if( DecisionNode is already activated), then return pointer to it;
if( DecisionNode current decision/choice is no longer valid), then activate the DecisionNode and return a pointer to it;
NB: DecisionNodes may have been activated before step AI.2.
-during AI.1. by a child Task completion/cancellation
-by events notified to DecisionNodes between the last frame and this one.
AI.3. the (last) frame Tasks-To-be-Executed PriorityList is cleared ( but Tasks
with StopCause==GoOn still exist as children of their parent DecisionNode, still flagged as Required)
AI.4. for each decision tree, run the Decision Path building loop starting from the highest level activated DecisionNode determined in AI.2.; in the end, confirm previous Tasks and create new ones, all flagged as Required, and discard others:
it is a loop: run the DecisionNode execution process, then run its child DecisionNode if any returned, else stop.
AI.5. for each Decision Path, create a link to each of its Tasks, erase the ToBeExecuted flag of the Task, and place the link in a Tasks-To-be-Executed PriorityList shared at bot level ( highest priority on top).
AI.6. solve conflicts by traversing the Tasks-To-be-Executed PriorityList top-down.
For each Task, a Task member function is first executed to provide data the conflict solver needs to operate, then the Task is checked; accepted Task are flagged as ToBe Executed, others are detached from the list and their parent DecisionNode decides on their fate ( usually delete).
AI.7. all Tasks left in the Tasks-To-be-Executed PriorityList are now executed, ie their orders are computed and "handed-out" to the bot player-like low level inputs.