an implementation and improvement method of artificial intelligence based on QT finite state machine
Ai in this year is a very fire direction, of course, not only this year, it has been fire for many years, some of the artificial intelligence algorithms abound. Ai in many areas have applications, take my familiar game domain, some search algorithm, such as A * algorithm (my "10th exorcism" has used a * algorithm to seek the road), there are some advanced algorithms, such as decision tree, etc., have been widely used in the game. I now want to make a project and AI also have a certain relationship, so I started this month to learn to build some simple AI framework.
Saiyang original article, starting address: http://blog.csdn.net/gamesdev/article/details/46628447. Welcome to come to discuss the peer.
QT introduces the concept of finite state machines in 4.6, in order to make it easier to add more complex logic to an existing GUI interface. Finite state machine refers to a limited number of States to convert each other, and the formation of an organic whole, it is used in the game is also very much, I used to make a game project when also saw their own production of finite state machine to deal with complex logic. So I started to pick up the finite state machine and see if I could dig deeper into its content.
If you know the usage of QML as much as I do, then there will be an impression that Qt transplanted the finite state machine module into the QML environment. To use QML's finite state machine, a declaration such as "Import Qtqml.statemachine 1.0" needs to be made. QT has a very rich documentation, and even a special chapter on the introduction of finite state machines, called the "the declarative states Machine Framework", describes its usage. If you are not familiar with QML's finite state machine, take a look at this QT Help document!
QT's finite state machine is divided into two important parts. One is "state", which refers to a specific status, and the other is "Transition", which refers to a specific conversion between two states. When I was using it, I found that the finite state machine provided by QML provided only Signaltransition and timeouttransition, and did not provide many practical transition like QT. Just beginning to try a simple time, feel good, but think of the future state machine unusually complex, once involved in the state of the ever-changing, may have to write a lot of state, is really inconvenient. I'll take the analogy of the project I'm working on:
is a very simple finite state machine, it has only the entrance, no exit, and only three states. In addition to the initial state S1, just switch between S2 and S3. In the diagram, the box represents the state, and the arrow represents a transform (transition). So excluding the start of that arrow, we have a total of 6 states here, but also 3x2 state. In the case of QML code, it looks like this:
qtobject{id:root Signal Output (string text) property string Input property var statemachine:statemachine {running:true initialstate:s1 State {id:s1 Onentered:output ("You Well, welcome to the AI test platform. ") signaltransition {targetstate:s2 signal:root.inputChanged Guard:root.input = = "I Like you." "} signaltransition {Targetstate:s3 signal:root.inputCh anged guard:root.input! = "I like you. "}} state {Id:s2 onentered:output (" I like you, too. ") signaltransition {targetstate:s2 signal:root.inputChanged Guard:root.input = = "I Like you." "} signaltransition {Targetstate:s3 signal:root.inputCh Anged Guard:roOt.input! = "I like you." "}} state {Id:s3 onentered:output (" I've just come into this world and I don't know much about human language, can I teach it? ") ") signaltransition {targetstate:s2 signal:root.inputChanged Guard:root.input = = "I Like you." "} signaltransition {Targetstate:s3 signal:root.inputCh anged guard:root.input! = "I like you. " } } }}
This is only for a minimal executable finite state machine, such as Galgame game, its branch situation is very much, and if you know the multiplication principle, when x and Y is very large, the number of transformations (Transition) is very amazing. The reason for this is that signaltransition must be attached to the State class as its sourcestate. So we have to find a way to scale it down.
So I'm studying the finite state machine mechanism of QT. Fortunately, under the powerful QT, the various parts of the finite state machine can also be customized. Qstate ancestor class is qabstractstate,qtransition ancestor class is qabstracttransition, they are a certain scale of abstract class, we need to implement their few methods, can be combined with QT finite state machine to do their own processing. So I made a state class called Aistate, which functions as:
1. Save a reference to all transformations (Transition) it emits, and when this state is activated, unify lets all conversions serve it.
Similarly, I have created a class named Conditionaltransition, which has the following features:
1, can set sourcestate, let it and state out of the parent-child relationship, that can be defined in any desired position;
2, provide the trigger condition attribute;
3. Send custom events to the state machine.
Here's their code:
AIState.h
#ifndef aistate_h#define aistate_h#include <QState> #include <QQmlListProperty> #include " ConditionalTransition.h "class Aistate:public qstate{ q_object q_property (qqmllistproperty< conditionaltransition> conditions READ conditions) Public: Explicit aistate (qstate* parent = q_nullptr); C4/>qqmllistproperty<conditionaltransition> conditions (void);p rivate slots: void onactivechanged (bool Active);p rotected: qlist<conditionaltransition*> m_conditions;}; #endif//Aistate_h
AIState.cpp
#include "AIState.h" aistate::aistate (qstate* Parent): qstate (parent) { Connect (this, SIGNAL (activechanged (BOOL) ), this , SLOT (onactivechanged (bool)));} Qqmllistproperty<conditionaltransition> aistate::conditions (void) { return qqmllistproperty< Conditionaltransition> (this, m_conditions);} void aistate::onactivechanged (bool active) { //sets the original transition sourcestate to aistate. foreach (conditionaltransition* condition, m_conditions) { condition->setsourcestate (active this:q_nullptr); }}
ConditionalTransition.h
#ifndef conditionaltransition_h#define conditionaltransition_h#include <QObject> #include <QObjectList> #include <QEvent> #include <QAbstractTransition> #include <qqmllistproperty>class Conditionaltransition:public qabstracttransition{q_object q_property (qstate* sourcestate READ sourceState WRITE s Etsourcestate NOTIFY sourcestatechanged) q_property (bool when READ condition WRITE setcondition NOTIFY Conditionchang ed) public:explicit conditionaltransition (qstate* sourcestate = q_nullptr); inline bool Condition (void) {return m_condition;} void Setcondition (bool condition); void Setsourcestate (qstate* state); signals:void sourcestatechanged (void); void conditionchanged (void);p rotected:virtual bool Eventtest (qevent* event); virtual void Ontransition (qevent* event); bool M_condition;}; Class Conditionalevent:public qevent{public:explicit conditionalevent (bool condition, conditionaltransition* sourcetransition): Qevent (Qevent::type (Conditionaltype)), M_co Ndition (condition), m_sourcetransition (sourcetransition) {} inline bool condition (void) {return M_con dition; } inline conditionaltransition* sourcetransition (void) {return m_sourcetransition;} Enum Type {conditionaltype = Qevent::user + 2079};p rivate:bool m_condition; conditionaltransition* m_sourcetransition;}; #endif//Conditionaltransition_h
ConditionalTransition.cpp
#include <QStateMachine> #include "ConditionalTransition.h" conditionaltransition::conditionaltransition ( qstate* sourcestate): Qabstracttransition (sourcestate) {m_condition = false;} void Conditionaltransition::setcondition (bool condition) {m_condition = condition; Emit conditionchanged (); if (condition && sourcestate ()! = q_nullptr && sourcestate ()->active () && Machine ()->isrunning ()) {//Only allow state machines to be running and the source state is activated to send events to state machine ()->postevent (New Condi Tionalevent (condition, this)); }}void conditionaltransition::setsourcestate (qstate* state) {if (sourcestate () = = state) return; SetParent (state); Emit sourcestatechanged ();} BOOL Conditionaltransition::eventtest (qevent* event) {BOOL ret = false; if (event->type () = = Qevent::type (conditionalevent::conditionaltype)) {//If the current condition is true and the source is converted to itself, then the conversion is performed by conditionalevent* CE = static_cAst<conditionalevent*> (event); ret = ce->sourcetransition () = = this; } return ret;} void Conditionaltransition::ontransition (qevent* event) {q_unused (event);}
Then, registering these classes in the QML environment allows you to define instances of these classes in the QML.
statemachine{ id:machine running:true initialstate:s1 statesettings { id:settings } Property alias InputWord:settings.inputWord Property alias OutputWord:settings.outputWord Condition { id:c2 objectName: "C2" when:inputWord.indexOf ("I Like You")! =-1 targetstate:s2 } Condition { id:c3 objectName: "C3" when:inputWord.indexOf ("I like you") = =-1 targetstate:s3 } Aistate { id:s1 objectName: "ai:s1" conditions: [C2, C3] Onentered:outputword = "Hello, Welcome to the AI test platform. " } aistate { id:s2 objectName:" Ai:s2 " conditions: [C2, C3] onentered: Outputword = "I like you, too." " } aistate { id:s3 objectName:" AI:S3 " conditions: [C2, C3] onentered: Outputword = "I have just come to this world, still do not understand the human language, can teach me?" " }}
The following is a diagram of the state machine to analyze:
Red represents the active state, and Green is the conversion that is owned by the active state. In combination with the QML code above, we can see that there are only two transformations defined in the program, and the conversion is targetstate, not tied to the sourcestate, which can decouple the state from the transition. Four conversions are used less than the previous implementation. If the finite state machine is large, such an increase in efficiency is very considerable.
To run the demo program:
Source code: Here
An implementation and improvement method of artificial intelligence based on QT finite state machine