以FSM描述Agent行为之深入实践
目录背景Agent实现结果背景上一篇以例子形式简要介绍了FSM及其一种实现,链接如下:https://blog.csdn.net/GWB_superman/article/details/107130486由于FSM运用极其广泛,上篇并未详细展开,很多人对StateMachine如何和真实物体对应还有疑惑,这篇重点就其一种应用做深入探讨,讲述FSM如何与agent结合描述其行为规则。AgentAg
目录
背景
上一篇以例子形式简要介绍了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;
}
结果
运行结果如下:

更多推荐

所有评论(0)