目录

 

背景

Agent

实现

结果


背景

上一篇以例子形式简要介绍了FSM及其一种实现,链接如下:https://blog.csdn.net/GWB_superman/article/details/107130486

由于FSM运用极其广泛,上篇并未详细展开,很多人对StateMachine如何和真实物体对应还有疑惑,这篇重点就其一种应用做深入探讨,讲述FSM如何与agent结合描述其行为规则。

Agent

Agent是指驻留在某一环境下,能持续自主地发挥作用,具备驻留性、反应性、社会性、主动性等特征的计算实体。

其实,Agent有很多种定义:

Agent在某种程度上属于人工智能研究范畴,因此要想给Agent下一个确切的定义就如同给人工智能下一个确切的定义一样困难。在分布式人工智能和分布式计算领域争论了很多年,也没有一个统一的认识。

以上描述太抽象,还是回归上次和小狗互动的例子:

如果通过计算机技术模拟上述过程,小狗和你就是agent的概念,简而言之就是智能体

那么状态机的作用就很明显了,那就是它可以抽象出agent的行为模型。

实现

设计思路如下:

智能体可以定义多个状态,智能体之间通过发送事件(SendEvent)进行交互,智能体在接受到事件后会进行状态的改变。

基于以上设计,抽象出下面几个类:

  • 事件类event
  • 状态类state
  • 智能体类Agent
  • 状态机设置类MachineSet

 

事件类代码如下:

class __declspec(dllexport) Event
{
    friend class MachineSet;
    friend class Agent;
public:
    Event(const MachineSetSharedPtr& machine_set)
        : machine_set_(machine_set)
    {
    }

    virtual ~Event()
    {
    }

public:
    virtual const MachineSetSharedPtr GetMachineSet() const
    {
        return machine_set_.lock();
    }

protected:
    MachineSetWeakPtr machine_set_;
    MachineBaseWeakPtrVec target_agents_;
};

template<class EventType,
         class = typename std::enable_if<std::is_enum<EventType>::value>::type>
class EventTemplate : public Event
{
    friend class MachineSet;
    friend class Agent;
public:
    typedef EventType Type;

    EventTemplate(Type type)
        : Event(MachineSetSharedPtr()),
          type_(type)
    {
    }

    EventTemplate(Type type, const MachineBaseWeakPtrVec& target_agents)
        : Event(MachineSetSharedPtr()),
          type_(type)
    {
        target_agents_ = std::move(target_agents);
    }

    EventTemplate(Type type, const MachineBaseSharedPtr& target_agent)
        : Event(MachineSetSharedPtr()),
          type_(type)
    {
        if (target_agent)
        {
            target_agents_.emplace_back(target_agent);
        }
    }

    EventTemplate(Type type, const MachineSetSharedPtr& machine_set)
        : Event(machine_set),
          type_(type)
    {
    }

    virtual ~EventTemplate()
    {
    }

    Type GetType() const
    {
        return type_;
    }

protected:
    Type type_;
};

 

状态类代码如下:

class __declspec(dllexport) State : public std::enable_shared_from_this<State>
{
public:
    static StateSharedPtr MakeState(Agent& owner, const char* name, time_t timerMS = 0);
    static StateSharedPtr MakeState(Agent& owner, const State& copy);

public:
    virtual ~State();

private:
    State(Agent& owner, const char* name, time_t timerMS = 0);
    State(Agent& owner, const State& copy);

public:
    const std::string& GetName() const
    {
        return name_;
    }

    time_t GetTimeout() const
    {
        return timeout_ms_;
    }

    void SetTimeout(time_t new_timeout_ms)
    {
        timeout_ms_ = new_timeout_ms;
    }

    void ClearActions();

    bool operator==(const State& rhs) const;
    bool operator!=(const State& rhs) const;

public:
    StateEvent OnEnter;
    StateEvent OnExit;

private:
    friend class Agent;
    friend class Transition;

    std::string name_;
    time_t timeout_ms_;

    std::vector<TransitionSharedPtr> transitions_;

private:
    State& operator=(const State&);
};

智能体类代码如下:

class __declspec(dllexport) Agent 
{
public:
    friend class State;
public:
    Agent(const std::string& name, MachineSetSharedPtr mset);

public:
    virtual ~Agent() {}

public:
    virtual void Birth();
    virtual bool Process(EventSharedPtr);
void SendEvent(EventSharedPtr event);

public:
    bool ForceState(const StateSharedPtr& state);
    bool SetStartState(const StateSharedPtr& state);
    bool SetMetaState(const StateSharedPtr& state);
    void ClearMetaState();
    const StateSharedPtr GetCurrent() const;
    const StateSharedPtr GetPrevious() const
    {
        return previous_state_;
    }


protected:
    Agent(const Agent& rhs);

private:
    Agent& operator=(const Agent& rhs);

private:
    bool ProcessNormalStateTransition(EventSharedPtr event);
    bool ProcessMetaStateTransition(EventSharedPtr event);

    template<bool IsMetaState>
    bool InternalSetState(const StateSharedPtr& state);

protected:
    unsigned long long timeout_ms_;
    StateSharedPtr current_state_;
    StateSharedPtr previous_state_;

    typedef std::vector<StateSharedPtr> StateListType;
    StateListType states_;

    StateSharedPtr meta_state_;

    MachineSetWeakPtr machine_set_;
};

状态机设置类代码如下:

class __declspec(dllexport) MachineSet : public std::enable_shared_from_this<MachineSet>
{
    friend std::ostream& operator<<(std::ostream& strm, const MachineSet& ms);
public:
    static MachineSetSharedPtr MakeMachineSet();

private:
    MachineSet();

public:
    ~MachineSet();

public:
    // thread safe
    void OnReceivedEvent(EventSharedPtr event);


    void StartBackground(unsigned int sleep_ms);
    void StopBackground();

    void Process();
    void Process(EventSharedPtr event);
    void ProcessTimeoutMachine(MachineBaseSharedPtr machine);

    MachineBaseSharedPtr GetMachine(const MachineType& type, const std::string& name);
    void UpdateTimeoutMahcine(const MachineBase& machine, time_t timeout) ;

    bool HasHandler() const
    {
        return static_cast<bool>(event_handler_);
    }

public:
    typedef std::function<void()> NotifyEvent;
    NotifyEvent OnProcessError;

private:
    void AddMachine(MachineBaseSharedPtr machine);
    void RemoveMachine(MachineBaseSharedPtr machine);

    bool ProcessTargetMachineEvent(const EventSharedPtr& event);
    bool ProcessNoTargetMachineEvent(const EventSharedPtr& event);
    void InternalProcessTimeoutEvent();

private:
    typedef std::vector<MachineBaseSharedPtr> MachinePtrList;
    typedef std::set<MachineBaseSharedPtr> MachinePtrSet;

    MachinePtrList machine_list_;
    MachinePtrSet machine_set_;

    Fifo<EventSharedPtr> event_fifo_;

    MachineSetHandlerSharedPtr event_handler_;

    std::thread::id owner_thread_id_;

    std::atomic<bool> background_thread_stop_flag_;
    std::unique_ptr<std::thread> background_thread_;
};

依旧是以和小狗互动的例子main.cpp如下:

enum class DogEventType
{
    DT_KICK,
    DT_EXPEL,
    DT_CARESS,
};

class DogEvent : public EventTemplate<DogEventType>
{
public:
    using underlying_type = std::underlying_type<DogEventType>::type;

    DogEvent(DogEventType type, const MachineBaseSharedPtr& machine)
        : EventTemplate<DogEventType>(type, machine)
    {
    }

    virtual std::ostream& ToStream(std::ostream& str) const
    {
        return str << "DogEvent | " << static_cast<underlying_type>(type_) << std::endl;
    }

    virtual std::string ToString() const
    {
        std::ostringstream os;
        os << "DogEvent | " << static_cast<underlying_type>(type_) << std::endl;
        std::string str = os.str();
        os.str("");
        return str;
    }
};

class DogAgent : public Agent
{
public:
    DogAgent(const std::string& name, MachineSetSharedPtr mset);

public:
    virtual void Birth();

public:
    StateSharedPtr sleep_;
    StateSharedPtr awake_;
    StateSharedPtr run_;

    TransitionSharedPtr sleep_awake_;
    TransitionSharedPtr awake_run_;
    TransitionSharedPtr awake_sleep_;
    TransitionSharedPtr run_sleep_;
    TransitionSharedPtr run_timeout_;
};

DogAgent::DogAgent(const std::string& name, MachineSetSharedPtr mset)
    : Agent(name, mset)
{
}

void DogAgent::Birth()
{
    sleep_ = State::MakeState(*this, "sleep");
    awake_ = State::MakeState(*this, "awake");
    run_ = State::MakeState(*this, "run", 5000);

    sleep_awake_ = Transition::MakeTransition("sleep_awake",
                   sleep_,
                   awake_,
                   std::make_shared<SimplePredicate<DogEvent>>(DogEventType::DT_KICK));
    awake_run_ = Transition::MakeTransition("awake_run",
                                            awake_,
                                            run_,
                                            std::make_shared<SimplePredicate<DogEvent>>(DogEventType::DT_EXPEL));
    awake_sleep_ = Transition::MakeTransition("awake_sleep",
                   awake_,
                   sleep_,
                   std::make_shared<SimplePredicate<DogEvent>>(DogEventType::DT_CARESS));
    run_sleep_ = Transition::MakeTransition("run_sleep",
                                            run_,
                                            sleep_,
                                            std::make_shared<SimplePredicate<DogEvent>>(DogEventType::DT_CARESS));
    run_timeout_ = Transition::MakeTransition("run_timeout",
                   run_,
                   run_,
                   std::make_shared<TimeoutPredicate>(type_));
}

int main()
{

    MachineSetSharedPtr machine_set = MachineSet::MakeMachineSet();

    if (machine_set)
    {
        //set machine set and machine log

        // start event process thread
        machine_set->StartBackground(500);

        //add foodmachine into machine set
        std::shared_ptr<Agent> people_agent = MakeAgent<Agent>("people_agent", machine_set);

        std::shared_ptr<DogAgent> dog_agent = MakeAgent<DogAgent>("dog_agent", machine_set);

        if (dog_agent)
        {
            dog_agent->SetStartState(dog_agent->sleep_);

            //set state's callback
            dog_agent->sleep_->OnEnter = [&](MachineBase & machine,
                                             const StateSharedPtr & state)
            {
                std::cout << "Enter " << state->GetName() << std::endl;
            };
            dog_agent->sleep_->OnExit = [&](MachineBase & machine,
                                            const StateSharedPtr & state)
            {
                std::cout << "Exit " << state->GetName() << std::endl;
            };

            dog_agent->awake_->OnEnter = [&](MachineBase & machine,
                                             const StateSharedPtr & state)
            {
                std::cout << "Enter " << state->GetName() << std::endl;
            };
            dog_agent->awake_->OnExit = [&](MachineBase & machine,
                                            const StateSharedPtr & state)
            {
                std::cout << "Exit " << state->GetName() << std::endl;
            };

            dog_agent->run_->OnEnter = [&](MachineBase & machine,
                                           const StateSharedPtr & state)
            {
                std::cout << "Enter " << state->GetName() << std::endl;
            };
            dog_agent->run_->OnExit = [&](MachineBase & machine,
                                          const StateSharedPtr & state)
            {
                std::cout << "Exit " << state->GetName() << std::endl;
            };

            //set transtition's callback
            dog_agent->sleep_awake_->OnTransition = [&](MachineBase & machine,
                                                    const StateSharedPtr & from_state,
                                                    ITransitionSharedPtr transition,
                                                    EventSharedPtr event,
                                                    const StateSharedPtr & to_state)
            {
                std::cout << transition->GetName()
                          << " | "
                          << from_state->GetName()
                          << " -> "
                          << to_state->GetName() << std::endl;
            };
            dog_agent->awake_run_->OnTransition = [&](MachineBase&,
                                                  const StateSharedPtr & from_state,
                                                  ITransitionSharedPtr transition,
                                                  EventSharedPtr event,
                                                  const StateSharedPtr & to_state)
            {
                std::cout << transition->GetName()
                          << " | "
                          << from_state->GetName()
                          << " -> "
                          << to_state->GetName() << std::endl;
            };
            dog_agent->awake_sleep_->OnTransition = [&](MachineBase&,
                                                    const StateSharedPtr & from_state,
                                                    ITransitionSharedPtr transition,
                                                    EventSharedPtr event,
                                                    const StateSharedPtr & to_state)
            {
                std::cout << transition->GetName()
                          << " | "
                          << from_state->GetName()
                          << " -> "
                          << to_state->GetName() << std::endl;
            };
            dog_agent->run_sleep_->OnTransition = [&](MachineBase&,
                                                  const StateSharedPtr & from_state,
                                                  ITransitionSharedPtr transition,
                                                  EventSharedPtr event,
                                                  const StateSharedPtr & to_state)
            {
                std::cout << transition->GetName()
                          << " | "
                          << from_state->GetName()
                          << " -> "
                          << to_state->GetName() << std::endl;
            };
            dog_agent->run_timeout_->OnTransition = [&](MachineBase&,
                                                    const StateSharedPtr & from_state,
                                                    ITransitionSharedPtr transition,
                                                    EventSharedPtr event,
                                                    const StateSharedPtr & to_state)
            {
                std::cout << transition->GetName()
                          << " | "
                          << from_state->GetName()
                          << " -> "
                          << to_state->GetName() << std::endl;
            };

            // send events

            people_agent->SendEvent(std::make_shared<DogEvent>(
                                        DogEventType::DT_KICK,
                                        dog_agent));
            people_agent->SendEvent(std::make_shared<DogEvent>(
                                        DogEventType::DT_EXPEL,
                                        dog_agent));
            people_agent->SendEvent(std::make_shared<DogEvent>(
                                        DogEventType::DT_CARESS,
                                        dog_agent));
        }
    }

    getchar();

    return 0;
}

结果

运行结果如下:

 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐