相关文章推荐
讲道义的黄瓜  ·  H5 IOS ...·  2 周前    · 
体贴的煎饼  ·  java - ...·  1 年前    · 

状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以Send事件,每一个状态可以响应自己注册的事件,同时也可以通过自身或者事件来改变状态机的状态

代码地址 https://github.com/9435202/StateAPI

首先Contex类:

CreateState() 接口,用于创建状态机和父状态机关系

Update() 接口,外部驱动状态机函数

SendEvent() 同步发送事件到当前状态, 能发送任意数据到状态中处理
SendAsyncEvent() 异步发送事件到当前状态,能发送任意数据到状态中处理

State类
virtual void start(){}      // 状态开始处理 子类实现
virtual void update(){}  // update处理 子类实现
virtual void stop(){}       // 状态结束处理 子类实现
void set_event_func();  // 设置事件处理回调函数,子类绑定

具体实现如下:

Context.h

#ifndef _CONTEXT_H_
#define _CONTEXT_H_
#include "Event.h"
#include <string>
#include <unordered_map>
#include <thread>
namespace HsmState
	class State;
	struct NodeState
		NodeState& operator = (const NodeState& n)
			_state = n._state;
			_father_name = n._father_name;
			return *this;
		State* _state;
		std::string _father_name;
	class Context
	public:
		friend class State;
		Context();
		~Context();
		// 开始状态机
		bool Start(std::string name);
		// 创建一个状态
		// [in] state 状态对象,在Context销毁时,内部释放state
		// [in] name  状态名称,为空名称为typedname的值
		// [in] father_name 父状态的名称
		// [out] 返回state
		State* CreateState(State* state, std::string name, std::string father_name = "");
		// 更新当前状态
		void Update();
		// 同步事件
		// 发送一个事件,提供给root状态和当前状态处理
		// 如果当前状态是子状态,则还会给父状态处理
		void SendEvent(EventData event_data);
		// 异步事件
		void SendAsyncEvent(EventData event_data);
		// 获取当前状态名称
		std::string GetCurStateName();
	private:
		// 状态切换
		void TransForState(std::string name);
		// 递归send
		void RecursiveSend(NodeState& node_state, EventData& event_data);
		std::unordered_map<std::string, NodeState> _states; // 状态列表
		NodeState _cur_node_state; // 当前状态名
		std::string _cur_name;
		std::string _root_name;    // 根状态名
#endif // !STATE_H_

 contex.cpp

#include "Context.h"
#include "State.h"
namespace HsmState
	Context::Context()
	Context::~Context()
		for (auto iter : _states)
			if (iter.second._state)
				delete iter.second._state;
				iter.second._state = nullptr;
		_states.clear();
	// 开始状态机
	bool Context::Start(std::string name)
		std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(name);
		if (iter_map != _states.end())
			_cur_node_state = iter_map->second;
			_cur_name = iter_map->first;
			iter_map->second._state->start();
		return false;
	// 创建一个状态
	// [in] state 状态对象,在Context销毁时,内部释放state
	// [in] name  状态名称,为空名称为typedname的值
	// [in] father_name 父状态的名称
	// [out] 返回state
	State* Context::CreateState(State* state, std::string name, std::string father_name)
		NodeState node_state;
		node_state._state = state;
		node_state._state->SetContext(this);
		node_state._father_name = father_name;
		_states[name] = node_state;
		return state;
	// 更新当前状态
	void Context::Update()
		_cur_node_state._state->update();
	// 同步事件
	// 发送一个事件,提供给root状态和当前状态处理
	// 如果当前状态是子状态,则还会给父状态处理
	void Context::SendEvent(EventData event_data)
		RecursiveSend(_cur_node_state, event_data);
	// 异步事件
	void Context::SendAsyncEvent(EventData event_data)
		// todo 待实现
	std::string Context::GetCurStateName()
		return _cur_name;
	// 递归send
	void Context::RecursiveSend(NodeState& node_state, EventData& event_data)
		EventDeal event_deal = node_state._state->RunEventFunc(event_data);
		if (event_deal == keep_on
			&& !node_state._father_name.empty())
			std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(node_state._father_name);
			if (iter_map != _states.end())
				RecursiveSend(iter_map->second, event_data);
	void Context::TransForState(std::string name)
		std::string str_name = std::string(name);
		std::unordered_map<std::string, NodeState>::iterator iter_map = _states.find(str_name);
		if (iter_map != _states.end())
			// 停止上一个状态
			_cur_node_state._state->stop();
			// 初始化下一个状态
			_cur_node_state = iter_map->second;
			_cur_name = iter_map->first;
			_cur_node_state._state->start();

state.h

#ifndef _STATE_H_
#define _STATE_H_
#include "Event.h"
#include<functional>
#include<string>
namespace HsmState
	class Context;
	class State
	public:
		// 进入状态时调用,子类重写
		virtual void start(){}
		// 更新状态,可以由外部周期性调用
		virtual void update(){}
		// 停止状态是调用,子类重写
		virtual void stop(){}
		// 设置事件响应回调函数
		void set_event_func(std::function<EventDeal(EventData&)> func);
		EventDeal RunEventFunc(EventData& event_data); 
		void SetContext(Context* context);
		// 切换状态
		// [in] name 状态名称
		void TransState(std::string name);
	private:
		std::function<EventDeal(EventData&)> _event_func;
		Context *_context;
#endif // !STATE_H_
		std::cout << "WorkState start" << std::endl;
		std::function<EventDeal(EventData&)> func = std::bind(&WorkState::DealEvent, this, std::placeholders::_1);;
		set_event_func(func);
	void stop()
		std::cout << "WorkState stop" << std::endl;
	EventDeal DealEvent(EventData &event_data)
		switch ((EventS)event_data._event_type)
		case belazy:
			TransState("LoafOnAJob");
			break;
		default:
			break;
		return keep_on;
	void update()
		time++;
		if (time == 180)
			run = false;
	int time = 0;
// 工作摸鱼状态
class LoafOnAJob : public State
public:
	void start()
		time = 0;
		std::cout << "LoafOnAJob start" << std::endl;
	void stop()
		std::cout << "LoafOnAJob stop" << std::endl;
	void update()
		time++;
		if (time == 10)
			TransState("WorkState");
	int time = 0;
// 对象工厂
class Factory
public :
	static State* CreateState(Context* context, std::string name, std::string parent_name = "")
		State* state = nullptr;
		if (name == "StartState")
			state = new StartState();
		else if (name == "HungerState")
			state = new HungerState();
		else if (name == "Dinner")
			state = new Dinner();
		else if (name == "DoTheCookingState")
			state = new DoTheCookingState();
		else if (name == "EatState")
			state = new EatState();
		else if (name == "SleepState")
			state = new SleepState();
		else if (name == "WorkState")
			state = new WorkState();
		else if (name == "LoafOnAJob")
			state = new LoafOnAJob();
		context->CreateState(state, name, parent_name);
		return state;
int main()
	Context* context = new Context();
	// 创建状态机
	Factory::CreateState(context, "StartState");
	Factory::CreateState(context, "HungerState");
	Factory::CreateState(context, "Dinner");
	Factory::CreateState(context, "DoTheCookingState", "Dinner");
	Factory::CreateState(context, "EatState", "Dinner");
	Factory::CreateState(context, "SleepState");
	Factory::CreateState(context, "WorkState");
	Factory::CreateState(context, "LoafOnAJob");
	// 开始状态机
	context->Start("StartState");
	int time = 0;
	while (run)
		time++;
		std::this_thread::sleep_for(
			std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(10)));
		context->Update();
		// 如果为工作状态,每隔60分钟发出偷懒事件
		if (context->GetCurStateName() == "WorkState" 
			&& time % 60 == 0) 
			EventData e = EventData((int)belazy);
			context->SendEvent(e);
	if (context)
		delete context;
		context = nullptr;
	std::cout << "state close" << std::endl;
	return 0;

三、运行结果

工作累了就偷偷懒,真是愉快的一天啊!!!

状态机我们大家都知道,有一个专门的设计模式状态机模式,类图大概如下图:不过如果按照下面图来实现的状态机,基本来说非常难用,没有实用性,只能作为教科书的产品。今天我们要实现的是一种通用状态机,可以Send事件,每一个状态可以响应自己注册的事件,同时也可以通过自身或者事件来改变状态机的状态 代码地址:https://github.com/9435202/StateAPI首...
//待完善 有限状态机是一个很常用的技术,在流程控制和游戏AI中都比较实用,因为状态机编程简单又很符合直觉。与有限状态机类似的是设计模式中的状态模式。本文是参考《Programming Game AI by Example》 记得最开始工作时候也接触过有限状态机,当时是一个长长的用switch写成的状态机,理解它的时候真的很困难。 所以现在使用一套内置规则到状态内部去,来控制状态的转换。 现在就来制作一个有限状态机。 作为一个关于使用状态机创建一个智能体的实际案例,我们先模拟这样一个场景。是作为一个简
次态:当条件满足后,即将转移的下一个状态 动作:当满足某个事件时执行的动作;动作执行完毕后可以转移到另一个状态或保持原有状态 条件:转移状态所需的条件,当满足条件时,会触发一个动作或进行状态转移 C++函数指针实现FSM 案例:学生的日常生活。 学生的日常生活包含以下几个状态:起床、上学、吃午饭、做作业、睡觉; 每个状态之间进行转移需要执行相应的事件。 我分为以下几个步骤来实现: (1)绘制状态转移图 (2)创建状态转移的FSMItem类 枚举:所有 状态机是什么?相信很多人有意无意间都会用到状态机。不过状态机究竟是个什么东西,很多人可能都心里了解,但无法言明。 恰巧今天想到这个问题,便在此记录一下。 状态机:(摘自百度百科) 状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类: 第一类,若输出只和状态有关而与输入无关,则称为Moore状态机 第二类,输出不仅和状态有关而且和输入
状态控制器库是一个独立于平台的通用C ++框架,该框架允许实现有限状态机及其多动作计划概括。 该库的结构和实现侧重于将有限状态机应用于实时控制回路,但实际上可以合理地适用于几乎所有其他应用,甚至与控制系统完全无关。 重点放在具有非常低的开销上,以便无论在何处使用此库都不会损害整体系统性能,同时仍保持易用性。 代码大小也已保持最小。 除了实现标准的有限状态机和多动作计划状态机之外,该库还可以用于实现分层状态控制器,或者实现这三种状态的任意混合。 请参阅大量文档以获取更多信息。 我欢迎所有反馈,建议和错误报告! 电子邮件:pallgeuer [at] ais.uni-bonn.de
        一般来说,“状态机”是一种表达状态转换变换逻辑的方法。曾经有人和我讨论过为什么不直接用ifelse,而要使用“状态机”去实现一些逻辑,认为使用“状态机”是一种炫技的表现。然而对于大型复杂逻辑的变化和跳转,使用ifelse将带来代码难以阅读等弊端。其实ifelse也是一种状态机实现的方式。         之前我们有个业务和操作系统有着强烈的关联,而我们希望比较清晰地描述整个业务中...
YOLOv5是一种目标检测算法,它可以用来识别图像中的对象。YOLOv5的C语言实现可以使用Pytorch框架来进行。 要使用YOLOv5进行目标检测,你需要了解目标检测的基本原理并掌握一些基本的机器学习知识。你需要准备训练数据集和训练好的模型参数。然后你可以使用Pytorch框架来设计和构建你的YOLOv5模型。 在使用YOLOv5的C语言实现时,你可能需要用到一些常见的Pytorch函数和类,如`torch.nn.Module`和`torch.optim`。你还可以使用`torch.utils.data.DataLoader`来加载数据,使用`torch.nn.functional`中的函数来定义损失函数,并使用`torch.nn.Module.train()`和`torch.nn.Module.eval()`方法在训练和测试时切换模型。 最后,你可以使用模型来进行目标检测,并使用工具如`cv2`来绘制检测结果。